각 목차마다 흥미로운 주제를 다뤄 현재까지도 매일 읽기를 실천하고 있다.
3장 함수의 내용이 읽으면 읽을 수록 좋은 내용이어서 반복해서 보고있다.
함수명에 의도를 분명히 나타내자.
함수 내의 추상화 수준은 동일해야한다.
이를 깬다면, 코드의 흐름을 깨고 혼란스러워질 수 있다.
함수명만 보고도 뭘 하는 기능이고, 어떤 흐름으로 실행되는지 예상할 수 있을 것이다.
만약 한 함수에 추상화 수준이 다양하다면 함수를 흐름을 깰 수가 있다.
또, 어떻게든 이해하려고 애쓸 것이다.
그냥 이런 일이 있기 전에 추상화 수준을 하나로 만들어 함수를 작성하자.
함수 내의 코드들이 자연스럽게 섹션으로 나눠진다면 추상화를 해야한다.
경제적인 코드, 미래의 나 그리고 팀원의 행복을 위해서는 좋은 함수를 작성하기 위해 노력해야한다.
이야기처럼 술술 잘 읽히는 코드야 말로 좋은 코드인 것 같다.
함수와 인자의 의존성을 느슨하게.
함수와 인자(파라미터)가 긴밀하게 연결되어있다.
만약 인자에 유형이 추가되면, 이 인자를 사용하는 함수에도 새로운 유형을 처리하는 함수를 작성해야한다.
또, 이러한 함수가 1개가 아니라 여러 개라면? 많은 수정이 필요할 거다.
이를 위해, 추상화된 인자를 사용한다.
함수는 이제 인자에 타입이 추가되든 ~ 삭제가 되든~ 상관없다. 오로지 자기가 해야할 일만 잘 수행하면된다.
함수의 관할이 아닌 코드에 수정이 발생했을 때, 함수도 수정이 되어야 한다면
나쁜 코드임을 의심하고, 추상화를 써먹어 보자.
지속적으로 주석을 유지보수 한다는 것은 불가능하다고 한다.
시스템을 표현하는 것은 함수. 주석은 시스템 구동에 아무 의미없다.
함수만이 진실된 정보를 표현한다.
나쁜 코드를 설명하려고 주석을 달 시간에
좋은 코드를 작성하자.
주석이 기능의 모든 걸 표현하긴 어렵다.
캡슐화를 사용하면, 내부 구현을 숨기면서 멤버변수에 대한 접근 정책을 강제할 수 있다.
추상 인터페이스를 제공해서 사용자가 내부 구현을 모른 채 자료를 조작할 수 있어야 진정한 의미의 클래스이다.
새로운 함수가 필요한 경우 절차적인 코드 + 자료구조
새로운 자료 타입이 필요한 경우에는 객체지향코드 + 클래스
시스템 안정성을 위해 꼭 필요한 오류처리.
오류를 처리하는 것도 하나의 일이다.
오류 처리 로직과 비즈니스 로직을 구분하자.
오류 코드를 사용해 if를 중첩해서 예외를 처리할 수 있지만, 이는 호출자 코드를 복잡하게 만든다. 오류를 처리하는 코드가 복잡해진다.
try-catch를 사용해 오류가 발생하면 예외를 던지도록 해서 코드를 간단하게 만들자.
미확인된 예외를 사용하라.
확인된 예외는 OCP를 위반한다. 새로운 예외가 추가되거나, 변경되면 최하위 함수로부터 최상위 함수까지의 연쇄적인 수정을 유발한다.
미확인된 예외를 사용해도 충분히 안정성 있는 소프트웨어를 구현할 수 있다고 한다.
예외를 구현할 때 드는 비용 그리고 이익을 고려하자.
예외에 의미를 제공하자. 수많은 예외가 존재하더라도, 예외에 대한 정보를 빠르고 쉽게 파악할 수 있도록 할 수 있다.
null 반환 지양. null를 반환했더라면 NullPointerException 예외에 대응을 해야한다.
많은 함수가 null을 반환한다면 처리해야하는 일도 많아진다.
null 반환 시 예외를 던지거나, 특수 사례 객체를 대신 반환하자.
예를 들어, 어떤 요소들을 포함한 배열을 반환해야할 때 요소가 하나도 없어 빈 배열을 반환해야한다면 null 대신 []을 반환할 수 있다.
null 전달 대응. 함수에 null 값이 인수로서 입력됐을 때, null에 대한 대응을 해주지 않았다면 에러를 발생시킬 것이다.
이를 위해 함수 호출전 null 입력에 대한 방어를 하거나, 아니면 함수에서 방어를 하는 방법이 있다.
결론, 오류 처리와 비즈니스 로직 처리를 분리해서 독립적으로 고려함으로서 튼튼하고 깨끗한 코드를 작성할 수 있다.