해당 chapter에서 가장 강조하는 바는 “의미있는 이름”입니다. 좋은 코드를 만들어 내기 위해서 우리는 하루에 최소 2번은 고민합니다. 왜 좋은 코드를 만들어 내기 위해 고민할까요? 과연 그럼 좋은 코드란 무엇일까요??
우리는 이 문제의 답을 이미 알고 있습니다. 좋은 코드가 필요한 이유는 다음과 같습니다.
- 향후 제 3자가, 혹은 작성자가 유지 보수를 편히 할 수 있게 하고, 잘못된 이름에서 발생하는 Side Effect를 고려
- 빠르게 변화는 비즈니스 영역에 대응하기 위해서 등등
이러한 문제점을 해결하기 위해 우리는 좋은 코드를 만들도록 노력합니다.
그럼 우리가 말하는 좋은코드란 무엇일까요?
흔히 말하는 좋은 코드는 가독성도 좋아야 하고, 변경도 쉬워야 하고, 재사용성이 높고, 효율적인 코드라고 알고 있을 겁니다. 그러나 이 좋은 코드에 관한 내용은 이상적일 뿐이고, 현실과 다름을 알고 있습니다.
그래서 이상과 가까워 질 수 있도록 항상 좋은 코드를 짜기 위해 노력해야하고, 생각해야합니다.
이번 챕터에서 가장 중요하다고 생각하는 내용입니다.
- 의도를 분명하게 밝히고 그릇된 정보를 피하자.
- 의도를 분명하게 표현하고 있는 대표적인 예시는 책의 목차입니다.
- 우리는 목차를 통해 챕터의 의도를 파악하고, 해당 챕터가 어떤 역할을 할지를 파악하고, 글쓴이의 의도를 확인할 수 있습니다.
- 경험이 많은 개발자는 해당 로직만 봐도 대충 어떤 동작을 하는지를 쉽게 파악할 수 있습니다. 그러나 동작을 파악하는 것과 작성자의 의도를 파악하는 것은 조금 다른 맥락이라 생각합니다.
- 의도를 분명하게 표현하고 있는 대표적인 예시는 책의 목차입니다.
int a;
int[] b = new int[5];
어떤 의미를 담고 있는 변수일까?
전혀 알 수 없다.
단지 int 형의 변수에 a라는 이름이 부여된 것과,
int[] 타입을 가지고 있고, 5개의 저장 공간을 가진 b라는 변수라는 것을 알 수 있다.
이 둘의 역할이 어떤지 모른다.
for (int a = 0; a < 15; a++){
if ( a / 2 == 0){
.... ( B에 관한 행위 )}]
}
사실 로직만 보면 해당 로직이 어떻게 동작하는지 확인할 수 있다.
그러나 이 코드만 보면 우리는 작성자의 의도를 정확하게 파악하기가 힘들다.
우리가 이 로직이 어떻게 동작하는지 아는 이유는 단지 익숙함과 노련함 때문이다.
(익숙하게 써왔기 때문에)
만약 아래와 같은 코드라면??
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x: theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
윗 코드에서 list1이 무엇을 의미하는지, getThem()이 무엇을 의미하는지 우린 알 수 없다.
위의 코드에 조금 직관적인 이름을 부여해서 코드를 이해해보자.
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for(int[] cell : gameBoard)
if(cell[STATUS_VALUE] == FLAGGED)
flaggedCElls.add(cell);
return flaggedCells
}
윗 코드에 비해 해당 로직이 어떤 의미를 가지고 있는지 명확해졌지만, 단순성은 해결되지 않았다.
단순성 한 숟갈을 추가해보자.
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
/--
for(Cell cell : gameBoard)
if(cell.isFlagged())
flaggedCElls.add(cell);
--/
return flaggedCells
}
가독성도 확실히 올라갔고, 해당 로직을 더욱 이해하기 쉬워졌다.이러한 이유의 배경에는 변수명이나
메서드 명을 통해 명시적으로 의미가 드러나고, 의미를 파악할 수 있기 때문이다.
앞서 예시 case로 제시한 내용에서 기반이 되어야 하는 내용이라 생각하는 바는 다음과 같습니다.
- 기발한 이름은 피하라
- 나만이 알고 있는 단어나 이름이 아닌, 표준어를 사용 ( 사투리 등은 자제 )
- 한 개념에 한 단어를 사용하라
- 추상적인 개념이 있다면 사용하는 단어도 일치
예시 : 자원의 생성 : create or save 독자적이고 일관적인 이름을 사용하되, 메소드 별 네이밍 개념을 일관성 있게 만드는 것이 중요
- 해법 영역에서 가져온 이름을 사용하라
- 기술 영역에서 가지고 온 개념은 기술 이름을 네이밍 하는 것이 좋음
- 의미있는 맥락을 추가하라
- 의미있는 맥락을 추가하게되면 코드가 더욱 깔끔해진다.
- ex) city, zipcode, state, street
- ( 위치를 나타내는 변수명들 → 앞에 adr을 붙인다 → adrCitym adrZipcode ….)
( 혹은 자바같은 경우엔 Embedded Type으로 만들어주면 깔끔 )
- 불필요한 맥락을 없애라
- 예시 : DTO Files
- Dto 패키지 내부에 있는데 굳이 클래스 명에 DTO를 붙일 필요가 없음 ( 불필요한 맥락 )
- 예시 : DTO Files
챕터 2의에서 나타나고 있는 문제들을 해결하기 위해선 팀에서 만든 코딩 컨벤션을 지키는 일이 중요합니다.
좋은 코드와 관련된 내용을 충분히 논의하고, 만들어 가는 것이, 개발자들이 지향해야할 일이고, 여기서 합의한 내용을 지키는 것이 좋은 코드를 만드는 방법이라 생각하기 때문입니다.
이러한 충분한 논의(Code Convention) 속에 서는 다음 내용이 논의 되어야 합니다.
2.클래스 이름, 메서드 이름, 변수 명 등등의 일관화
이러한 이유는 프로젝트는 이해 관계가 있는 여러 사람들이 투입되어 진행해서, 각자 맡은 부분들이 있을 겁니다. 그래서 자신이 맡은 부분에 대해 개발을 진행하게 될 것인데, 사전에 미리 가이드라인을 정해놓지 않으면 자신의 경험에 의존해서 네이밍을 정할 것입니다.
자신의 경험에 의존하다보면 타인이 이해하지 못하는 상황이 발생할 수 있어 이로 인해 갈등이 발생할 수 있는데, 이를 해결하고자 클래스 이름과 메서드 명, 패키지 구조 등 여러 논의가 필요합니다. ( **해당 언어의 표준을 확인해보면 좋음** )
대표적으로 우리가 알고 있는 내용은 다음과 같습니다.
- 클래스 이름은 명사나 명사구로 사용할 것 ( Customer, WikiPage, Account )
- 메서드 이름은 동사나 동사구로 사용할 것 ( getName, setInfo, toEntity )
- 생성자 (Constructor)를 중복정의(Overload)할 땐 정적 팩토리 메서드 사용
PayPoint payPoint = PayPoint.changePoint(2000);( good Case )
PayPoint payPoint = new PayPoint(2000) ( soso Case ) - 한 개념에 한 단어를 사용할 것 ( 자원을 가지고 오는 행위 : getXXX , 자원 수정 : setXXX )
만약 여기서 사용할 단어가 없다면 도메인 영역을 참고하는 것도 좋은 방법이라 생각합니다.
'책 읽기' 카테고리의 다른 글
[Clean Code/클린 코드] - 객체와 자료구조 (0) | 2023.06.18 |
---|---|
[Clean Code/클린 코드] - 형식 맞추기 (1) | 2023.06.04 |
[Clean Code/클린 코드] - 주석 (0) | 2023.06.04 |
[Clean Code/클린 코드] - 함수 (0) | 2023.05.29 |
[자바 웹 프로그래밍 - Next Step] - 테스트와 리팩토링 (1) | 2022.12.27 |