devFancy BE Developer

[좋은 코드, 나쁜 코드] Part1. 이론 (코드 품질, 추상화 계층)

2024-09-08
devFancy

책의 내용 중 자극히 개인적으로 중요한, 기억하고 싶은 부분들을 메모해두자. 자세한 내용은 책을 참고하자.

  • 고품질의 코드는 개발자의 역량과 리더십의 지원, 두 가지가 다 있어야 가능한 성과물이기 때문에, 개발 조직의 리더가 개발과 테스트를 고려해서 충분한 시간을 보장해주어야 한다.

Chapter1. Code quality

  • 고품질의 코드는 신뢰할 수 있고, 유지보수가 쉬우며, 요구 사항을 충족하는 소프트웨어가 될 가능성을 최대한으로 높여준다.

실제 서비스되는 환경에서 실행되는 소프트웨어가 되기까지의 과정

  1. 개발자가 코드베이스(Git과 같은 형상 관리 시스템)의 로컬 복사본을 가지고 작업하면서 코드를 변경한다.
  2. 작업이 끝나면 코드 검토를 위해 변경된 코드를 가지고 병합 요청을 한다.
  3. 다른 개발자가 코드를 검토하고 변경을 제안할 수 있다.
  4. 작성자와 검토자가 모두 동의하면 코드가 코드베이스에 병합된다.
  5. 배포는 코드베이스를 가지고 주기적으로 일어나지만, 얼마나 자주 배포되는지는 조직과 팀마다 다를 수 있다.
  6. 테스트에 실패되거나 코드가 컴파일되지 않으면 코드베이스에 병합되는 것을 막거나 코드가 배포되는 것을 막는다.

코드를 작성할 때 다음과 같은 네 가지 상위 수준의 목표를 달성해야 한다.

  1. 작동해야 한다.
  2. 작동을 멈춰서는 안된다.
  3. 변화하는 요구 사항에 적응해야 한다.
  4. 이미 존재하는 기능을 또다시 구현해서는 안된다.

코드 품질여섯 가지 핵심 요소는 다음과 같다.

  1. 코드는 읽기 쉬워야 한다.
  2. 코드는 예측 가능해야 한다.
  3. 코드를 오용하기 어렵게 만들라.
  4. 코드를 모듈화해라.
  5. 코드를 재사용 가능하고 일반화할 수 있게 작성하라.
  6. 테스트가 용이한 코드를 작성하고, 제대로 테스트하라.

Chapter2. Layers of abstraction

Method

  • 단일 함수 내에서 너무 많은 작업을 수행하면 코드를 이해하기 어렵게 만드는 문제가 발생할 수 있다.

  • 그러한 문제가 발생한다면 함수를 작게 만들고 수행하는 작업을 명확하게 해서 코드의 가독성과 재사용성을 높힌다.

Class

줄 수(number of lines): ‘한 클래스는 코드 300 줄을 넘기지 않아야 한다’와 같은 가이드라인을 접하는 경우가 있는데, 이는 경고의 역할만 할 뿐, 본인이 속한 팀의 문화에 따라 다를 수 있다.

응집력(cohesion): 한 클래스 내의 모든 요소들이 얼마나 잘 속해 있는지를 보여주는 척도로, 좋은 클래스는 응집력이 매우 강하다. 응집력에는 여러 방식이 있다.

  • 예를 들어, 커피 한 잔을 만드는 과정(원두를 갈아서 커피를 추출하는)과 같은 순차적 응집력이 있고, 케이크를 만들기 위해 필요한 장비를 모이는 과정과 같은 기능적 응집력이 있다.

관심사의 분리(seperation of concerns): 시스템이 각각 별개의 문제를 다루는 개별 구성 요소로 분리되어야 한다고 주장하는 설계 원칙이다.

  • 코드를 적절한 크기의 클래스로 쪼개지 않으면 너무 많은 개념을 한꺼번에 다루고,

  • 그로 인해 가독성이 떨어지며 모듈화가 덜 이루어지고,

  • 재사용과 일반화가 어렵고, 테스트하기도 어려워진다.

Interface

  • 하나의 추상화 계층에 대해 두 가지 이상의 다른 방식으로 구현을 하거나 향후 다르게 구현할 것으로 예상되는 경우 인터페이스를 정의하는 것이 좋다.

  • 이를 통해 코드를 더욱 모듈화할 수 있고 재설정도 훨씬 쉽게 할 수 있다.

모든 것을 위한 인터페이스?

  • 주어진 추상화 계층에 대해 하나의 구현만 존재하는 경우에도 인터페이스를 통해 추상화 계층을 표현해야 하는지는 팀에서 결정할 문제다.

    • 많은 소프트웨어 공학 철학에서는 인터페이스 사용을 권장하지만, 나는 조금 다른 생각을 가지고 있다.

    • 나의 경우, 두 가지 이상의 구현이 있거나 앞으로 다른 구현이 필요할 가능성이 있는 경우가 아니라면, 단 하나의 구현 클래스만 있다면 굳이 인터페이스를 만들 필요는 없다고 본다.

    • 인터페이스와 구현 클래스가 1:1로 대응될 때는 서비스가 확장될수록 관리해야 할 파일과 코드가 불필요하게 많아지기 때문이다.

    • 또한, 다른 개발자가 코드를 이해하려고 할 때, 인터페이스 -> 구현 클래스(하위) 로 이동하면서 찾아야 한다.

    • 그래서 나는 일반적으로 먼저 구현 클래스로 시작하고, 인터페이스가 필요한 시점에 도입하여 설계를 보완해 나가는 방식을 선호한다.

  • 일반적으로 클래스를 작성하거나 수정해야 할 때, 인터페이스를 붙이는 것이 어렵지 않도록 코드를 작성해야 한다.

Reference


Comments

Index