클린코드 챌린지 Day 05
오늘 TIL 3줄 요약
- 중첩 구조가 생길만큼 함수가 커져서는 안 된다. 들여쓰기 수준은 1단이나 2단을 넘어서면 안 된다.
- 단순히 다른 표현이 아니라 의미 있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다.
- 코드 중복은 코드 길이가 늘어날 뿐 아니라 유지보수가 힘들어진다. 중복은 소프트웨어에서 모든 악의 근원이다.
TIL (Today I Learned) 날짜
2022.04.26 - 2022.04.27
오늘 읽은 범위
3장. 함수
작게 만들어라!
함수를 만드는 첫째 규칙은 ‘작게!’다. 함수를 만드는 둘째 규칙은 ‘더 작게!!’다.
블록과 들여쓰기
if문, while문 등 들여쓰기 블록은 한 줄이여야 한다. 바깥을 감싸는 함수가 작아질 뿐 아니라, 블록 안에서 호출하는 함수 이름을 적절히 짓는다면, 코드를 이해하기도 쉬워진다.
💡 중첩 구조가 생길만큼 함수가 커져서는 안 된다. 들여쓰기 수준은 1단이나 2단을 넘어서면 안 된다.
한 가지만 해라!
함수는 한 가지를 해야한다. 그 한가지를 잘해야한다. 그 한 가지만을 해야한다.
지정된 함수 이름 아래에서 추상화 수준이 하나인 단계만 수행한다면 그 함수는 한 가지 작업만 한다. 큰 개념을 다음 추상화 수준에서 여러 단계로 나눠 수행하는 것이 함수의 목적이다.
💡 단순히 다른 표현이 아니라 의미 있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 셈이다.
함수 당 추상화 수준은 하나로!
함수가 확실히 ‘한 가지’ 작업만 하려면 함수 내 모든 문장의 추상화 수준이 동일해야 한다. 한 함수 내에 추상화 수준을 섞으면 코드를 읽는 사람이 헷갈린다. 특정 표현이 근본 개념인지, 세부사항인지 구분하기 어렵기 때문이다. 이를 뒤섞기 시작하면 깨진 창문처럼 사람들은 함수에 세부사항을 점점 더 추가한다.
위에서 아래로 코드 읽기: 내려가기 규칙
코드는 위에서 아래로 이야기처럼 읽혀야 좋다. 한 함수 다음에는 추상화 수준이 한 단계 낮은 함수가 온다. 즉, 위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다. 이것을 내려가기 규칙이라 부른다.
SRP (Single Responsibility Principle)
객체 지향 프로그래밍에서 단일 책임 원칙(SRP, Single Responsibility Principle)이란 모든 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화해야 함을 일컫는다. 클래스가 제공하는 모든 기능은 이 책임과 주의 깊게 부합해야 한다.
OCP (Open-Closed Principle)
개방-폐쇄 원칙(OCP, Open-Closed Principle)은 ‘소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다’는 프로그래밍 원칙이다. 소프트웨어 개발 작업에 이용된 많은 모듈 중에 하나에 수정을 가할 때 그 모듈을 이용하는 다른 모듈을 줄줄이 고쳐야 한다면, 이와 같은 프로그램은 수정하기가 어렵다. 개방-폐쇄 원칙은 시스템의 구조를 올바르게 재조직(리팩토링)하여 나중에 이와 같은 유형의 변경이 더 이상의 수정을 유발하지 않도록 하는 것이다. 개방-폐쇄 원칙이 잘 적용되면, 기능을 추가하거나 변경해야 할 때 이미 제대로 동작하고 있던 원래 코드를 변경하지 않아도, 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다. 객체 지향 프로그래밍의 핵심 원칙이라고 할 수 있다.
서술적인 이름을 사용하라!
“코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드라 불러도 되겠다.”
한 가지만 하는 작은 함수에 좋은 이름을 붙인다면 이런 원칙을 달성함에 있어 이미 절반은 성공했다. 함수가 작고 단순할수록 서술적인 이름을 고르기도 쉬워진다.
서술적인 이름을 사용하면 개발자 머릿속에서도 설계가 뚜렸해지므로 코드를 개선하기 쉬워진다. 좋은 이름을 고른 후 코드를 더 좋게 재구성하는 사례도 없지 않다.
이름을 붙일 때는 일관성이 있어야 한다. 모듈 내에서 함수 이름은 같은 문구, 명사, 동사를 사용한다.
함수 인수
함수에서 이상적인 인수 개수는 0개(무항)다. 인수는 개념을 이해하기 어렵게 만든다.
많이 쓰는 단항 형식
함수에 인수 1개를 넘기는 이유로 가장 흔한 경우
- 인수에 질문을 던지는 경우
- 인수를 뭔가로 변환해 결과를 반환하는 경우
- 출력 없이 함수 호출을 이벤트로 해석해 입력 인수로 시스템 상태를 바꾼다.
다음의 경우가 아니라면 단항 함수는 가급적 피한다.
플래그 인수는 추하다. 함수를 나눠야 마땅하다.
이항 함수, 삼항 함수
인수 객체
객체를 생성해 인수를 줄이는 방법은 눈속임이 아니다. 변수를 묶어 넘기려면 이름을 붙여야 하므로 결국은 개념을 표현한다.
부수 효과를 일으키지 마라!
부수 효과는 거짓말이다. 함수에서 한 가지를 하겠다고 약속하고선 남몰래 다른 짓도 하니까.
예상치 못하게 클래스 변수를 수정하거나, 넘어온 인수나 시스템 전역 변수를 수정한다면, 시간적인 결합이나, 순서 종속성을 초래한다.
출력 인수
일반적으로 우리는 인수를 함수 입력으로 해석한다. 객체 지향 프로그래밍 언어에서는 출력 인수로 사용하기 위해 설계한 변수가 this이다. 함수에서 인수의 상태를 변경해야 한다면 인수 객체의 상태를 변경하는 함수로 선언하는 방식을 택한다.
명령과 조회를 분리하라!
오류 코드보다 예외를 사용하라!
오류 처리도 한 가지 작업이다. Try/catch문을 함수에서 뽑아내자.
반복하지 마라!
코드 중복은 코드 길이가 늘어날 뿐 아니라 유지보수가 힘들어진다. 중복은 소프트웨어에서 모든 악의 근원이다.
함수를 어떻게 짜죠?
먼저 생각을 기록한 후 읽기 좋게 다듬는다. 처음에는 길고 복잡하며 서투른 코드를 작성한다. 하지만 그 코드를 빠짐없이 테스트하는 단위 테스트 케이스도 만든다. 그런 다음 코드를 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거한다. 메서드를 줄이고 순서를 바꾼다. 떄로는 전체 클래스를 쪼개기도 한다. 이 와중에도 코드는 항상 단위 테스트를 통과하도록 작성한다. 처음부터 탁 짜내지 않는다. 그게 가능한 사람은 없을것이다.
프로그래밍 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어간다. 시스템에서 발생하는 모든 동작을 설명하는 함수 계층이 바로 그 언어에 속한다. 작성하는 함수가 분명하고 정확한 언어로 깔끔하게 같이 맞아떨어져야 이야기를 풀어가기가 쉬워질 것이다.
오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요
각 도메인 영역에서 전문성이 있을 때 비로소 올바른 추상화를 할 수 있을 것 같다.
내가 개발하고자 하는 시스템의 도메인에서는 이 함수가 한가지 일을 수행하는 것일까라는 의문을 생각해봐야 한다.
고로 전체적인 시스템의 목적을 알지 못한다면 좋은 함수를 짜낼수 없을 것 같다는 생각이 들었다.
궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.
올바른 단위 테스트 방법이 궁금해졌다. 높은 코드 커버리지가 유지보수에 구체적으로 어떤 영향을 미칠까?