ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 9. 설계의 건전성을 해치는 여러 악마
    Study/내 코드가 그렇게 이상한가요? 2024. 2. 11. 05:15
    반응형

    이번 장에서는 지금까지 소개한 것 이외의 나쁜 코드 및 대처 방안을 공부한다.

    1. 데드 코드

    절대 실행되지 않는 조건 내부에 있는 코드를 데드 코드(dead code) 또는 도달 불가능한 코드(unreachable code)라고 부른다. 이러한 코드는 여러 문제를 일으킨다.

    1. 코드의 가독성을 떨어뜨린다.
      • 코드를 읽는 사람이 데드 코드 주변을 읽을 때마다, 해당 코드가 어떤 조건에서 실행되는지 생각하게 만든다.(실제로는 실행되는 경우가 없는데도 말이다. 이는 숨겨둔 의도가 있는 것은 아닌지 생각하느라 에너지를 소비하게 한다.)
    2. 언젠가 버그가 될 가능성이 있다.
      • 지금까지는 실행되지 않았지만, 사양 변경에 의해 도달 가능한 코드로 바뀔 수 있다. 이렇게 되살아난 코드가 변경된 사양과 다르다면 버그가 된다.

    데드 코드는 발견되는 즉시 제거하는 것이 좋다. 버전 관리 시스템인 Git 등을 활용하여 변경 이력을 관리하면, 코드를 제거했을 때 발생할 수 있는 문제들을 따로 걱정하지 않아도 된다.

    2. YAGNI 원칙

    YAGNI라는 소프트웨어 원칙이 있다. 'You Aren't Gonna Need It.'의 약자로, '지금 필요 없는 기능을 만들지 말라!'라는 뜻이다. 소프트웨어에 대한 요구는 매일매일 변하기 때문에, 확정되지 않은 요구를 미리 예측하고 구현해도, 이러한 예측은 대부분 맞지 않는다.

    또한, 이러한 예측으로 만들어진 코드는 예측이 들어맞지 않았을 때 데드 코드가 된다. 즉, 예측해서 코드를 미리 작성해 두어도 결국 시간 낭비이기 때문에, 지금 필요한 기능을 최대한 간단한 형태로 만드는 것이 가독성과 유지 보수성을 높이며, 중요한 작업에 집중할 수 있게 한다.

    3. 매직 넘버

    매직 넘버란 설명이 없는 숫자를 말한다. 코드에 아무런 설명이 없이 특정한 숫자가 사용되면, 로직을 읽는 것만으로는 이 숫자의 의도를 알아내기 힘들고, 이러한 매직 넘버는 동일한 값이 여러 위치에 등장하여 중복 코드를 만들어낸다. 필요한 특정한 숫자가 있다면 의미를 알 수 있는 이름을 붙여서 상수를 만들어 활용하자.

    4. 문자열 자료형에 대한 집착

    // 레이블 문자열, 표시 색(RGB), 최대 문자 수
    String title = "타이틀,255,250,240,64"

    의미가 다른 여러 개의 값을 하나의 String 변수에 무리하게 넣으면 의미를 알기 어려울 뿐 아니라 split 메서드 등을 활용해야 하기 때문에 쓸데없이 로직이 복잡해진다.

    의미가 다른 값은 각각 다른 변수에 저장하는 것이 좋다.

    5. 전역 변수

    모든 곳에서 접근할 수 있는 변수를 전역 변수라고 부른다. 자바 언어에서는 전역 변수 사양이 없지만, 변수를 public static으로 선언하면 모든 곳에서 접근할 수 있다.

    여러 로직에서 전역 변수를 참조하고 값을 변경하면, 어디에서 어떤 시점에 값을 변경했는지 파악하기 힘들 뿐 아니라, 전역 변수를 참조하고 있는 로직을 변경할 때, 해당 변수를 참조하는 다른 로직에서 버그가 발생할 수 있다. 또한 동기화가 필요한 경우에 퍼포먼스를 크게 떨어뜨리거나, 데드락 상태에 빠질 수도 있다.

    전역으로 선언된 변수 이외에 거대 데이터 클래스도 전역 변수와 같은 성질을 띠는 경우가 많기 때문에 조심하여 설계해야 한다.

    이를 해결하기 위해서는, 영향 범위가 가능한 한 되도록 좁게 설계해야 한다. 관계없는 로직에서는 접근할 수 없게 설계하여, 호출할 수 있는 위치가 적고 국소적일수록 로직을 이해하고 구현하기 쉽다.

    6. null 문제

    변수에 null이 들어갈 수 있도록 설계하면, 해당 변수를 사용하는 모든 곳에서 null 체크를 해야한다. 이는 가독성이 크게 떨어지게 만들고, 실수로 null 체크를 빠트린다면 곧바로 NullPointerException이 발생할 위험에 처한다. 따라서 null 체크 자체가 필요하지 않도록 애초에 null을 다루지 않게 만들어야 한다.

    • null을 리턴하지 않는 설계 : 메서드에서 null을 리턴하지 않게 작성하는 것
    • null을 전달하지 않는 설계 : 메서드에서 null을 변수에 할당하지 않는 것

    null이란 '잘못된 처리'를 의미하여 무언가 갖고 있지 않거나 설정되지 않은 상태조차 존재하지 않음을 뜻한다. 무언가 존재하지 않는 상태 등을 표현하려면 null이 아닌 EMPTY 등의 상태를 만들어서 할당하자.

    코틀린 등은 기본적으로 모든 자료형에 null을 할당하지 못하는 null 안전 자료형을 사용한다.

    7. 예외를 catch하고서 무시하는 코드

    try-catch로 예외를 catch하고도 별다른 처리를 하지 않는 코드는 예외가 발생해도 무시하고 넘어가기 때문에, 오류가 발생해도 어느 시점에 어떤 코드에서 문제가 발생했는지 발견하기 어렵게 만든다.

    이러한 상황을 피하려면, 잘못된 상태에 어떠한 관용도 베풀어서는 안 된다. 예외를 확인했다면 곧바로 통지, 기록하는 것이 좋고, 상황에 따라서는 바로 복구해야 한다.

    8. 설계 질서를 파괴하는 메타 프로그래밍

    프로그램 실행 중에 해당 프로그램 구조 자체를 제어하는 프로그래밍을 메타 프로그래밍이라고 부른다. 자바에서는 리플렉션 API가 여기에 해당한다. 이를 통해 일반적인 프로그래밍에서는 접근할 수 없는 부분까지 접근할 수 있기 때문에, '흑마법'이라고 불리기도 한다.

    리플렉션을 사용하면 final로 지정한 변수의 값도 바꿀 수 있고, private으로 외부에서 접근하지 못하게 만든 변수에도 접근할 수 있다. 따라서 리플렉션을 남용하면, 이 책에서 소개하고 있는 '잘못된 상태로부터 클래스를 보호하는 설계'와 '영향 범위를 최대한 좁게 만드는 설계'가 아무 의미도 없어진다.

    메타 프로그래밍의 단점을 이해하지 못하고 사용하면, 유지 보수와 변경이 정말 힘들어진다. 메타 프로그래밍을 사용하고 싶다면 시스템 분석 용도로 한정하거나, 아주 작은 범위에서만 활용하는 등 리스크를 최소화해야 한다.

    9. 기술 중심 패키징

    패키지를 구분할 때 폴더를 적절하게 나누지 않으면 여러 문제가 생길 수 있다. 스프링(Spring) 등 여러 웹 프레임워크에서는 MVC 아키텍처를 채택하고 있다. 이와 같은 아키텍처에서는 기본적으로 폴더 구성을 models, views, controllers로 구분한다.(기술 중심 패키징)

    비즈니스 클래스들은 기술 중심 패키징에 따라 폴더를 구분하면, 관련성을 알기 매우 힘들어진다. 비즈니스 클래스는 아래와 같이 관련된 비즈니스 개념을 기준으로 폴더를 구분하는 것이 좋다.

    • 재고
      • 재고_유스케이스.java
      • 발주_엔티티.java
      • 입고_엔티티.java
      • 출고_엔티티.java
    • 주문
      • 주문_유스케이스.java
      • 장바구니_엔티티.java
      • 주문_엔티티.java
    • 결제
      • 지불_유스케이스.java
      • 청구_엔티티.java
      • 청구_금액.java
      • 할인_포인트.java

    10. 샘플 코드 복사해서 붙여넣기

    프로그래밍 언어와 프레임워크에 저마다 있는 공식 사이트는, 사양과 문서와 더불어 다양한 샘플 코드가 함께 적혀 있다. 추가로, 기술 커뮤니티 사이트, Q&A 사이트, 엔지니어 개인 블로그 등에서도 설명과 함께 샘플 코드를 제공하낟.

    샘플 코드는 어디까지나 언어의 사양과 라이브러리의 기능을 설명하기 위해서 작성된 것으로, 유지 보수성과 변경 용이성까지 생각해서 작성된 코드가 아니기 때문에, 그대로 복사하여 사용하는 것은 조악한 로직을 만들 수 있다.

    샘플 코드는 어디까지나 참고만 하고, 클래스 구조를 잘 설계해서 사용하자.

    11. 은 탄환

    서양에서 늑대 인간과 악마는 은으로 만들어진 총알(Silver bullet)로 죽일 수 있다고 알려져 있다. 그래서 어떤 문제를 해결하는 비장의 무기, 묘책을 '은 탄환'이라고 부른다. 하지만 소프트웨어 개발에는 은 탄환이 없다.

    어떤 문제가 있을 때, 어떤 방법이 해당 문제에 효과적인지, 비용이 더 들지는 않는지 평가하고 판단하는 자세가 무엇보다 중요하다. 문제와 목적을 머릿속에 새겨 두고, 적절한 기술을 선택할 수 있도록 노력하자.

    반응형
Designed by Tistory.