[CLEAN CODE]

2015. 8. 11. 11:47Etc/독서

사소한 곳에서 발휘되는 정직의 중요성

"사소한 곳에서 발휘하는 정직은 사소하지 않다" - 덴마크 속담
"신은 세세함에 깃들어 있다" - 루트비히 미스 반 데어 로에

이 두 문장은 책의 서문에 적힌 말입니다. 결국, 사소한 것이 중요하다는 것을 강조합니다. 이 글에서는 이러한 원칙이 어떻게 우리가 일하는 방식에 적용될 수 있는지, 특히 소프트웨어 개발과 Lean 원칙에서 어떻게 적용되는지 살펴보겠습니다.

Lean의 원칙: 5S

Lean의 5S 원칙은 작업 환경을 정리하고 효율성을 극대화하는 데 초점을 맞춥니다. 이 원칙들은 소프트웨어 개발에서도 적용될 수 있으며, 다음과 같습니다:

1. 정리 (Sort)

무엇이 어디에 있는지 알아야 합니다. 이를 위해서는 적절한 명명법과 정리를 통해 각 항목이 어디에 속하는지 명확하게 하는 것이 중요합니다.

2. 정돈 (Set in Order)

모든 물건에는 제자리가 있습니다. 소프트웨어 코드에서도 마찬가지로, 변수, 함수, 클래스가 어디에 위치해야 하는지 예측 가능하게 배치하는 것이 중요합니다.

3. 청소 (Shine)

작업 공간을 깨끗하게 유지하는 것은 중요합니다. 소프트웨어에서는 불필요한 주석, 과거의 코드 이력, 사용하지 않는 변수를 제거하여 코드를 정리하는 것을 의미합니다.

4. 청결 (Standardize)

팀 내에서 일관된 구현 스타일과 기법을 사용하여 작업 공간을 청결하게 유지합니다. 표준화는 작업의 효율성과 품질을 높이는 데 도움이 됩니다.

5. 생활화 (Sustain)

관례를 따르고, 자주 돌아보며, 기꺼이 변경하는 규율을 뜻합니다. 개발자는 코드를 지속적으로 개선하고 최적화하는 습관을 들여야 합니다.

좋은 이름을 사용하라

코드의 명확성을 높이는 가장 좋은 방법 중 하나는 의미 있는 이름을 사용하는 것입니다. 다음은 그 예입니다:

개선 전

public List<int[]> getThem() {
    List<int[]> list1 = new ArrayList<int[]>();
    for (int[] x : theList)
        if (x[0] == 4)
            list1.add(x);
    return list1;
}

개선 후

public List<Cell> getFlaggedCells() {
    List<Cell> flaggedCells = new ArrayList<Cell>();
    for (Cell cell : gameBoard)
        if (cell.isFlagged())
            flaggedCells.add(cell);
    return flaggedCells;
}

이제 코드의 목적이 훨씬 더 명확해졌습니다. 코드를 읽는 사람은 getFlaggedCells() 메서드가 무엇을 하는지 바로 이해할 수 있습니다.

주석

주석을 다는 것은 때로 유용하지만, 코드를 통해 의도를 충분히 전달할 수 있는지 항상 고려해야 합니다. 다음 질문을 스스로에게 던져보세요:

  • 코드만으로 내가 말하고자 하는 바를 온전히 나타낼 수 없는가?
  • 주석이 Java Doc과 같은 불필요한 문서를 만들기 위한 행위는 아닌가?

코드 자체가 주석 없이도 충분히 명확해야 합니다.

단위 테스트의 중요성

단위 테스트를 작성하는 것은 소프트웨어 품질을 높이는 중요한 방법입니다. 다음 세 가지 법칙을 기억하세요:

  1. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
  2. 컴파일은 성공하지만 실행은 실패하는 정도로만 단위 테스트를 작성한다.
  3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

테스트는 각 기능이 예상대로 작동하는지 확인하는 중요한 수단이며, 가능한 한 명확한 assert를 사용해 테스트당 하나의 주장을 포함하는 것이 좋습니다.

클래스와 설계 원칙

클래스 이름과 책임

클래스의 이름은 그 책임을 명확히 표현해야 합니다. 예를 들어, 만약 UserManager라는 클래스가 있다고 합시다. 이 클래스의 이름은 사용자 관련 기능을 관리할 것이라는 기대를 줍니다. 하지만 이 클래스가 사용자뿐만 아니라 결제 정보까지 관리한다면, 이름이 책임을 제대로 반영하지 못하고 있습니다. 이 경우, 결제 정보를 관리하는 부분을 PaymentManager라는 별도의 클래스로 분리하여 각 클래스가 명확한 책임을 가지도록 해야 합니다.

단일 책임 원칙 (SRP)

단일 책임 원칙에 따르면, 클래스나 모듈은 변경할 이유가 하나뿐이어야 합니다. 예를 들어, ReportGenerator라는 클래스가 보고서를 생성하고, 데이터를 저장하며, 이메일로 발송까지 한다고 가정해 봅시다. 이 클래스는 여러 가지 책임을 가지고 있어, 변경할 이유가 많아질 수 있습니다. 이 경우, 각 책임을 ReportDataFetcher, ReportSaver, ReportMailer와 같은 클래스로 분리하여 각각의 책임을 명확히 하는 것이 좋습니다.

OCP (Open-Closed Principle)

클래스는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 합니다. 예를 들어, Shape라는 클래스가 있다고 가정합시다. 이 클래스는 draw() 메서드를 가지고 있습니다. 이 클래스가 Circle, Square 등의 서브클래스를 가지고 있다면, 우리는 새로운 도형을 추가하기 위해 기존 코드를 수정할 필요가 없습니다. 대신, Shape 클래스를 상속받아 새로운 도형 클래스를 추가하면 됩니다. 이렇게 하면 기존 코드를 수정하지 않고도 새로운 기능을 추가할 수 있습니다.

abstract class Shape {
    abstract void draw();
}

class Circle extends Shape {
    void draw() {
        System.out.println("Drawing Circle");
    }
}

class Square extends Shape {
    void draw() {
        System.out.println("Drawing Square");
    }
}

class Triangle extends Shape {
    void draw() {
        System.out.println("Drawing Triangle");
    }
}

위 예제에서 새로운 도형을 추가하고 싶다면, 단지 Shape 클래스를 상속받아 새로운 클래스를 만들기만 하면 됩니다. 기존의 Circle이나 Square 클래스를 수정할 필요가 없으므로 OCP 원칙을 따르게 됩니다.

단순한 설계의 4단계

  1. 모든 테스트를 실행한다.

    • 테스트 케이스를 만들고 지속적으로 실행하면, 자연스럽게 낮은 결합도와 높은 응집력을 갖는 코드가 탄생합니다.
  2. 중복을 없앤다.

    • 중복은 추가 작업, 위험, 불필요한 복잡도를 초래합니다. 코드를 단순화하여 중복을 제거하세요.
  3. 프로그래머 의도를 표현한다.

    • 좋은 이름을 선택하고, 함수와 클래스의 크기를 줄이며, 꼼꼼한 테스트 케이스를 작성하세요. 이는 모두 의도를 명확히 표현하는 데 기여합니다.
  4. 클래스와 메서드 수를 최소화한다.

    • 시스템의 크기도 작게 유지해야 합니다. 그러나 클래스와 메서드를 무조건적으로 줄이는 것은 옳지 않으며, 시스템의 복잡도를 고려해야 합니다.
반응형

'Etc > 독서' 카테고리의 다른 글

[니체] 지성에 대하여  (3) 2015.08.13
[니체] 사랑에 대하여  (2) 2015.08.11
[니체] 인간에 대하여  (0) 2015.08.10
[니체] 세상에 대하여  (0) 2015.08.09
[니체] 친구에 대하여  (0) 2015.08.09