프로그래밍/Java

나쁜 코드 지우기 5

이재만박사 2017. 11. 28. 13:59


* 일반


G7. 기초 클래스가 파생 클래스에 의존한다


 - 개념을 기초 클래스와 파생 클래스로 나누는 가장 흔한 이유는 고차원 기초 클래스 개념을 저차원 파생 클래스 개념으로부터 분리해 독립성을 보장하기 위해서다 

그러므로 기초 클래스가 파생 클래스를 사용한다면 뭔가 문제가 있다는 말이다

일반적으로 기초 클래스는 파생 클래스를 아예 몰라야 마땅하다


물론 예외는 있다 

간혹 파생 클래스 개수가 확실히 고정되었다면 기초 클래스에 파생 클래스를 선택하는 코드가 들어간다

FSM(Finite State Machine) 구현에서 많이 본 사례다 

하지만 FSM은 기초 클래스와 파생 클래스가 굉장히 밀접하며 언제나 같은 JAR 파일로 배포한다

일반적으로는 기초 클래스와 파생 클래스를 다른 JAR 파일로 배포하는 편이 좋다


기초 클래스와 파생 클래스를 다른 JAR 파일로 배포하면, 그리고 기초 JAR 파일이 파생 JAR 파일을 전혀 모른다면, 독립적인 개별 컴포넌트 단위로 시스템을 배치할 수 있다. 

만약 컴포넌트를 변경한다면 해당 컴포넌트만 다시 배치하면 된다

기초 컴포넌트까지 다시 배치할 필요가 없다

즉 변경이 시스템에 미치는 영향이 아주 작아지므로 현장에서 시스템을 유지보수하기가 한결 수월하게 된다



G8. 과도한 정보


- 잘 정의된 모듈은 인터페이스가 아주 작다 하지만 작은 인터페이스로도 많은 동작이 가능하다

부실하게 정의된 모듈은 인터페이스가 구질구질하다 그래서 간단한 동작 하나에도 온갖 인터페이스가 필요하다

잘 정의된 인터페이스는 많은 함수를 제공하지 않는다 그래서 결합도(coupling)가 낮다

부실하게 정의된 인터페이스는 반드시 호출해야 하는 온갖 함수를 제공한다 그래서 결합도가 높다


우수한 소프트웨어 개발자는 클래스나 모듈 인터페이스에 노출할 함수를 제한할 줄 알아야 한다

클래스가 제공하는 메서드 수는 작을수록 좋다 함수가 아는 변수 수도 작을 수록 좋다

클래스에 들어있는 인스턴스 변수도 작을 수록 좋다


자료를 숨겨라 유틸리티 함수를 숨겨라 상수와 임시 변수를 숨겨라 

메서드나 인스턴스 변수가 넘쳐나는 클래스는 피하라

하위 클래스에서 필요하다는 이유로 protected 변수나 함수를 마구 생성하지 마라

인터페이스를 매우 작게 그리고 매우 깐깐하게 만들어라 정보를 제한해 결합도를 낮춰라



G9. 죽은 코드


- 죽은 코드란 실행되지 않는 코드를 가리킨다

불가능한 조건을 확인하는 if문과 throw 문이 없는 try 문에서 catch 블록이 좋은 예다

아무도 호출하지 않는 유틸리티 함수와 switch/case 문에서 불가능한 case 조건도 또 다른 좋은 예다

죽은 코드는 시간이 지나면 악취를 풍기기 시작한다

죽은 지 오래될수록 악취는 강해진다 죽은 코드는 설계가 변해도 제대로 수정되지 않기 때문이다

컴파일은 되지만 새로운 규칙이나 표기법을 따르지 않는다

옛날옛적 시스템의 모양새가 다른 시절에 짜놓은 코드다 

죽은 코드를 발견하면 올바른 행동을 취하기 바란다 적절한 장례식을 치뤄주라 시스템에서 제거하라



G10. 수직 분리


변수와 함수는 사용되는 위치에 가깝게 정의한다

지역 변수는 처음으로 사용하기 직전에 선언하면 수직으로 가까운 곳에 위치해야 한다

선언한 위치로부터 몇백 줄 아래에서 사용하면 안 된다


비공개 함수는 처음으로 호출한 직후에 정의한다

비공개 함수는 전체 클래스 범위에 속하지만 그래도 정의하는 위치와 호출하는 위치를 가깝게 유지한다

비공개 함수는 처음으로 호출되는 위치를 찾은 후 조금만 아래로 내려가면 쉽게 눈에 띄어야 한다



G11. 일관성 부족


- 어떤 개념을 특정 방식으로 구현했다면 유사한 개념도 같은 방식으로 구현한다 

앞서 언급한 최소 놀람의 원칙에도 부합한다

표기법은 신중하게 선택하며, 일단 선택한 표기법은 신중하게 따른다

한 함수에서 response라는 변수에 HttpServletResponse 인스턴스를 저장했다면 다른 함수에서도 일관성 있게 동일한 변수 이름을 사용한다

한 메서드를 processVerificationRequest라 명명했다면 다른 메서드도 (processDeletionRequest처럼) 유사한 이름을 사용한다

착실하게 적용한다면 이처럼 간단한 일관성만으로도 코드를 읽고 수정하기가 대단히 쉬워진다



G12. 잡동사니


 - 비어 있는 기본 생성자가 왜 필요한가? 쓸데 없이 코드만 복잡하게 만든다

아무도 사용하지 않는 변수, 아무도 호출하지 않는 함수, 정보를 제공하지 못하는 주석 등이 좋은 예다

모두가 코드만 복잡하게 만들 뿐이므로 제거해야 마땅하다 소스 파일은 언제나 깔끔하게 정리하라

잡동사니를 없애라!



G13. 인위적 결함


 - 서로 무관한 개념을 인위적으로 결합하지 않는다

예를 들어, 일반적인 enum은 특정 클래스에 속할 이유가 없다.

enum이 클래스에 속한다면 enum을 사용하는 코드가 특정 클래스를 알아야만 한다

범용 static 함수도 마찬가지로 특정 클래스에 속할 필요가 없다


일반적으로 인위적인 결합은 직접적인 상호작용이 없는 두 모듈 사이에서 일어난다

뚜렷한 목적 없이 변수, 상수, 함수를 당장 편한 위치에 넣어버린다(잘못된 위치) 게으르고 부주의한 행동이다

함수, 상수, 변수를 선언할 때는 시간을 들여 올바른 위치를 고민한다

그저 당장 편한 곳에 선언하고 내버려두면 안 된다