까진 유리창의 법칙
아무도 관심을 갖지 않으니 당신 마음대로 해도 좋다는 메시지를 전달한다…..
즉 사소해 보이는 것들이 사람들에게는 중요한 메시지를 전달한다.
깨끗한 코드를 유지해야 하는 이유
1. 나쁜 코드로 치르는 대가
나쁜코드가 쌓일수록 생산성은 계속 악화된다. 매번 얽히고 설킨 코드를 해독해서 얽히고 설킨 코드를 더할 수록 쓰레기 더미는 점점 높아지고 커진다.
2. 나쁜코드는 심각한 장애물이고 빨리 가려면 코드를 깨끗하게 유지해야한다. 우리는 새로운 코드를 짜면서 끊임 없이 기존코드를 읽는다(10:1=읽기:쓰기)
3. 깨끗한 코드라는 예술을 위해서는 다양한 방법/절차/기법을 아는 것이 필요하다.
깨끗한코드와 나쁜코드를 구분할 줄 안다!=깨끗한 코드를 작성할 줄 안다. 구분하는 법부터 배워보자
보이스카우트 규칙
캠프장은 처음 왔을때보다 더 깨끗하게 해놓고 떠나라.
체크아웃할 때보다 좀더 깨끗한코드를 체크인한다면 코드는 절대 나빠지지 않는다.
의미있는 이름
1. 의도를 분명히 밝혀라
변수/함수/클래스 이름은 존재 이유를 고려해서 정한다. (수행하는 기능, 가용하는 방법)
따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 뜻이다.
2.그릇된 정보를 피하라
유형을 이름에 넣지 않는 것이 좋다.
Ex: accountList->accountGroup, bunchOfAccounts
흡사한 이름 사용하지 않기
유사한 개념은 유사한 표기법 사용: 코드 자동완성 기능에서 핫키 사용이 수월하다.
I,O와 같이 오해가 생길 수 있는 변수 이름은 피하기(소문자 L은 1, 대문자 O는 0처럼 보인다)
3.의미있게 구분하라
연속적인 숫자를 덧붙이는 것은 아무런 정보를 제공하지 않는다
의미 불분명한 말을 추가한 이름도 아무런 정보를 제공하지 못한다.
읽는 사람이 차이를 알수 있도록 이름을 지어라
4.발음하기 쉬운 이름을 사용하라
대화/토론에서 발음하기 쉬운 이름을 선택 하는 것이 좋다.
5.검색하기 쉬운 이름을 사용하라
이름이 한 문자일 경우 코드에서 눈에 띄지 않는다.
숫자대신 constant 로 정의해서 상수를 사용하는 것이 좋다.
Ex)Vector는 grep 으로 찾기 쉽지만 4는 아니다.
변수/상수를 코드 여러곳에서 사용한다면 검색하기 쉬운 이름이 바람직하다.
6.인코딩을 피하라
헝가리식 포기법 하지마라….. 멤버 변수 접두어 사용필요없다. IDE 가 제공한다.
7.자신의 기억력을 자랑하지 마라
loop에서 반복횟수를 세는 변수 I,j,k는 상관없지만. (l은 안된다)
8. 클래스 메소드 이름
클래스: 명사나 명사구
메소드: 동사나 동사구
9. 한 개념에 한 단어를 사용하라
추상적인 개념하나에 단어 하나를 선택해 이를 고수한다. (fetch,retrieve,get……. 통일해라;;;)
10. 말장난하지마라
한단어를 두가지 목적으로 사용하지마라
ex) 기존코드에서 add 가 두값을 더하는데 사용되었다면, 값을 추가하는 변수는 insert 나 append를 사용하라
11. 해법(Solution) 영역에서 가져온 이름을 사용하라: 전산용어 알고리즘이름,패턴이름,수학용어 등등
12. 문제 영역에서 가져온 이름을 사용하라: 적절한 프로그래머 용어가 없다면 문제 영역에서 이름을 가져온다.
13. 의미있는 맥락을 추가하라: 클래스.,함수, 변수 이름에 의미를 넣어 맥락을 부여한다.
Ex: firstName,lastName,street,houseNumber,city,state,zipcodeà addrFirstName, addrLastName, addrState 더 좋은 방법은 Address 클래스 생성
14. 불필요한 맥락을 없애라: 의미가 분명한 경우에는 짧은 이름이 긴 이름 보다 좋다.
함수
1.작게 만들어라: 읽고 이해하기가 쉬워진다
If/else while 문에 들어가는 블록은 한줄이어야한다. : 중첩구조가 생길만큼 함수가 커져서는 안된다.
2.한가지만해라: 함수는 한 가지를 해야한다. 그 한가지를 잘 해야한다.
함수 당 추상화 수준은 하나로
위에서 아래로 내려가기 규칙: 한 함수 다음에는 추상화 수준이 한 단계 낮은 함수가 온다.
3.Switch 문: 다형성을 이용하라: 스위피문은 한가지 작업만 하도록 만들기 어렵다. 다형성을 이용하여 추상 팩토리에 숨겨 다형성 객체를 생성하는 코드에서만 사용한다.
4.함수 인수: 이상적인 인수의 개수는 0개
함수에 인수 1개를 전달하는 경우: 인수에 질문을 ㅈ던지는경우 인술르 뭐나로 변환해서 결과를 반환하는경우 이벤트 함수일경우 (이벤트라는 사실이 코드에 명확하게 드러나야 한다) 위 3개지경우가 아니라면 단항 함수를 가급적 피하라
플래그 인수: bool값을 넘긴다는 것은 함수가 여러가지 일을 처리한다고 공표 하는 것. 플래그 인수를 사용하지 말고 대신함수를 나눠라
인수 객체활용 : 인수가 2~3개 필요하다면 객페를 생성하여 인수를 줄인다
동사와 키워드:단항 함수는 함ㅁ수와 인수가 동사/명사 쌍을 이뤄야 한다. Ex) write(name);
함수 이름에 인수 이름을 추가하면 순서를 기억할 필요가 없다.
Ex)assertExpectedEqualActual(expected,actual);
5.부수 효과를 일으키지 마라: 한 함수에서는 딱 한가지만 수행해야 한다.
출력인수(함수의 반환 값이 아닌 입력 인수로 결과를 받는 경우): 출력 이수로 쓰일경우 인수 값이 변하는데 사용자가 이를 인지하기 어렵다 객체지향 프로그래밍 전에는 출력인수가 불가피한 경우도 있지만 객체지향이라면 멤버변수를 사용하는 것이 바람직함.
6.명령과 조회를 분리하라
7.오류코드보다 예외를 사용하라
오류코드에서enum 클래스 사용을 경계하라: 새 오류코드를 추가하거나 변경할 때 코스트가 많이 든다.
8.반복하지 마라: 중복은 모든 악의 근원 이다.
주석:
코드만으로 의도를 표현할 수 있어야 한다.
좋은 주석
1. 법적인 주석: 소스 파일 첫 머리에 위치 저작권 정보 소유권 정보
2. 정보를 제공하는 주석
3. 구현의도를 설명하는 주석
4. 의미를 명료하게 밝히는 주석: 인수나 반환값이 표준 라이브러리나 변경하지 못하는 코드에 속한다면 의미를 명료하게 밝히는 주석
5. 결과를 경고하는 주석: 다른 개발자에게 결과를 경고할 목적으로 사용
6. TODO 주석: 앞으로 할 일 당장 구현하기 어려운 업무 요청사항등을 기술 대다수IDE는 TODO만 리스트 업하는 기능을 가지고 있다.
7. 중요성을 강조하는 주석
나쁜주석
1. 주절거리는주석
2. 코드랑 내용이 중복되는 주석,오해할 여지가 있는 주석
3. 의무적으로 다는 주석
4. 있으나 마나 한 주석
5. 닫는 괄호에 다는 주석: 함수의 길이가 길 경우 닫는 괄호에 주석을 다는 경우가 많다. 함수의 길이를 짧게 리팩토링하면 닫는괄호에 주석이필요없다.
6. 이력을 기록하는 주석,저자를 표시하는 주석: 형상관리 시스템에서 제공한다.
7. 함수나 변수로 표현할 수 있는 주석
8. 전역정보를 제공하는주석: 주석을 달아야 한다면 근처에 있는 코드만 기술
9. 주석으로 처리한 코드 : 형상관리 쓰니까 걍 지워라
10. 위치를 표시하는 주석
11. 모호한 주석
형식 맞추기
코드형식은 의사소통의 일환이다. 처음 작은 구현스타일과 가독성 수준은 앞으로 바뀔 코드의 품질에 지대한 영향을 미치기 때문
세로 형식 맞추기: high levelLow level 순서로 작성
개념은 빈행으로 분리하라
서로 밀접한 행은 세로로 가까이 놓기
비슷한 동작을 수행하는 함수들을 가까이 배치
서로 밀접한행은 세로로 가까이 놓기
변수는 사용하는 위치에 최대한 가까이 선언: 각 함수 처음 부분에 지역 변수 선언, 루프제어 변수는 가급적 루프 문내부에 선언 단,인스턴스 변수는 클래스 맨처음에 선언함(java)
호출관계가 있는 종속함수는 세로로 가까이 배치
가로 형식 맞추기: 80줄 정도 너무 긴거별로
쓸데없는 띄우기 별로
들여쓰기
빈 while/for 문에는 세미콜론을 새 행에다 제대로 들여 써서 넣어준다.
팀 규칙: 팀은 한 가지 규칙에 합의 해야하며, 모든 팀원은 그 규칙을 따라야 함
좋은 소프트웨어 시스템은 읽기 쉬운 문서로 이뤄지고, 읽기 쉬운 sans서는 스타일리 일관적이고 매끄러워야 한다.
오류처리
1.에러코드보다 exception을 사용하라
2.Try catch finally 문부터 작성하라 try 블록에서 무슨일이 생기든지 catch 블록은 일관성있게 유지해야한다.
1.강제로 예외를 일으키는 테스트 케이스 작성
2.테스트를 통과하는 코드를 작성
테스트를 통과하기 위한 기본로직을 먼저 구현하게 됨
기존에 구현하려고 했던 의도를 잃지 않으면서 구현 가능
3.Exception을 던질 때는 전후 상황을 충분히 포함하도록 함오류가 발생한 원인과 위치를 찾기쉬워짐
4.호출자를 고려해 exception 클래스를 정의하라
오류를 분류하는 방법은 많음 but 오류를 잡아내는 방법이 더 중요 : weapper 사용
5.정상 흐름을 정의하라: 비즈니스 논리와 오류 처리를 잘 분리하면 코드가 깨끗해지지만 오류감지가 프로그램 언저리로 밀려남 특수사례패턴을 사용: 클래스를 만들거나 객체를 조작해 특수사례를 처리하는 방식. 클라이언트 코드가예외적인 상황을 처리할 필요가 없다.
6.Null을 반환하지마라: null을 반환하는 습관은 개발자가 흔히저지르는 오류를 유발하는행윌이다.
7.Null을 전달하지마라: 정상적인 인수로 null을 기대하는 api 가 아니라면 메서드로 null 전달은 지양
경계
시스템에 들어가는 모든 소프트웨어를 직접 개발하는경우는 드물다.
외부코드사용하기:패키지/프레임워크의인터페이스제공자와 사용자 사이에 입장차 존재
제공자: 더 많은 환경에서돌아가도록 적용성을 최대한넓히려 함
사용자: 자신의 요구에 집중하는 인터페이스를 바람
경계 인터페이스를 여기저기 넘기지 마라 map과 같은 경계 인터페이스를 이용할때는 캡슐화로 이를 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의 필요
학습테스트는 공짜 이상이다: 학습테스를 통해 확보한 테스트케이스로 패키지의 새버전이 나오면 코드와 호환되는지 확인 가능하다. 경계테스트가 있다면 패키지의 새버전으로 이전하기 쉬워진다. 그렇지 않다면 낡은 버전을 필요이상으로 오랫동안 사용하려는 유혹에 빠지기 쉽다.
아직 존재하지 않는 코드를 사용하기: 현재 알지 못하는 코드를 사용해야 한다면 자체 인터페이스를 정의하여 사용
깨끗한 경계
경계 에서는 많은 변경이 발생: 통제하지 못하는 코드를 사용할 때 향후 변경 비용을 줄일 수 있도록 주의 필요
경계에 위치하는 코드를 깔끔히 분리해야 함: 외부 패키지를 세세하게 알 필요 없음 통제가 불가능한 외부 패키지에 의존하기 보다 통제 가능한 우리 코드에 의존
깨끗한 경계를 위한 제안 사항 : 기대치를 정의하는 테스트 케이스 작성
외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리
패키지가 제공하는 인터페이스를 우리가 원하는 인터페이스로 변환하여 사용(새로운 클래스로 경계를 감싸거나 Adapter 패턴을 사용)
코드 가독성/경계 인터페이스를 사용하는 일관성 향상됨
외부 패키지가 변했을 때 변경할 코드 줄어듦
클래스
깨끗한 클래스: 가능한 비공개 상태를 유지 (캡슐화)할 방법을 강구
함수와 마찬가지로 클래스도 작게:한 클래스는 하나의 책임만 가져야 한다. (SRP(Single Responsibility Principle)
응집도를 유지하도록 여러 개 클래스로 분리
변경하기 쉬운 클래스: 클래스를 체계적으로 정리하여 변경에 수반하는 위험을 낮춰야한다. OCP(Open/Close principle) :클래스는 확장에 개방적이고 수정에 폐쇠적이어야한다.
인터페이스와 추상 클래스를 사용해 구현이 미치는 영향을 격리해야 한다. (DIP:Dependency inversion principle) 프로그래머는 추상화에 의존해야지 구체화에 의존하면 안된다.
클래스 체계: 클래스를 정의하는 표준 자바관례에 따르면 아래 순서대로 정의
Static public 상수 > static private 변수 > private instance 변수 > public 함수 > private 함수는 자신을 호출하는public 함수 바로 다음에 위치
신문 기사처럼 읽히도록 추상화 단계가 순차적을 내려가도록 작성
캡슐화를 풀어주는 결정은 최후의 수단: 변수와 유틸리티 함수는 가능한 공개하지 않음. Test를 위해 protected로 접근 허용은 가능
클래스는 작아야 한다.
클래스의 이름은 해당 클래스의 책임을 기술해야한다. : Processor Manager Super 와 같은 모호한 단어가 들어있다면 클래스에 여러 책임을 떠 안겼다는 증거
클래스 설명은 if,and,or,but을 사용하지 않고 25단어 내외로 설명 가능해야 한다.
클래스는 단 하나의 책임만 가져야한다.SRP
클래스는 인스턴스 변수 수는 적게, 각 메서드는 인스턴스 변수를 하나 이상 사용.: 일반적으로 메서드 변수를 더 많이 사용할수록 메서드와 클래스는 응집도가 높다.
응집도가 높다는 것은 : 클래스에 속한 메서드와 변수가 서로 의존하며, 논리적인 단위로 묶인다는 의미
클래스가 응집력을 잃으면 쪼개라:큰 함수를 작은 함수로 쪼개면 작은 클래스 여럿으로 쪼개짐프로그램이 점점 더 체계적이고 투명해짐
클래스를 쪼갰더니 프로그램이 길어졌다: 서술적인 변수 이름이 사용되고 주석을 추가하는 수단으로 함수 선언과 클래스 선언활용 가독성을 높이고자 공백을 추가하고 형식을 맞추었다.
변경하기 쉬운 클래스: 신규 기능 추가 시, 기존 코드 변경없이 시스템만 확장 OCP
의존관계 역전 원칙(DIP) 클래스는 상세한 구현이 아니라 추상화에 의존해야한다.
결합도가낮다: 시스템 요소가 다른 요소의 변화로 인한 영향에서 잘 격리되어 있다.