스터디/CleanCode
[CleanCode] Chapter03 함수
냠냠쿠
2023. 11. 3. 08:32
728x90
📖 책 내용 정리
🔶 3장 함수
1️⃣ 작게 만들어라
- 어떤 프로그램이든 가장 기본적인 단위가 함수이다.
- if문, else문, while문 등에 들어가는 블록은 한줄이어야한다.
(함수의 들여쓰기 수준은 1단이나 2단을 넘어서면 안 된다.)
2️⃣ 한가지만해라
- 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다.
- 단순히 다른 표현이 아니라 의미있는 이름으로 다른 함수를 추출 할 수 있다면 그 함수는 여러가지 작업을 하는 셈이다.
- 한 가지 작업만 하는 함수는 자연스럽게 섹션으로 나누기 어렵다.
3️⃣ 함수당 추상화 수준은 하나로
- 함수가 확실히 한가지 작업만 수행하려면 함수 내 모든 문장의 추상화 수준이 동일 해야한다.
→ 근본 개념인지 세부사항인지 구분할 수 있도록.
◾ 위에서 아래로 코드 읽기 : 내려가기 규칙
- 위에서 아래로 읽으면서 함수 추상화 수준이 한번에 한 단계씩 낮아진다.
- 각 함수가 다음 함수를 소개하듯이 작성하며 일정한 추상화 수준을 유지한다.
TO 설정 페이지와 해제 페이지를 포함하려면 A를 포함하고 B를 포함하고 C를 포함한다.
A를 포함하려면 A-1를 포함한 후 A-2를 포함한다.
A-1을 포함하려면 A-1-1을 포함한다
...
4️⃣ Switch문
- 본질적으로 switch문은 N가지를 처리한다.
- 다형성을 이용해 switch문을 추상팩토리에 숨기고 절대로 반복하지 않는 방법을 사용한다.
public abstract class school {
public abstract string teacher();
public abstract string student();
public abstract string classRoom();
}
public interface ISchool {
public school newSchool(schoolRecord r) throws InvalidSchoolType;
}
public class ISchoolImpl implements ISchool {
public School newSchool(schoolRecord r) throws InvalidSchoolType{
switch(r.Type){
case ...
}
}
5️⃣ 서술적인 이름을 사용하라
- 함수가 작고 단순할수록 서술적인 이름을 고르기도 쉬워진다.
- 서술적인 이름을 사용하면 개발자 머릿속에도 설계가 뚜렷해지므로 코드를 개선하기 쉬워진다.
- 이름을 붙일 때에는 일관성이 있어야 한다.
- 모듈 내 함수이름은 같은 문구, 명사, 동사를 사용한다.
6️⃣ 함수인수
- 인수 개수가 3개 이상인 경우는 피하는 것이 좋다.
예) includSetupPageInto(new PageContent) 보다 includeSetupPage()가 더 좋다.
◾ 많이 쓰는 단항 형식
- 함수에 인수를 한개를 넘기는 경우는 아래 경우가 아니라면 가급적 피한다.
- 인수에게 질문을 던지는 경우
- 인수로 뭔가를 반환하는 경우 이다.
- 이벤트로 해석하여 입력 인수로 시스템 상태를 바꾼다.
그리고 위의 경우 함수 이름을 분명히하여 혼선이 없도록 주의 해야 한다.
◾ 플래그 인수
- 함수가 한꺼번에 여러가지를 처리하는 대표적인 예이다.
◾ 이항 함수
- 단항 함수보다 이해하기 어렵다. 하지만
Point p = new Point(0, 0)
과 같이 좌표계 점과 같은 경우는 인수를 2개 쓰는 것이 더 적절할 때도 있다. - 이항함수는 단항함수로 바꾸어쓸 수 있도록 노력해야한다.
◾ 삼항 함수
assertEquals(1.0, amount, .0001)
과 같이 최대한 신중하게 고려하여 함수를 생성해야한다.
◾ 인수 객체
- 인수가 2~3개 필요하다면 일부를 독자적인 클래스 변수로 선언할 가능성을 짚어봐야한다.
◾ 인수 목록
- 인수 개수가 가변적인 함수가 필요한데, String.format 메서드가 좋은 예미여, String.format은 사실상 이항 함수다.
예)String.format("%s worked %.2f hours", name, hours)
◾ 동사와 키워드
- 단항 함수는 함수와 인수가 동사/명사 쌍을 이뤄야 한다
예)setName
- 함수이름에 키워드(인수 이름)를 추가한다.(인수 순서를 기억할 필요가 없어진다.)
예)assertExpectedEqulsActual(expected,actual)
7️⃣ 부수효과를 일으키지 마라
- 클래스 변수를 수정하거나 함수로 넘어온 인수나 시스템 전역 변수를 수정하지 않도록 한다.
public boolean checkPwd(String userName, String password){
...
if("Valid Password".equals(phrase)){
session.initialize();
}
...
}
예를들어 위의 같은 함수 이름을 통해 패스워드를 체크한다는 것은 알 수 있으나, session.initialize()
(세선초기화)를 한다는 사실이 드러나지 않는다. 만약 결합이 필요하다면 함수 이름에서 드러나도록 수정 해 준다.
◾ 출력 인수
- 일반적으로 인수를 함수 입력으로 해석한다. 그리고 출력 인수는 피해야한다.
- 부득이하게 출력 인수를 사용하는 경우, 이 함수가 하는 일과 동시에 출력 인수임을 밝혀준다.
예)report.appendFooter()
8️⃣ 명령과 조회를 분리하라
- 명령과 조회를 섞으면 (ex. 이름이 A인 속성을 찾아 value로 설정 한 후 성공하면 true 실패하면 false 반환 등) 혼란을 초래한다.
9️⃣ 오류 코드보다 예외를 사용하라
- 명령 함수에서 오류코드를 반환하면 자칫 if문에서 명령을 표현식으로 사용하기 쉬워진다.
- 위의 경우 여러단계로 중첩되는 코드를 야기한다. 오류코드를 반환하면 호출자는 오류코드를 곧바로 처리해야한다는 문제에 부딪힌다.
- 예외를 사용하면 오류 처리 코드가 원래의 코드에서 분리되어 코드가 깔끔해진다.
◾ Try/Catch 블록 뽑아내기 - try/catch블록은 코드 구조에 혼란을 일으키고 정상 동작과 오류 처리 동작을 뒤섞기 때문에 별도의 함수로 뽑아낸다
public void delete (Page page){
try {
deletePage(page);
}
catch (Exception e){
logError(e);
}
}
private void deketePage(Page page) throws Exception{
deletePage(page);
...
}
◾ 오류 처리도 한 가지 작업이다.
- 오류를 처리하는 함수는 오류만 처리 해야한다.
◾ Error.java 의존성 자석
- 오류코드를 반환한다는 이야기는 클래스든, 열거형 변수든 어디선가 오류코드를 정의한다는 뜻
- 아래와 같은 코드가 의존성 자것ㄱ인데, Error enum이 변하면 Error enum을 사용하는 클래스 전부를 다시 컴파일하고 배치해야하기 때문에 error 클래스 변경이 어려워진다.
오류코드 대신 예외를 사용하면 재컴파일/재배치 없이도 새 예외 클래스를 추가 할 수 있다. public enum Error { 404, 505, ... }
1️⃣0️⃣ 반복하지마라
- 다른 코드와 섞이면서 모양새가 조금씩 달라진 탓에 중복이 금방 드러나지 않더라도 중복은 문제다.
1️⃣1️⃣ 구조적 프로그래밍
- 데이크스트라 : 모든 함수와 함수 내 모든 블록에 입구와 출구가 하나만 존재해야함.
즉, 함수는 return 문이 하나여야한다. - 루프안에서 break, continue, goto는 절대로 사용하면 안되지만,
함수를 작게 만든다면 간혹 return, break, continue를 여러번 사용해도 괜찮다. 하지만 goto는 큰 함수에서만 의미가 있으므로 작은 함수에서는 피해야한다.
1️⃣2️⃣ 함수를 어떻게 짜죠?
- 처음에는 길고 복잡하지만 빠짐없이 테스트하는 단위 테스트 케이스로 만들고, 코드를 다듬고 함수를 만들고 이름을 바꾸고 중복을 제거한다.
- 메서드를 줄이고, 순서를 바꾸고, 전체 클래스를 쪼개기도한다.
- 최종적으로는 설명한 규칙을 따르는 함수가 얻어진다.
1️⃣3️⃣ 결론
- 모든 시스템은 프로그래머가 설계한 도메인 특화 헌어로 만들어진다.
그 안에서 함수는 동사고, 클래스는 명사다. - 함수가 분명하고 정확한 언어로 깔끔하게 맞아떨어져야 시스템이라는 이야기를 풀어나가기 쉬워진다.
💌 책에서 기억하고 싶은 내용
부수효과를 일으키지마라
코드는 위에서 아래로 이야기처럼 읽혀야 좋다.
함수는 한 가지를 잘 해야한다. 그 한 가지를 잘 해야한다.
오류도 한 가지 작업이다.
💬 소감
이번 내용은 정말 어려웠던 점이 많았던 것 같다.
사실 코드를 짜다보면, 기능을 만드는 순서대로 줄줄 써지다보니 코드의 순서로 인해 가독성이 달라진다는 부분을 생각도 하지 못했다.
부수효과를 일으키지마라라는 부분이 무슨말을 하는거지 ? 했는데 코드를 보니 단박에 이해가 갔다.
C#을 이용하여 코드를 짰을때, 저랬던 적이 있기 때문에 찔리기도 했다.
나는 이 과정을 거치면 당연한 과정이지라고 생각했지만 다른 개발자가 읽을 때에는 미처 생각하지 못한 부분이라 오류를 발생할 수 있을 것이라고는 생각지도 못했다.
책을 읽으면서 switch 문을 작게 만드는 방법과 try/catch문을 뽑아내는 부분은 새롭게 알게 된 부분이라 다음에 실무에서 꼭 적용 해 보고 싶다는 생각을 했다.
💥 이해 안 가는 부분
- 인수 객체(53p), 출력 인수(56p)는 이해가 잘 가지 않았다.
출력 인수는 잘 쓸 일이 없지만, 인수 객체에 관해서는 따로 공부 해 볼 생각이다.
728x90