[클린 코드] 6. 코드 인덴트(indent) 단축

코드 인덴트(indent, 들여쓰기)를 줄이는 것은 코드의 가독성을 높이는 중요한 방법 중 하나이다. 본 포스팅에서는 가드 조항(Guard Clause)과 다형성(Polymorphism)을 사용하여 코드를 클린하게 작성하는 방법을 알아볼 것이다.

가드 조항(Guard Clause)

일반적으로 if-else문이 중첩(nestsed)될수록 코드는 복잡해지고 보기 지저분해진다. 복잡한 if-else 구조를 줄이고, Fail이 되는 로직을 코드 상단에 배치하여 가독성을 높이는 기법이다.

1
2
3
4
5
6
7
8
9
10
# BAD
if :
	...
	if :
		...
		if :
			...
			while :
			...
...

as-is

1
2
3
4
5
6
7
8
9
10
11
12
13
def say_hi_to_spring_user(developer):
    if developer.is_front_end:
        raise Exception("프론트 엔지니어입니다")
    elif developer.is_back_end:
        if not developer.use_java:
            raise Exception("자바를 사용하지 않습니다")
        else:
            if developer.use_spring:
                print("안녕하세요!")
            else:
                raise Exception("자바의 다른 프레임워크를 사용합니다")
    else:    
        raise Exception("who are you?")

이 코드는 중첩된 if-else 구문을 사용하여 개발자가 Spring을 사용하는 Java 백엔드 개발자인지 확인한다. 이 구조는 코드가 복잡하게 보이게 하고 가독성이 떨어지게 만든다.

to-be

1
2
3
4
5
6
7
8
9
10
11
12
# Fail이 되는 부분을 상위로 올리면 코드를 더 쉽게 읽을 수 있다.
def say_hi_to_spring_user(developer):
    if not developer.is_backend:
        raise Exception("백엔드 엔지니어가 아닙니다")
    
    if not developer.use_java:
        raise Exception("자바를 사용하지 않습니다")

    if not developer.use_spring:
        raise Exception("스프링을 사용하지 않습니다")
    
    print("안녕하세요!")

이 코드는 Guard Clause를 사용하여 중첩된 구문을 줄이고, 코드를 더 쉽게 읽을 수 있게 개선한다.

  1. 먼저, 백엔드 개발자가 아닌 경우에 대해 예외를 발생시킨다.
  2. 다음으로, Java를 사용하지 않는 경우에 대해 예외를 발생시킨다.
  3. 마지막으로, Spring을 사용하지 않는 경우에 대해 예외를 발생시킨다.

이 모든 조건들이 충족되지 않으면(즉, 개발자가 Java 백엔드 개발자이고 Spring을 사용한다면), 개발자에게 인사를 출력한다. 이렇게 하면 코드가 더 간결하고 가독성이 향상된다.

이 예에서 Guard Clause를 사용하면 중첩된 if-else 구문을 피할 수 있으며, 각 조건에 대해 명확한 처리가 가능해진다. 이로 인해 코드의 가독성과 유지 보수성이 향상된다.

다형성(Polymorphism)

객체 지향의 꽃이라고 불리는 다형성을 활용하여 if-condition을 줄일 수 있다. 객체 지향 프로그래밍에서 다형성은 클래스 간의 관계를 통해 동일한 인터페이스에 대해 다양한 구현을 제공한다.

as-is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Developer:
    def coding(self):
        print("코딩을 합니다")

class Designer:
    def design(self):
        print("디자인을 합니다")

class Analyst:
    def analyze(self):
        print("분석을 합니다")

class Company:
    def __init__(self, employees):
        self.employees = employees

    def make_work(self):
        for employee in self.employees:
            if type(employee) == Developer:
                employee.coding()
            elif type(employee) == Designer:
                employee.design()
            elif type(employee) == Analyst:
                employee.analyze()

이 코드에서는 각 직원의 유형에 따라 다른 작업을 수행한다. make_work() 함수는 각 직원의 유형을 확인한 후 해당 직원의 역할에 맞는 작업을 수행한다. 이러한 구조는 각 직원 유형마다 if-elif 구문이 필요하므로 코드가 길어지고 가독성이 떨어진다.

to-be

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Employee로 추상화해둔다.
class Employee(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def work(self):
        ...

class Developer(Employee):
    def work(self):
        print("코딩을 합니다")

class Designer(Employee):
    def work(self):
        print("디자인을 합니다")

class Analyst(Employee):
    def work(self):
        print("분석을 합니다")

class Company:
    def __init__(self, employees: List[Employee]):
        self.employees = employees

    # if문을 사용하지 않고 다형성을 통해서 이를 해결한다.
    def make_work(self):
        for employee in self.employees:
            employee.work()

이 코드는 다형성을 활용하여 코드를 개선한다. 우선, 모든 직원 유형에 대해 공통 인터페이스를 정의한다. Employee 추상 클래스를 생성하고 work() 메서드를 추상 메서드로 선언한다.

그런 다음, 각 직원 유형(Developer, Designer, Analyst)이 Employee 클래스를 상속받고, 고유한 구현을 가진 work() 메서드를 정의한다.

마지막으로, Company 클래스의 make_work() 메서드를 수정하여 if-elif 구문 대신 각 직원의 work() 메서드를 호출한다. 이렇게 하면 코드가 더 간결해지고 가독성이 향상된다.

다형성을 사용하면 코드를 더 깔끔하게 작성할 수 있으며, 새로운 직원 유형이 추가되어도 make_work() 메서드를 수정할 필요가 없다. 이렇게 하면 코드의 유지 보수성이 크게 향상된다.

0%