Code Smell 에 관하여

code-smells-130917082754-phpapp01-thumbnail-4

높은 퀄러티의 코드를 유지하는 작업은 프로젝트가 중반 이후로 갈 수록 뼈저리게 중요함을 많이 느낀다. 막판 마감일이 다가오면 프로젝트의 버그를 잡거나 기능을 수정하는 데 온 시간들을 빼앗겨서 좋은 Code Quality를 유지하는 것이 더 어렵다. QA 혹은 QC를 진행한 후에는 조금 한숨을 돌린다고 치더라도, 그 때 Refactoring을 진행하는 것은 치카치카를 한 다음 밥을 먹는 것과 같을 것이다.
Code Smell 이란 개발자들 사이에서 쓰는 단어다. Wikipedia에 따르면 “any symptom in the source code of a program that possibly indicates a deeper problem”, 즉 더 큰 문제들이 있음을 가리키고 있을만한, 소스 코드 상의 증상들이다. 이건 버그와는 다른데, 버그는 딱 집어서 기능이 제대로 동작하지 않는 문제 이지만 Code Smell은 정상적인 기능 수행과는 무관하게 존재한다. Code Smell을 디자인 패턴과 밀접한 관련이 있는데, 잘못 설계된 디자인 패턴이나 전체적인 프로그램의 디자인 패턴을 해치는 특정한 구조들이라고 볼 수도 있다. Code Smell은 코드의 디자인적인 약점이며, 그로인해 개발을 느리게 만들고, 버그가 생기기 쉽게 한다.

따라서, Code Smell은 Refectoring과 밀접하게 연관되어 있다. Code Smell을 체크하여 Refectoring의 타임을 결정할 수 있고 Refectoring은 Code Smell들을 없애는 방향으로 작업하게 된다.

이 Code Smell을 잘 맡을 수 있는 개발자가 좋은 개발자임은 당연한 것이다. 또한, Code Smell의 개념을 잘 알고 있어서, 본인이 개발한 혹은 개발하고 있는 코드에서 Code Smell을 느낄 수 있는 개발자들이 더 좋은 코드를 만들어내는 도전을 받게 되는 것도 자연스럽다.

Code Smell의 예는 매우 다양한다. SO cofounder인 codinghorrorCode Smell에 대해서 쓴 글에서 그는 Code Smell의 예를 이렇게 든다.

클래스 내부적으로는

  •  Comment는 항상 What보다는 Why에 대해 적도록 노력해야한다. 또한, 기계를 향해 적는것이 아니라 사람을 향해 적는 것임을 잊지 말아야 하고, 코멘트가 필요 없는 구조와 Naming이 제일 좋으므로 꼭 필요한 건지 체크할 필요가 있다.
  •  짧은 메쏘드 이름이 읽기에도 이해하기에도 좋다. 너무 긴 메쏘드는 작은 메쏘드들로 분리하라.
  • 메쏘드의 파라미터들이 많으면 많을 수록 복잡도가 증가한다. 파라미터의 갯수를 제한하고, Object를 통해 넘겨라.
  • 소프트웨어 개발의 맹독은 중복되는 코드들이다. 코드 내에 가능한한 중복된 코드를 제거하고 가능한한 전체 소프트웨어를 중복 코드 없이 유일한 코드들로 채우도록 노력해야 한다.
  • 너무 거대해지는 Conditional logic을 멀리하라. 시간이 지남에 따라 조건 블락들이 너무 커지고 비대해질 경우 State나 Decorator 등의 접근을 통해 OOP 구조로 바꾸는 것을 고려하라.
  • 거의 같은데 약갘씩 다른 코트들도 주효한 Code Smell이다. Generic이나 Interpreter로 대체하여 중복을 없내는 것을 고려하라.
  • 너무 비대한 클래스는 거대한 메쏘드와 같은 효과를 불러 일으킨다. 코드를 읽어 내기도, 이해하기도, 수정하기도 힘들다. 클래스 하나가 너무 많은 책임을 가지고 있는지 체크하라. 그렇다면 더 작은 클래스들로 분리시켜라.
  • 메쏘드 이름에 파라미터 타입을 넣지 마라. 타입은 언제든지 바뀔 수 있다.
  • 메쏘드 이름을 가지고 다른 개발자에게 무엇을 하는 메쏘드인지 설명하기 어렵다면 Rename을 하거나 재작성하라.
  • 표준 용어들을 써서 Naming하라. 가령 Open()이라는 메쏘드가 있으면 Close()가 존재할 것이다.
  • 사용하지 않는 코드는 무자비하게 지워버려라. 코드는 이미 소스 컨트롤 시스템에 커밋되어 있다.
  • 오늘 필요한 코드를 짜라. 대부분의 미래에 일어날 일을 대비하는 코드들은 쓸모없게 되는 경우가 허다하다.
  • 하나의 동작을 하는 코드는 전체 소스 코드 내에서 하나의 코드로만 존재해야 한다. 특정 동작에 대해서 약간 이상한 방법들이 다양하게 존재한다면 이 또한 중복 코드와 다를 것이 없다.
  • 파라미터로 오브젝트를 넘긴다면 일부를 사용하기보다 가능한 전부를 사용하는 것이 좋다. 필요 없는 필드를 없애라.

 
클래스와 클래스 간에서는

  • 두클래스가 내부적으로는 비슷하고 바깥에서 보기에는 달라보인다면 공통 Interface를 만들어서 공유하게 수정할 수 있다.
  • 수많은 기본 데이터 타입을 나열하여 클래스를 대체하지 말자. 데이터들이 충분히 복잡하고 많다면 그것들을 표현하는 Struct나 Class를 만들자.
  • 항상 두 데이터가 같이 따라다닌다면 Structure나 Class로 묶어주라.
  • 상속을 해놓고 상위 클래스의 메쏘드를 하나도 쓰지 않는다면 해당 상속은 필요 없지 않을까.
  • 클래스에서 외부로 드러난 부분인 Public을 공격적으로 줄여라. 가능한 public을 줄이는 것이 좋다.
  • 다른 클래스의 메쏘드를 많이 사용해야하는 메쏘드라면 그 다른 클래스로 옮기는 것이 좋지 않을까.
  • 클래스가 너무 많이 있는 것도 복잡도를 증가한다. 클래스를 만드는 것에는 적당한 내용과 무게감이 존재해야 한다.
  • 모든 작업을 Delegating 시키는 클래스는 존재의 이유가 불분명하다. 이러한 중간 클래스 혹은 Wrapper들을 없애라.
  • 시간이 가면 갈수록 해당 클래스의 주요 목적과는 크게 무관한 부분의 코드가 커지고 있다면 그 부분을 따로 떼어 내는 것을 고려하라.
  • 한개의 클래스의 변경이 다른 여러 클래스의 추가 변경으로 Chainning 형태로 이뤄져야할 경우 Refectoring을 하여 하나의 클래스 수정으로 가능하도록 변경하라.
  • 특정 기능이 빠진 라이브러리 자체를 바꿀 수 없다면 원하는 메쏘드만 따로 고립시키는 것을 고민하라.
  • 하나의 유의미한 작업을 하기 위해서 대여섯개의 클래스를 이용해야 한다면 너무 벌려 놓은 것이 아닌가 고민하고 디자인적으로 더 간단하게 만드는 법을 고민하라.
  • Code Smell을 잘 맡을 수 없는 개발자라면 본인이 무엇을 잘못 짜고 있는지 명확하게 알고 있지 못할 여지가 많다. 해당 동작의 기능만 구현된다면 아무런 문제를 제기하지 않는 개발 조직이 대부분이기 때문이다. 그리고 Bug의 경우에는 딱 집어서 무엇이 잘못되었다 라고 이야기할 수 있지만, Code Smell은 그 특성상 명백한 잘잘못을 지적하기 어려운 경우가 많다.

이런 것을 굳이 비유를 들자면 이렇다.
좋은 시민이란 그 국가에서 정해 놓은 법을 어기지 않는 시민이다. 이건 버그를 양산하지 않는 개발자가 좋은 개발자라는 말과 동일하다.
그러나, 정말 좋은 시민이란 준법은 기본적으로 지키되, 그 국가 법의 근본 정신과 그 법이 추구하는 궁극적인 인간상과 가장 닮아 있는 시민일 것이다.

단순히 버그가 없다고 해서 좋은 개발자라고 한다면 좋은 개발자는 코딩을 가장 적게하거나 가장 쉬운 부분을 코딩하는 개발자가 가장 좋은 개발자일 가능성이 높아진다. 그러나 좋은 개발자의 조건에 Code Smell을 일으키는 코드를 거의 만들지 않는 개발자라고 하면 그 기준은 한단계 더 높아지게 되고 정교하게 된다.

Code Smell에 대한 높은 이해는 높은 Software Quality와 직접적인 연관이 있다. 그러므로 좋은 개발자는 코드의 냄새를 잘 맡을 수 있어야 한다.

wake-up-and-smell-the-coffee