이번 주 목차
5장 형식 맞추기
6장 객체와 자료 구조
7장 오류처리
8장 경계
5장 형식 맞추기
- 형식을 맞추는 목적
코드 형식은 중요하다!
오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도
맨 처음 잡아놓은 구현 스타일과 가독성 수준은 유지보수 용이성과 확장성에 계속 영향을 미친다.
원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다.
- Clean Code 96 Page 인용 -
그래서 우리 회사의 코드는 10년 전의 스타일을 그대로 유지하고 있다.
처음부터 스타일과 규율을 잘 잡는 코드습관을 가지도록 하자.
- 적절한 행 길이를 유지하라
신문 기사처럼 작성하라.
이름은 간단하면서도 설명이 가능하게 짓는다.
이름만 보고도 올바른 모듈을 살펴보고 있는지 아닌지를 판단할 정도로 신경 써서 짓는다.
소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명한다.
아래로 내려갈수록 의도를 세세하게 묘사한다.
마지막에는 가장 저차원 함수와 세부 내역이 나온다.
- Clean Code 98 Page 인용 -
- 가로 형식 맞추기
- 팀 규칙
요즘은 짝프로그래밍도 많이 한다고 한다.
협업을 중시하게 여겨서 그런 듯 하다.
좋은 시스템은 읽기 쉬운 문서로 이뤄진다는 사실을 기억하며 일관적인 스타일의 팀 규칙을 만들어가자.
- 밥 아저씨의 형식 규칙
5장 형식 맞추기 내 맘대로 정리
나는 좋은 코드 습관이라 생각이 드는 것 중 하나가 변수 선언 시 지역변수는 함수 맨 처음에 선언한다.
이 부분이라고 생각한다. 형식 맞추기는 코드를 유지보수 하다 보면 저절로 따라오게 되어있다고 생각한다.
물론 시간에 쫓겨 코드를 짜다 보면 그 형식을 파괴할 때도 있지만 나는 항상 코드 커밋 전에 순서를 정리하고는 한다.
내가 읽기 편한 코드가 그나마 남들도 읽기 편하다고 생각하기 때문이다.
나는 솔루션 기업을 다니는 입장으로 내가 쉬면 다른 사람이 내 코드를 읽어야 하기 때문에, 꼭 팀 규칙에 맞추려고 노력하고 있다. 그 규칙이 옛날 규칙이라고 할지라도 말이다....
< 내가 가지고 있는 습관 >
첫째 변수를 맨 위에서 선언한다.
처음부터 변수를 선언하고 코드를 시작한다.
물론 중간에 한 번만 등장하는 변수일 경우에는 중간에 선언하지만 계속해서 사용하는 변수는 위에 선언한다.
public static void main(String[] args){
int seq = "";
String channel = "";
String[][] SiteList = null;
List<String[]> ExSiteList = null;
Map<String, String> CodeMap = null;
}
둘째, 클래스를 개념적으로 유사한 것끼리 묶어둔다.
셋째, 종속함수의 경우 항상 세로로 가까운 곳에 배치한다.
그래야 나중에 다시 수정할때도 읽기 쉽다.
원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다.
잊지말자.
6장 객체와 자료 구조
- 자료 추상화
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 편이 왜 더 좋은 것일까?
추상적인 것이 왜 더 좋은지 잘 모르겠다.
보안 측면 때문일까?
그래서 검색을 해봤더니 의도하지 않는 변화를 최소화하고, 정보 은닉 즉 보안에 좋다고 한다.
그리고 추상화로 의해 객체지향 프로그래밍 기법이 가능하게 된다고 한다.
- 자료 / 객체 비대칭
- 디미터 법칙
디미터 법칙은 객체간 결합도를 낮추는 원칙이다.
void MyMethod(int length){ for(int i=0; i<length; i++){ play.cars().getCar(i) } }
위의 코드는 디미터 법칙을 위반하는 코드이다. 아래처럼 수정한다.
void MyMethod(int length){ for(int i=0; i<length; i++){ play.car(i) } }
그래서 디미터 법칙을 한 줄에 점 하나만 찍는다고 요약해서 말하기도 한다.
- youngjinmo.github.io/2021/03/law-of-demeter/ 블로그 인용 -
- 자료 전달 객체
자료 전달 객체의 일반적인 형태는 빈(bean) 구조이다.
- 결론
시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다.
다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.
우수한 소프트웨어 개발자는 편견 없이 이 사실을 이해해 직면한 문제에 최적인 해결책을 선택한다.
- Clean Code 128 Page 인용 -
6장 객체와 자료 구조 내 맘대로 정리
객체와 자료구조를 적절히 구분하면서 사용하라는 말일까?
객체와 자료구조가 무엇인가부터 시작해야 할 것 같다.
객체는 구체적인 클래스와 추상적인 클래스로 나누자.
자료구조는 절차적인 도형과 다형적인 도형으로 나누자.
그러면 객체와 자료구조는 근본적으로 양분된다.
절차적인 코드는 기존 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.
객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.
절차적인 코드는 새로운 자료 구조를 추가하기 어렵다.
그러려면 모든 함수를 고쳐야 한다. 객체 지향 코드는 새로운 함수를 추가하기 어렵다.
그러려면 모든 클래스를 고쳐야 한다.
- Clean Code 122 Page 인용 -
위의 말처럼 필요에 따라 적절히 사용하라는 말인 것 같다.
객체지향 프로그래밍을 하도록 하자.
7장 오류처리
- 오류 코드보다 예외를 사용하라
예외코드를 사용하면 각 개념을 독립적으로 살펴보고 이해할 수 있다.
- Try-Catch-Finally 문부터 작성하라
Try 블록은 트랜잭션과 비슷하다.
Try 블록에서 무슨 일이 생기든지 catch 블록은 프로그램 상태를 일관성 있게 유지해야 한다.
Try-Catch-Finally 문부터 작성할 때,
Try 블록에서 무슨 일이 생기든지 호출자가 기대하는 상태를 정의하기 쉬워진다.
- Clean Code 132 Page 인용 -
상태를 정의하기 쉬워진다는 말은 코드가 쉬워진다는 말인 것 같다.
- 미확인 예외를 사용하라
- 예외에 의미를 제공하라
- 호출자를 고려해 예외 클래스를 정의하라
- 정상 흐름을 정의하라
클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식이다.
그러면 Try-Catch-Finally 문을 처리할 필요가 없어진다.
public class PerDiemMealExpenses implements MealExpenses {
// 기본값으로 항상 일일 기본 식비를 반환한다.
public int getTotal(){
}
}
//그러면 아래와 같은 간결한 코드가 가능하다.
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
- null을 반환하지 마라
자바는 null을 반환한다.
반드시 null을 반환할 필요가 있을까?
나는 그래서 쿼리단에서 null 값을 ""값으로 처리해서 사용한다.
null 값은 꼭 반환하지 않아도 좋다.
- null을 전달하지 마라
null을 반환하지도 말고 전달하지도 말라고 저자는 말하고 있다.
좋은 말인 것 같다.
때때로 null을 전달하는 코드가 종종 보인다.
앞으로 이런 코드는 바로 수정해주자.
- 결론
깨끗한 코드는 읽기도 좋아야 하지만 안정성도 높아야 한다.
이 둘은 상충하는 목표가 아니다.
오류 처리를 프로그램 논리와 분리해 독자적인 사안으로 고려하면 튼튼하고 깨끗한 코드를 작성할 수 있다.
오류 처리를 프로그램 논리와 분리하면 독립적인 추론이 가능해지며 코드 유지 보수성도 크게 높아진다.
- Clean Code 142 Page 인용 -
7장 오류처리 내 맘대로 정리
오류 코드보다는 예외를, 예외에는 의미를 두기!
안정성이 높은 코드를 작성하기!
이 2가지를 유의하면서 코드를 작성하면 유지 보수도 적게 할 수 있다.
8장 경계
- 외부 코드 사용하기
경계 인터페이스를 이용할 때는 이를 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의한다.
- Clean Code 146 Page 인용 -
- 경계 살피고 익히기
학습 테스트 하기.
테스트 코드를 만들라는 말인 것 같다.
외부 API는 언제 변경될지 모른다. 이를 방지하기 위해 테스트 코드를 작성하라는 말일까?
- log4j 익히기
독자적인 클래스로 캡슐화하라.
공부해서 혼자 써도 될 정도로 캡슐화하라는 말이다.
- 학습 테스트는 공짜 이상이다
통합된 다음 패키지가 우리 코드와 호환되지 않는다면 테스트 코드가 무슨 소용일까?
호환되지 않는다면 어서 새 버전으로 갈아타라고 독자는 말하는 것 같다.
- 아직 존재하지 않는 코드를 사용하기
구현을 나중으로 미루고 자체적으로 인터페이스를 정의하기.
우리가 구현해서 우리가 원하는 대로 테스트 하고 통제할 수 있다.
수고는 우리가 조금 더 하는 거로 ?
- 깨끗한 경계
경계에 위치하는 코드는 깔끔히 분리한다.
외부 코드에 휘둘리지 않게 분리한다.
외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자.
우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자.
어느 방법이든 코드 가독성이 높아지며,
경계 인터페이스를 사용하는 일관성도 높아지며,
외부 패키지가 변했을 떄 변경할 코드도 줄어든다.
- Clean Code 152Page 인용 -
8장 경계 내 맘대로 정리
경계는 조금 어렵다.
읽다 보면 사수님이 말씀해주신 문장이 떠오른다.
언제 변할지 모르는 API를 사용하는 것 보다는 독자적으로 만들어서 사용하는 것이 오류 잡기 쉽다.
'STUDY REVIEW > 클린코드 독서스터디' 카테고리의 다른 글
Clean Code - (3 - 2)주차 (0) | 2021.05.21 |
---|---|
Clean Code - 3주차 (0) | 2021.05.21 |
Clean Code - 2주차 스터디 후기 (0) | 2021.05.11 |
Clean Code - 1주차 스터디 후기 (0) | 2021.05.03 |
Clean Code - 1주차 (0) | 2021.05.03 |