인프런 워밍업 스터디 클럽 2기 - 백엔드(클린코드, 테스트코드) 1주차 발자국

인프런 워밍업 스터디 클럽 2기 - 백엔드(클린코드, 테스트코드) 1주차 발자국

클린 코드를 추구하는 이유는?

개발을 시작한지 좀 된 사람이라면 로버트 마틴의 ‘클린 코드’라는 책을 읽진 않아도 들어 봤을 것이다.

클린 코드의 부제를 보면 '애자일 소프트웨어 장인 정신'인데 부제 그대로 장인 정신에 관한 내용이다.

 

image

여기서 거추장스럽게 애자일이 뭔지 이해할 필요 없이 클린 코드의 목적을 말하자면 바로 '가독성'을 추구하는 것이다.

코드는 사람이 작성하고, 읽기 때문에 클린 코드를 추구해야하는 근원적 이유는 눈에 잘 들어오고 쉽게 이해가능 해야하는 것이다.

하지만 이를 왜 지켜야할까? 그 이유를 코드를 통해 체득해 나가는 것이 이 강의의 핵심 주제이다.

 

추상

image

이를 체득하기 위해 가장 중요한 키워드는 바로 '추상'인데 강의 내내 보게 될 키워드이며 그만큼 중요하다.

추상의 사전적 의미 다음과 같다.

여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용.

사물이나 개념에서 특성이나 속성을 추출한다고 나와있다. 개발이 아니더라도 일상 생활에서 '추상적 사고'는 이미 뿌리깊이 자리 잡고 있다.

예를 들어 '날씨'는 대기 중에서 일어나는 모든 기상 현상을 포괄하는 추상적 개념으로 온도, 습도, 강수량, 기압 등의 요소가 결합하여 특정한 기후 조건을 형성하는 것을 의미한다.

이를 구체적으로 바라본다면 “오늘 아침 기온은 20°C이고, 바람은 시속 10km로 불고 있으며, 30%의 습도를 동반한 맑은 하늘”이라는 식으로 각 요소를 수치로 구체화할 수 있다. (미션-Day2)

정리하면 '구체'라는 것은 여러가지 개별 사건에 하나하나 대응하는 것으로, '추상'은 공통적인 특징을 하나로 정리해 일반화한 것이다.

이처럼 적절한 추상화는 일상 생활 뿐만 아니라 컴퓨터 과학에서 다루는 복잡한 데이터를 읽기 쉽게 도와준다.

클린 코드는 이를 다음과 같이 설명한다.

우리가 함수를 만드는 이유는 큰 개념을(다시 말해, 함수 이름을) 다음 추상화 수준에서 여러 단계로 수행하기 위해서가 아니던가. - 클린코드, 45page

사실 이미 클린 코드에 나온 내용을 강박처럼 지키고 있었기 때문에, 섹션 2인 추상과 섹션 3 논리, 사고의 흐름은 어려움없이 넘길 수 있었다.

때문에 Day4 미션인 읽기 좋은 코드로 리팩토링하기도 어려움없이 코드를 작성할 수 있었다.

 

// 리팩토링 전

public boolean validateOrder(Order order) {

    if (order.getItems().size() == 0) {

        log.info("주문 항목이 없습니다.");

        return false;

    } else {

        if (order.getTotalPrice() > 0) {

            if (!order.hasCustomerInfo()) {

                log.info("사용자 정보가 없습니다.");

                return false;

            } else {

                return true;

            }

        } else if (!(order.getTotalPrice() > 0)) {

            log.info("올바르지 않은 총 가격입니다.");

            return false;

        }

    }

    return true;

}

// 리팩토링 후

public boolean validateOrder(Order order) {

    try {

        validateItems(order);

        validateTotalPrice(order);

        validateCustomerInfo(order);

    } catch (InvalidOrderException e) {

        log.info(e.getMessage());

        return false;

    }

    return true;

}

private void validateItems(Order order) throws InvalidOrderException {

    if (order.hasNoItems()) {

        throw new InvalidOrderException("주문 항목이 없습니다.");

    }

}

private void validateTotalPrice(Order order) throws InvalidOrderException {

    if (order.isPricePositive()) {

        throw new InvalidOrderException("올바르지 않은 총 가격입니다.");

    }

}

private void validateCustomerInfo(Order order) throws InvalidOrderException {

    if (order.hasNoCustomerInfo()) {

        throw new InvalidOrderException("사용자 정보가 없습니다.");

    }

}

// 커스텀 예외 InvalidOrderException

class InvalidOrderException extends Exception {

    public InvalidOrderException(String message) {

        super(message);

    }

}

 

조기 Return, 부정어로 인한 읽는데 중간에 한번 막히게 되는 코드 개선, 예외 처리 등 한 눈에 코드를 알아볼 수 있게 끔 리팩토링 해봤다. 이 부분은 코드가 더 복잡해진다면 어떻게 하면 좋을지 숙련이 필요하다고 생각하게 된 부분이었다.

전체적으로 규칙뿐만 아니라 추상화라는 거대한 개념을 이해하기에 아주 좋은 파트였다.


객체 지향 적용하기

객체 지향 패러다임, 특히나 객체 지향 5원칙인 SOLID는 기계처럼 법칙을 외운다고 해서 절대 이해할 수 없기 때문에 이해한 것을 바탕으로 코드를 재구성해봤다. - 미션 Day4

코드를 쓰면서 계속 염두에 뒀던 것은 비즈니스 요구 사항이 항상 변경될 것을 인식하고 있었다는 것이다. 나중에 요구 사항이 바뀌더라도 작성했던 코드의 틀을 유지하면서 변경하려면 어떻게 해야할까?라는 고민을 자연스럽게 하게되었다.

그에 대한 키워드는? 역시나 '추상화'였다.

미션에서 작성했던 코드와 글의 마무리가 만족스럽지 않아, 다시 SOLID 원칙을 다시 짧게 정리해본다면

> SRP: 모듈(클래스 or 클래스의 집합)이 변경되는 이유는 한 가지여야 함 -> 책임에 따라 코드를 분리하게되면 새로운 비즈니스 요구 사항이 생겼을 때 변화가 발생하더라도 수정할 대상이 명확해진다.

> OCP: 확장에 대해 열려있고 수정에 대해 닫혀있다는 것 -> 인터페이스에 의존하도록 추상화함으로써 기존 코드를 수정하지 않은 채 수정 및 확장이 가능

> LSP: 하위 타입은 상위 타입을 대체할 수 있다는 것 -> upcasting된 상태에서 부모의 메서드를 사용해도 동작이 의도대로 흘러가야 함

> ISP: 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 함 -> 목적과 용도에 적합한 인터페이스 만을 제공하는 것이 목표

> DIP: 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 되며, 저수준 모듈이 고수준 모듈에 의존해야 함 -> 추상 클래스나 인터페이스를 참조하여 거의 변화가 없는 것에 의존시켜 각 클래스간의 결합도를 낮추는 것이 목적

이렇게 정의할 수 있지 않을까 싶다.

이제 컴포지션 사용, VO 객체, 일급 컬렉션과 같은 개념들은 이어지는 미션에서 직접 적용하고 글을 다시 정리해 볼 생각이다.


맺음

강의를 보며 단순히 ‘깨끗한 코드’라는 차원을 넘어서, 내가 작성한 코드를 나중에 동료들이 쉽게 이해할 수 있을까에 대한 고민을 계속 하게되는 시간을 보냈다.

그러던 중, 인프콘에서 발표를 마치고 토비님이 블로그에 남기신 말이 있는데

클린 코드는 그저 이름 잘 짓고, 함수 작게 만들고, 주석 달지말고, 스타일 통일하고, 디미터 법칙 지키자라는 수준의 피상적이고 기계적인 주장을 하는 캐치프레이즈가 아니다. 대부분 앞부분만 보고 6장 넘어서 나오는 내용에 대해서는 얘기도 하지 않는, 책에 나오는 저자가 꽤나 고민하면서 수집하고 애써 만진 코드는 술렁술렁 넘기고 말 책이 아니란 말이다.

읽으면서 굉장히 따끔한 문장이었다.

image

클린 코드는 단순히 형식적인 규칙을 따르는 것이 아니라, 코드를 읽는 사람, 즉 나와 동료 개발자들 간의 소통을 원활하게 하고, 더 나아가 유지보수성과 확장성을 높이는 데 중점을 둬야한다는 것이다.

더 이상 코드를 ‘깨끗하게’만 작성하는 것이 목표가 아니라, 의도를 명확히 전달하고, 미래의 변화에 유연하게 대응할 수 있는 코드를 작성하는 것이 중요하다는 점을 깨달았다.

앞으로도 클린 코드 원칙을 단순한 규칙 그 이상으로 생각하며, 더 나은 개발자, 더 나은 동료가 되기 위해 지속적으로 고민하고 실천하도록 노력해야겠다.


출처

- Clean Code

- 우빈님의 강의

- 애자일 소프트웨어 개발 선언

- 토비님의 블로그

 

댓글을 작성해보세요.

채널톡 아이콘