완벽한 코드 작성을 위한 클린 코드

Page 1

이성우

완벽한 코드 작성을 위한 클린 코드 클린 코드 클린코드란 무엇이며 이를 지향해야 하는 이유가 무엇인지에 대한 개괄이다. 나쁜 코드를 작성했을 때 치러 야 하는 대가와 좋은 코드에 대한 전문가들의 견해를 공유한다. 아래의 구절이 가장 인상깊었다. 일정에 쫓기더라도 대다수 관리자는 좋은 코드를 원한다. 그들이 일정과 요구사항을 강력하게 밀어붙이는 이 유는 그것이 그들의 책임이기 때문이다. 좋은 코드를 사수하는 일은 바로 우리 프로그래머들의 책임이다.

의미 있는 이름 변수나 함수, 클래스의 이름을 지을 때 신중할 것을 강조하고 있다. 이름은 그 의미를 포함하고 있어야 하며, 정확한 정보를 제공해야 하며, 여러 개의 나열인 경우 의미 구분이 가능해야 하고, 발음하기 쉬우며 검색이 쉬운 이름이 좋다. 축약하지 말고 헝가리식 표기법이나 멤버변수 접두어를 사용하며 기억력을 과신하지 말도 록 당부한다. 클래스명은 명사나 명사구, 메소드명은 동사나 동사구로 짓는게 좋으며 기발한 이름이나 말장 난은 가급적 피한다. 개념 하나에 하나의 단어를 사용하며, 프로그래머가 이해할 수 있는 범위에서 용어를 정한다. 변수의 컨텍스트를 분명히 하는 것도 중요하다.

함수 함수는 10 줄 내외로 짧게 작성하되 조건문 안의 블록은 한줄로 제한한다. 하나의 함수는 한 가지만 하며 함 수당 추상화의 수준을 하나로 줄여야 하고, 코드는 위에서 아래로 읽기 좋아야 한다. Switch 문은 작게 만들 기 어려우므로 다형적 객체를 생성하는 정도에서만 사용하고 가급적 지양한다. 함수명은 길어도 좋으니 서술 적으로 짓도록 하고 인수는 가급적 사용하지 않는다. 특히 출력인수는 코드를 이해하기 매우 어렵게 만든다. 단항 함수는 가급적 피하고 입력인수라도 반환하는 형식을 취하도록 한다. 플래그 인수를 지양하고 인수가 여러 개 필요한 경우는 인수객체를 생성하도록 한다. 함수명은 동사+명사 형 태를 취하고 인자를 표현하는 것도 고려한다. 함수에서 여러가지를 처리하려고 부수효과를 일으키면 안되며 명령과 조회는 서로 다른 함수에서 수행하도록 한다. 오류 코드보다는 예외를 이용하여 try/catch 문에서 처 리하도록 하며 try 문과 catch 문도 별도의 함수로 작성한다. 동일한 알고리즘을 반복하지 않도록 하며 구조 적 프로그래밍의 원칙대로 함수는 하나의 진입점과 출구를 가진다.

주석 주석으로 나쁜 코드를 보완하려고 의도하지 않는다. 코드에 주석을 달기 전에 우선 코드를 깔끔하게 정리하 려고 노력한다. 프로그램의 의도는 가급적이면 코드에서 명시적으로 드러나도록 하면 필요없는 지저분한 주 석을 줄일 수 있다. 좋은 주석은 법적으로 필요한 경우와 기본적인 정보를 제공하는 주석, 구현보다는 결정 에 깔린 의도를 설명하는 경우, 의미를 명료하게 밝혀주거나 결과를 경고하거나 중요성을 강조, TODO 와 JavaDocs 정도로 제한하는 것이 좋다.

1/5


완벽한 코드 작성을 위한 클린 코드

나머지의 대다수 주석들은 나쁜 주석이며, 특히 나쁜 주석은 이야기를 주절거리거나 같은 이야기를 중복하는 경우, 오해의 여지가 있는 주석이나 의무적으로 다는 주석, 변경 이력을 기록하는 주석이나 있으나 마나 한 주석, 함수나 변수로 표현이 가능한데 불구하고 다는 주석, 위치를 표시하려고 행을 강조한 주석, 닫는 괄호 에 다는 주석, 작성자를 표시하는 것도 나쁜 주석이다. 코드를 삭제하지 않고 주석으로 처리하는 예도 SVN 과 같은 버전관리 시스템이 존재하는 현재에서는 의미가 없다. HTML 로 주석을 만드는 것은 어느 경우에도 가독성을 낮출 뿐이다. 지나치게 광의의 주석을 다는 것도 낭비이며, 관련 없는 정보(특히 역사나 이벤트)를 나열하는 것도 방해가 될 뿐이다. 주석과 주석이 설명하는 코드 사이의 관계는 명백해야 하며 짧은 함수에 긴 설명을 붙인 경우도 지양해야 한다. 비공개 코드에 Javadocs 를 다는 것도 낭비이다. 책을 읽으면서 느낀 것이지만, 우리가 사용하는 대다수의 주석들(특히 QP 지표를 맞추기 위해서 자동으로 생성된)은 나쁜 주석에 속한다.

형식 맞추기 포매팅은 코드의 가독성을 위해서 필요하다. 적절한 행의 길이를 유지하며 신문기사처럼 간략하고 핵심적인 내용을 위에서 아래방향으로 나열하려고 노력한다. 개념은 빈 행으로 분리하고 연관이 있는 행은 세로로도 가깝게 놓는다. 연관이 깊은 개념을 멀리 떨어뜨리면 코드를 읽기 어려워진다. 변수 선언은 변수를 사용하는 위치에 최대한 가까이 둔다. 함수는 짧게 만들어야 하므로 지역변수는 함수 맨 앞에 두도록 한다. 인스턴스 변수는 논란의 여지가 있지만 클래스 맨 처음에 선언하는 것이 좋다. (혹은 잘 알려진 위치에 모아둔다.) 두 개의 함수가 서로 종속관계라면 가급적 세로로 가까운 위치에 두도록 한다. 개념적으로 친화도가 높은 코드 도 세로로 가까이 둔다. 가급적 함수 호출 종속성을 아래방향으로 유지하는 것이 좋다. 가로 행을 일정하게 유지하는 것도 중요하며 가급적 120 행을 넘기지 않도록 한다. 가로에도 공백을 사용하 며 비슷한 개념을 밀집시키고 느슨한 개념을 분리시킨다. 변수 선언을 굳이 줄 맞출 필요는 없으며 변수선언 이 너무 많으면 클래스를 나눈다. 들여쓰기를 적절히 사용해야 하며 간단한 if 문에도 들여쓰기를 무시하지 않고 원칙을 지키도록 한다. 빈 while 문이나 for 문을 사용하지 않으며 행여 사용하더라도 들여쓰기 규칙을 지킨다. 무엇보다 팀에서 정한 규칙을 팀원 모두가 지키는 것이 중요하다. 우리 팀은 회사의 전사가이드에 맞추어 nhn formatter 를 사용하고 있으므로 이를 적절히 지키고 있다고 볼 수 있을 것이다.

객체와 자료 구조 자료는 추상클래스를 이용하여 나타내는 것이 좋다. 추상클래스를 만들 때 주의할 점은, 단순히 getter 와 setter 를 추가해서 만들지 말고 객체가 포함하는 자료를 잘 표현하는 방법을 고민해야 한다는 것이다. 자료 구조와 객체는 비대칭적일 수밖에 없으며, 객체지향에 얽매이지 말고 객체를 잘 나타내는 방법을 고민해야 한다. 디미터법칙은 모듈이 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙이다. 추상클래스를 사용함으로 서 이 법칙을 유지할 수 있는데, 체이닝 호출의 경우 이를 위배하여 기차충돌이라는 현상을 일으키기도 한 다. 디미터법칙은 객체에만 해당하며 자료구조인 경우엔 해당하지 않으므로 클래스를 명확히 드러내는 것이 중요하다. 자료 전달 객체는 공개변수만 있고 함수가 없는 클래스이다. 일반적인 형태로는 빈(bean)이 있다. 활성레코 드는 DTO 의 특수한 형태이며 save 나 find 같은 비즈니스 규칙을 담으므로 자료구조로 취급해야 한다.

2/5


완벽한 코드 작성을 위한 클린 코드

오류 처리 오류를 처리하는 좋은 방법은 오류코드를 돌려주는 것 보다는 예외를 사용하는 것이다. 코드를 구현할 때 try/catch/finally 문을 먼저 작성하고 코드가 예외를 던지는 부분을 캐치해 낸다면 이러한 오류처리를 보다 쉽 게 구현할 수 있다. 예외의 처리에 있어서는 확인된 예외를 처리하는 것 보다는 미확인 예외를 처리하는 편이 보다 효율적이다. 예외로 오류를 처리할 때 중요한 것은 예외를 던질 때 예외에 의미를 부여하여 던져야 한다는 것이다. 또한 예외 클래스는 호출자를 고려하여 정의되어야 한다. 물론 간단한 분기처리는 예외보다는 정상흐름의 로직 내 에서 처리되도록 하는 것이 더 좋다. 예외의 경우에 null 을 반환하는 것은 좋지 않은 습관이다. Null 을 함수에서 반환하게 되면 함수를 사용하는 쪽에서 이 null 에 대한 처리를 추가해야 하는데, null 이 가지는 의미를 모른 상태에서 이를 처리하는 것은 좋 지 않을뿐더러 매우 위험하다. 또한 인자로 null 을 전달하는 로직을 가지는 것도 매우 나쁘다. 코드의 가독성 도 중요하지만 코드의 안정성은 그에 못지않게 중요한 목적이다.

경계 외부의 코드를 사용할 때 외부의 인터페이스를 그대로 사용하는 것 보다는, 필요한 기능만 제한한 Wrapper 를 작성하여 사용하는 것이 좋다. 이렇게 하면 인터페이스의 경계를 살피고 익히는 것이 좀더 수월해진다. 협업을 진행할 때도 상대방이 코드를 모두 구현하기를 기다리기보다는 Fake API 를 작성하고 이를 사용하여 로직을 구현하는 것이 좋다. 이렇게 작성된 Adapter 는 변경에 강하고 테스트도 편리하다.

단위 테스트 TDD 는 세가지 규칙을 기반으로 한다. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다. 클린 테스트 코드를 유지하는 것도 중요하다. 테스트코드는 실제 코드 못지않게 중요하다. 테스트코드를 엉 망으로 작성하면 테스트 케이스를 유지하고 보수하는 비용이 늘어나서 곤란하다. 우리팀은 현재 유닛테스트 에 대해서 formatter 나 checkstyle 과 같은 기본적인 기준들을 적용하지 않고 있는데, 이 내용을 공유하고 토 론해보는 것이 좋을 것 같다. 테스트코드에서도 가장 중요한 것은 가독성이다. 앞에 정의된 코드에 적용되는 규칙들은 테스트 코드에도 동 일하게 적용된다. 테스트 하나는 하나의 assert 를 가져야 하고, 하나의 개념을 테스트해야 한다. 좋은 테스트는 다음 다섯가지 규칙을 지켜야 한다. 빠르게 독립적으로 반복 가능하게 자가 검증하는 적시에

3/5


완벽한 코드 작성을 위한 클린 코드

클래스 클래스 체계는 캡슐화되어 있어야 한다. 물론 테스트를 위해서 protected 로 함수를 풀어주는 것이 필요할 수 있지만 가급적 비공개 상태를 유지하려고 노력한다. 클래스는 작아야 하며 하나의 클래스는 가급적 작은 책임을 지어야 한다. 클래스의 이름은 클래스의 책임을 기술하기에 충분해야 한다. 클래스는 인스턴스 변수를 너무 많이 가지면 안된다. 인스턴스 변수가 많은 경우 클래스를 분리하는 것을 검 토해야 한다. 함수의 응집도를 유지하면 클래스의 응집도도 유지되어 작은 클래스 여럿으로 가독성 좋은 코 드를 산출할 수 있다. 클래스는 변경하기 쉬워야 하며 변경으로부터 격리하도록 인터페이스와 추상클래스를 사용하여 의존도를 낮 춘다.

시스템 시스템의 제작과 시스템의 사용은 분리되어야 한다. 그 방법으로는 Main 분리, 팩토리, Dependency Injection 등이 있다. 자바 프록시나 자바 AOP 프레임워크, AspectJ 등을 사용하는 것은 손쉬우면서 훌륭한 시스템의 분리가 될 수 있다. 무엇보다 의사 결정을 최적화하고 모듈과 관심사를 명확하게 나누는 것이 깨끗한 시스템을 유지하 면서 사용하는 왕도이다.

창발성 켄트백은 소프트웨어의 설계품질을 높일 수 있는 네가지 규칙을 제시하였다. 모든 테스트를 실행한다. 중복을 없앤다. 프로그래머 의도를 표현한다. 클래스와 메소드 수를 최소로 줄인다. 이 책에서는 여기에 한가지 절차를 추가한다. 점진적인 리팩토링(코드와 클래스 정리) 이 절차를 모두 따르면서 현업에 임하기는 어렵겠지만, 원칙을 정하고 앞에서부터 가능한 곳 까지라도 따라 간다면 우리의 코드는 보다 나은 설계를 가질 수 있을 것이다.

동시성 동시성은 결합을 없애는 전략이며, 이를 통해 프로그램의 구조와 효율이 극적으로 나아질 수 있다. 하지만 동시성은 정확한 구현을 위해 각별한 주의와 노력이 필요하다. 동시성은 항상 성능을 높여주는 것이 아니며, 설계의 변경을 유발하기도 하며, 성능의 부하를 유발하기도 하 므로 꼭 필요한 경우에만 구현을 하는 것이 좋다. 동시성 코드가 유발하는 문제에서 시스템을 방어하기 위해 아래의 원칙과 기술들이 필요하다. 단일 책임 원칙 자료 범위의 제한 자료 사본의 사용

4/5


완벽한 코드 작성을 위한 클린 코드

스레드의 독립적인 구현 자바를 이용해 스레드를 구현한다면 라이브러리를 이해하는 것이 도움이 될 것이며, 실행 모델을 이해하는 것도 필요하다. 동기화 하는 메소드 사이에 의존성을 이해해야 하며 동기화하는 부분은 최소화시켜야 한다. 스레드코드도 테스트가 필요한데, 이를 테스트하기 위해서는 고려해야 할 점이 매우 많다. 순차코드부터 시 작해서 다중스레드를 다양한 환경과 플랫폼에서 실행해보기까지 다양한 테스트방법이 필요하다.

점진적인 개선 하나의 예제를 차례대로 리팩토링 하는 예제를 제공한다. 실습차원에서 읽어볼만하다.

JUnit 들여다보기 테스트의 도구로서 JUnit 을 잘 사용하는 방법을 예제와 함께 제시한다.

SerialDate 리팩토링 실제 JCommon 라이브러리의 코드를 책에 나온 여러가지 원칙들에 비추어 리팩토링을 실습한다.

5/5


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.