본문 바로가기
내 코드가 그렇게 이상한가요?

16장 설계를 방해하는 개발 프로세스와의 싸움

by lleesla 2024. 4. 13.
  • 개발 프로세스 자체가 레거시 코드의 발생 원인이 되기도 한다.
  • 문제는 기술 부족 이외에도 심리적 안정감, 커뮤니케이션, 조직적 요인 등 굉장히 다양한 원인으로 발생한다.
  • 각각의 문제와, 그 해결 방법에 대해 설명해보자

16.1 커뮤니케이션

16.1.1 커뮤니케이션이 부족하면 설계 품질에 문제가 발생

  • 팀 개발에서는 팀원과 어떤 코드를 작업할 때 서로의 로직이 제대로 맞물리지 않아 버그로 이어지는 상황이 매우 흔하다.
  • 커뮤니케이션이 부족해 서로가 무엇을 하고 있는지 잘 모르기 때문이다.

16.1.2 콘웨이 법칙

  • 커뮤니케이션 문제 해결과 관련된 콘웨이 법칙
  • 콘웨이 법칙은 ‘시스템의 구조는 그것을 설계하는 조직의 구조를 닮아간다’ 라는 법칙이다.
  • 개발 부문이 3개의 팀으로 구분되어 있다면 모듈의 수도 팀의 수와 동일하게 3개로 구성되는 시스템이 만들어진다.
  • 커뮤니케이션 비용 구조의 법칙으로 팀 내부에서 이뤄지는 커뮤니케이션은 비용이 낮고, 팀 외부와의 커뮤니케이션은 비용이 높다는 비용 구조 자체가 시스템 구조에 영향을 준다.
  • 최근에는 반대로 접근하는 역콘웨이 법칙이 등장했다.
  • 역콘웨이 법칙이란 ‘소프트웨어의 구조를 먼저 설계하고, 이후 소프트웨어의 구조에 맞게 조직을 편성한다'는 접근 방법이다.
  • 하지만 커뮤니케이션 문제는 팀원 간 커뮤니케이션 비용이 높다는 이야기다. 역콘웨이 법칙을 내세우며 팀을 구성하더라도 팀 내부의 문제가 있다면 본질적인 문제가 해결되지 않는다.

16.2 설계

  • 설계는 굉장히 중요한 개발 프로세스이다. 설계가 제대로 이루어지지 못하게 하거나, 설계한 것이 제대로 동작하지 않게 하는 다양한 함정이 있다.
  • 각각의 함정과 대처 방법을 살펴보자.

16.2.1 ‘빨리 끝내고 싶다’는 심리가 품질 저하의 함정

  • 품질이 나쁜 시스템을 만드는 팀은 클래스 설계와 관련된 습관이 애초에 없는 경우가 많다.
  • 일이 바쁘면 구현을 빨리 끝내고 싶은 마음이 앞서게 되고, 그냥 동작하기만 한다면 코드를 어떻게든 구현해 버린다.
  • 이러한 환경에서는 클래스 다이어그램조차 그려보지 않는 등 설계 품질을 무시하기 쉽다.
  • 하지만 소프트웨어는 한 번 만드는 것으로 끝나지 않는다. 이후에 사양 변경이 계속 이루어지고, 기능도 점점 확장될 것이다.
  • 초반에는 빠른 구현을 할 수 있지만 시간이 지날수록 구현 속도가 느려지고 버그 수정을 하게될 것이다.

16.2.2 나쁜 코드를 작성하는 것이 좋은 코드를 작성하는 것보다 오래 걸린다.

  • ‘테스트 주도 개발(TDD)를 사용해서 구현하는 경우 와 ‘사용하지 않고 구현하는 경우’ 중에 TDD를 사용해서 개발하는 편이 더 빠르다는 결론이 나왔다.

16.2.3 클래스 설계와 구현 피드백 사이클 돌리기

  • 사양을 변경할 때 최소한 메모라도 적어 클래스 다이어그램을 그려보자
  • 구현하다 보면 예상하지 못했던 요소들을 발견하는데 이때마다 클래스 다이어그램에 반영하면 설계 품질이 향상될 것이다.

16.2.4 한 점에 완벽하게 설계하려고 들지 말고, 사이클 돌리며 완성하기

  • 사양을 대규모로 변경할 때는 그만큼 확실한 클래스 설계가 필요하다.
  • 단 한번의 설계로 완벽한 구조를 만들어 낼 수 없다.
  • 완벽하다고 생각해도, 구현하다 보면 결국 동작에 필요한 요소들을 추가로 발견하게 될 것이다.
  • 설계 품질은 설계와 구현 피드백 사이클을 계속 돌리면서 조금씩 향상된다.

16.2.5 ‘성능이 떨어질 수 있으니 클래스를 작게 나누지 말자’는 맞는 말일까?

  • 클래스 인스턴스 생성은 비용이 발생하여 성능을 떨어뜨릴 수 있으므로 클래스를 많이 만들면 안된다’라고 생각하는 사람이 꽤 많다.
  • 클래스가 많아지면 비용이 발생하는 것은 맞으나 무시할 수 있는 정도이다.
  • 성능에 지배적인 영향을 미치는 부분은 실제로 측정해 보기 전까지는 제대로 알 수 없다.

16.2.6 설계 규칙을 다수결로 결정하면 코드 품질은 떨어진다.

  • 코드 품질을 향상시키기 위해 코딩 규칙과 설계 규칙을 정하는 경우가 있다.
  • 이때 팀 전체의 합의를 이루고자 규칙을 다수결로 결정하는 경우가 있는데 일반적으로 결과가 좋지 않다.
  • 설계 기술이 미숙한 팀원이 제안된 규칙의 좋고 나쁨을 제대로 판단할 수 없어 조악한 규칙이 채택될 수도 있고 규칙 자체가 만들어지지 않을 수도 있다.

16.2.7 설계 규칙을 정할 때 중요한 점

  • 설계 역량이 뛰어난 팀원이 중심이 되어 규칙을 만들어 나가는 것이 좋다.
  • 또한 각각의 설계 규칙에는 이유와 의도를 함께 적는 것이 좋다.

16.3 구현

16.3.1 깨진 유리창 이론과 보이스카우트 규칙

  • 범죄학에는 깨진 유리창 이론이 있다. 다음과 같은 과정을 거쳐 치안이 악화된다는 이론이다.
    1. 건물에 깨진 유리창 하나가 생긴다.
    2. 깨진 유리창이 오래 방치되면, 아무도 신경쓰지 않는 건물이라는 인식이 퍼진다.
    3. 다른 문을 깨기도 하고, 쓰레기를 버리는 등의 경범죄가 추가로 발생해서 치안이 조금씩 나빠진다.
    4. 상황이 더욱 악화되어 흉악 범죄까지도 일어나게 한다.
  • 이 이론은 소프트웨어 개발에도 적용된다. 조악하고 복잡하고 질서없는 코드가 방치되면, 소프트웨어 전체가 점점 더 무질서해집니다.
  • 코드를 변경할 때, 자신이 변경하기 전보다 더 깨끗한 상태로 만들어 커밋하다보면 이러한 작은 개선이 코드의 전체적인 질서가 점점 더 좋아질것이다.

16.3.2 기존의 코드를 믿지 말고, 냉정하게 파악하기

  • 레거시 코드를 박멸하려면, 기존의 코드를 맹신하지 않는 마음가짐이 중요하다.
  • ‘이코드는 무엇을 해결하고 싶은 코드일까?’, ‘이 코드가 달성하려는 목적은 무엇일까?’를 분석한다.
  • 이상적인 설계를 다시 하기 위해서는 넘어야 할 장애물이 있다.
    1. 앵커링 효과
      1. 처음 제시한 수치와 정보가 기준이 되어, 이후의 판단을 왜곡하는 인지 편향을 의미한다.
      2. 기존의 클래스 이름과 메서드 이름이 기준이 되어서, 개발자 판단을 왜곡시키는 경우가 굉장히 많다.
    2. 이름이 없거나, 이름을 모르는 것은 인지하기 어렵다.
      1. 예를 들어 ‘매매 계약’ 이라는 이름이나 개념을 모르면 관련된 조건의 존재도 알기 힘들다.
      2. 관계자를 찾아 대화하거나, 관련된 글을 읽고 그곳에서 쓰이는 용어를 파악하고 이해해야한다.
  • 이러한 두 장애물을 극복하면 냉정하게 정체를 파악하고 클래스와 메서드에 정체를 표현하는 이름을 붙일 수 있을 것이다.

16.3.3 코딩 규칙 사용하기

  • 코딩 규칙이란 코드의 가독성과 유지 보수성 향상, 문제가 있는 코드를 미연에 방지하기 위한 목적 등으로 코딩 스타일과 명명 규칙 등을 정해 놓은 것이다.
  • 코딩 규칙을 잘 준수하면, 코드의 구조와 이름에 질서가 생기고 읽기 쉬워진다.

16.3.4 명명 규칙

  • 명명 규칙이란 변수 이름, 클래스 이름, 메서드 이름을 정하는 규칙이다.

요소 규칙 예

클래스 어퍼 카멜 케이스 Customer
메서드 로어 카멜 케이스 payMoney
상수 모두 대문자, 구분자로 _를 사용 MAX_NAME_LENGTH
  • 어퍼 카멜 케이스는 단어의 앞글자를 모두 대문자로 하는 규칙
  • 로어 카멜 케이스는 두 번째 단어부터 앞글자를 대문자로 하는 규칙
  • 이외에도 모든 글자를 소문자로 사용하고 단어 구분자를 _로 사용하는 스네이크 케이스등이 있다.
  • 중요한 점은 팀 전체에서 통일된 규칙을 정하고 이를 활용해 가독성을 높이는 것이다.

16.4 리뷰

16.4.1 코드 리뷰 구조화하기

  • 레거시 코드가 작성되는 현장이라면, 코드 리뷰를 안하는 경우가 많다. 동작만 가능하도록 작성된 난잡한 코드가 누구의 확인도 받지 않고 병합된다.
  • 이런 코드는 결국 품질이 떨어져 버그가 빈번하게 발생한다. 버그만 고쳐보려고 해도 비슷한 버그가 또 발생할 것이다.
  • 깃허브에는 다른 팀원이 승인한 풀 리퀘스트(PR)만 병합(merge)할 수 있는 기능이 있다. 그 외에도 코드 품질 분석과 단위 테스트와의 연동, 자동 실행 등의 CI 기능이 다양하게 제공되므로 꼭 활용해보길 바란다.
  • 코드의 히스토리와 경위를 알고 있는 사람이나 설계를 자세하게 아는 사람이 리뷰하는 것이 좋다.
  • PR 작성 시 템플릿 텍스트에는 리뷰 관점을 명시하는 것이 좋다. 보이스카우트 규칙 확인 항목, 설계 규칙과 관련된 링크를 포함하는 것도 좋다.

16.4.2 코드를 설계 시점에 리뷰하기

  • 많은 사람이 코드 리뷰를 로직이 기능 요건을 만족하는지, 결함이 존재하는지, 코딩 스타일을 지키고 있는지 리뷰하는 것이라고 생각하지만 이보다는 설계적 타당성을 중심으로 리뷰해야 한다.
  • 이 책에서 언급했던 여러 설계 관점과 비교해 보면서 리뷰하기 바란다.

16.4.3 존중과 예의

  • 코드 리뷰 시 기술적 올바름을 두고 공격적인 코멘트를 다는 사람이 있다. 아무리 옳은 말이라도 공격적 코멘트는 안된다. 이러한 리뷰는 사람에게 상처를 주고, 생산성을 저하시키는 것은 물론, 코드를 좋게 만든다는 본래의 목표도 저해한다.
  • 리뷰에서 가장 중요한 것은 존중과 예의이다. 리뷰를 받는 사람에 대한 존중을 먼저 생각하자. 기술적 올바름과 유용성보다도 함께 일하는 동료에 대한 존중이 먼저다.
  • 다음은 구글 크로미움 프로젝트의 리뷰 지침, 존중하는 코드 리뷰이다.

해야 하는 것 설명

능력과 선의를 갖고 있다고 생각하기 개발자는 능력이 있고 선의를 갖고 있다고 생각하세요. 실수는 정보 부족으로 인해 발생하는 것이라고 생각하세요.
만나서 이야기하기 리뷰 도구만으로 의견이 모이지 않는 경우, 직접 만나 의견을 교환하세요.
이유를 설명하기 왜 잘못되었는지, 어떤 변경이 더 좋은지 설명하세요. 이렇게 하면 안된다는 말만으로는 상대에게 의견이 전달되지 않습니다.
이유 듣기 상대방의 의도를 모르겠다면 주저하지 말고 변경 이유를 물어보세요.
잘 끝맺기 완벽을 위해 너무 철저하게 리뷰하다 보면, 리뷰 받는 사람이 너무 힘들어집니다. 완벽을 찾으려고 하기보다 이렇게 하는 것이 더 좋을 것 같다라는 의견으로 리뷰를 적절하게 끝맺는 것이 좋습니다.
적절한 시간 내에 답변하기 리뷰를 계속 방치하지 마세요. 24시간 내에 답변할 수 없다면, 언제까지 답변할 수 있는지 코멘트를 달아 주는 등 적절한 방법으로 대응하세요.
긍정적인 부분 이야기하기 리뷰는 모든 잘못된 부분을 찾겠다는 비판적인 마음으로 임하지 말고, 긍정적인 부분을 인정하는 자세로 임하세요. 억지로 칭찬할 필요는 없지만, 어려운 일을 맡은 사람과 좋은 변경을 한 사람에게 감사하는 마음을 표현해 보세요.

하지 말아야 하는 것 설명

나쁜 말 사용하지 않기 상대방이 최선을 다하고 있다는 것을 전제로 합니다. 왜 신경쓰지 못했죠? 처럼 공격적인 말은 달아선 안 됩니다.
극단적이고 부정적인 표현 사용하지 않기 일반적인 사람이라면 이러지 않는다, 끔찍한 알고리즘이다 라는 부정적인 표현을 사용해서는 안 됩니다. 사람을 공격해서 움직이려고 하면 안 됩니다. 사람이 아니라 코드에 대해서 이야기해야 합니다.
도구 사용을 단념 시키지 말기 작성자가 코드 포매터 등 자동화 도구를 사용했다면, 일단 그 자체에 감사해야 합니다. 도구 사용에 대해 시비를 걸거나, 도구에 대한 취향을 강요해서는 안 됩니다.
사소한 것으로 시간 오래 끌지 않기 어떻게 해도 괜찮을 것 같은 경우, 리뷰에서 둘 중 하나를 결정하려 하지 마세요. 리뷰의 목적은 이기고 지는 것이 아닙니다.

16.4.4 정기적으로 개선 작업 진행하기

  • 구현이나 코드 리뷰 중간에 좋지 않은 코드를 발견했는데, 스케줄 문제로 대처하지 못하는 경우가 있을 수 있다. 이때 일반적으로 나중에 고치자하고 넘어가곤 한다.
  • 하지만 이렇게 넘어간 결함은 대부분 대책 없이 방치된다. 왜냐하면 새로운 업무가 계속해서 할당되기 때문에, 새로운 업무에 정신이 팔려서 잊어버리기 때문이다.
  • 좋지 않은 코드에 대처하는 일은 작업 관리 도구에 개선 작업으로 추가해두고 정기적으로 이런 작업을 모아 개선 작업을 진행해서 확실하게 대처하는 것이 좋다.
  • 예를 들어 주 1회 팀 회의에서 이번 주에 진행할 개선 작업에 대한 논의를 한다든지 하면 좋을 것이다.
  • 작업 관리에는 깃허브의 이슈를 활용하면 좋다. 소스 코드, PR과 연동되기 때문에 편리하다.

16.5 팀의 설계 능력 높이기

  • 이 장에서 지금까지 다룬 개발 프로세스는 설계 역량이 뛰어난 팀원이 어느 정도 있을 때의 이야기다.
  • 그런데 팀에 따라서는 설계를 잘 아는 팀원이 아예 없을 수도 있다. 이런 환경에서는 리뷰뿐만 아니라 설계와 구현 개선 제안도 힘들다.
  • 팀 전체의 설계 능력이 부족하면, 설계 능력을 높이기 위한 활동이 필요하다.

16.5.1 영향력을 갖는 규모까지 동료 모으기

  • 혼자서 품질 문제를 깨닫고, 설계를 개선하려고 했다고 생각해보자. 혼자 힘으로는 효과가 거의 나지 않는다. 오히려 남들은 지시한 대로 일하지 않고, 쓸데없이 다른 일을 한다고 생각할 수도 있다.
  • 설계뿐만 아니라 일의 방식을 상향식으로 개선하려면, 주위의 협력이 반드시 필요하다.
  • 협력이 왜 필요할까? 서로 협력해야 일하는 방식을 바꿀 만큼 큰 영향력이 생기기 때문이다. 우선은 영향력을 가질 수 있을 만큼 동료를 모으는 게 중요하다. 영향력을 발휘할 수 있는 규모는 어느 정도 일까?
  • 시장 점유율의 목표를 정의하는 쿠프만 목표라는 것이 있는데 쿠프만 목표치는 점유율 10.9%이다. 이 수치를 엔지니어 팀에 적용해서 생각해 보자. 만약 팀이 20명이라면 약 2명이다. 그렇게 많은 수는 아니다. 팀이 20명 정도라면, 자신 이외의 동료를 한 명만 끌어들여도 진행할 수 있다는 이야기이다.

16.5.2 천리길도 한 걸음부터

  • 동료를 발견하면 곧바로 이 책의 내용들을 한꺼번에 전달하고 싶은 충동이 생길 수도 있다.
  • 매일매일 조금씩 설계 지식을 공유하도록 하자.

16.5.3 백문의 불여일견

  • 동료와 설계 지식을 어느 정도 공유했다면, 함께 클래스를 설계하고 구현한 뒤 리뷰해 보자.
  • 백문이 불여일견이라는 말처럼 사물의 모습은 말로 설명을 듣는 것보다, 실제로 보고 실감할 때 확실히 알 수 있다. 설계도 마찬가지이다.
  • 실제로 손을 움직여서 코드의 가독성이 좋아지고, 중복 코드가 줄어드는 모습을 동료들과 실감하고 공유해 보자.

16.5.4 팔로우업 스터디 진행하기

  • 처음에는 독서 모임 느낌으로 설계 관련 서적을 읽으면서 진행하는 것도 좋다. 하지만 이전에 언급했던 것처럼 역시 실제로 코드를 개선해 보는 것이 효과적이다. 인풋보다 아웃풋이 학습 효과가 높다고 한다.
  • 추천하는 스터디 흐름
    • 책에 적혀 있는 노하우를 1~2개 정도 읽어 본다.
    • 프로덕션 코드에서 노하우를 적용해 볼 수 있는 부분을 찾는다.
    • 노하우를 사용해 코드를 개선해 본다.
    • 어떻게 개선했는지 비포&애프터를 비교할 수 있게 발표한다.
    • 발표 내용에 대해 질의 응답과 논의를 한다.
  • 스터디는 한 번에 한 시간 정도, 스몰 스탭으로 반복한다. 이렇게 하면 인풋, 아웃풋, 피드백을 빠르게 반복할 수 있어서, 효과적으로 공부할 수 있다.

16.5.5 스터디 그룹에서 발생할 수 있는 문제 해결 노하우

  • 스터디 방식에 따라 효과를 아예 얻지 못하고, 오히려 설계에 대한 인식을 나쁘게 만드는 경우도 있으므로 주의해야 한다.
  • 일단 단순하게 책을 읽기만 하는 스터디는 추천하지 않는다. 아웃풋이 동반되지 않으므로 학습 효과가 낮다. 그리고 한 번에 많이 인풋해도 사람들은 업무가 바빠 관련된 내용을 금방 잊어버린다.

16.5.6 리더와 매니저에게 설계의 중요성과 비용 대비 효과 설명하기

  • 조직 차원에서 설계 품질을 향상시키려면, 개발 프로세스 흐름에 설계를 추가해야 한다. 그러려면 리더와 매니저도 설계의 필요성을 공유해야 한다.
  • 매니저에게 비용 대비 효과를 중심으로 이야기 하자.
  • 개발 효율 저하 문제를 이야기하고, 이런 문제를 해결할 수 있는 설계 업무가 있음을 알리자. 그리고 설계에 비용을 투자해야 하는 이유를 설명하자.
  • 매니저에게 설명할 때는 혼자가 아니라, 동료와 함께하는 것이 바람직하다. 동료들과 했던 설계 활동과 그 실적을 함께 설명하면 설득력이 더 높아질 것이다.

16.5.7 설계 책임자 세우기

  • 개발 팀원 대부분이 설계 품질을 좋게 만드는 데 적극적이라면, 품질 향상 작업이 자연스럽게 이루어진다. 하지만 그렇지 않은 경우, 설계 책임자를 내세우는 것이 좋다.
  • 설계 책임자는 변경 용이성 품질 향상을 위해, 다음과 같은 내용을 추진한다.
    • 설계 품질과 관련된 규칙이나 개발 프로세스 수립
    • 규칙을 반복적으로 알리고 교육
    • 리더와 매니저에게 효과 공유
    • 품질 시각화
    • 설계 품질 유지
  • 설계 규칙, 코딩 규칙, 리뷰 방법 등 설계 품질과 관련된 규칙과 개발 프로세스를 수립하도록 하자.
  • 규칙을 정하면 팀원들에게 확실하게 인지시키고 필요하다면 스터디를 하는 등 교육도 진행하자.
  • 추가로, 개발 팀원뿐만 아니라 리더와 매니저에게도 평소 설계와 개발 비용 관련 내용을 계속해서 공유해야 한다.
  • 설계 품질 향상에 도움을 주는 도구를 도입하는 것도 좋다. 품질을 시각화하고, 품질 향상을 효율화할 수 있다.