전달하고 싶은 것
- 설계를 바라보는 관점
- 시스템 동작 변경과 구조 변경의 차이점
- 군더더기를 없애자
개요
- 설계란 무엇인가?
- 부적절한 가치 판단에 의한 낭비
- 동작 변경과 구조 변경: 코드 정리와 작은 리팩토링
- 군더더기 없는 코드를 위한 아기 발걸음
- 코드 정리는 언제 해야 하는가?
설계란 무엇인가?
설계란 소프트웨어의 구조를 정리하고 코드를 어디에 배치할지 결정하는 과정을 의미합니다. 이는 코드가 수행할 역할을 명확히 하여 코드를 특정 위치에 작성하는 행위 입니다.
효율적이고 명확한 코드를 작성하기 위해서는 코드를 어떤 구조 안에서 배치할지 미리 계획하는 작업이 필요합니다.
부적절한 가치 판단에 의한 낭비
켄트 벡은 XP(익스트림 프로그래밍)에서 “내가 가치 있게 생각하는 것과 정말로 가치 있는 것 사이의 차이에서 낭비가 생긴다” 라고 말했습니다.
이 말은 소프트웨어 개발에서 진짜로 중요한 요소에 집중하지 못할 때 발생하는 불필요한 기능이나 복잡성을 의미합니다.
설계에 이 관점을 적용하는 방법:
- 설계는 반드시 필요한 요소에만 집중해야 하며, 당장 필요하지 않은 기능이나 복잡한 구조를 추가하는 것은 낭비입니다.
- 미래를 대비한 복잡한 설계는 오히려 개발 과정에서 장애물이 될 수 있으며, 유지보수에 있어서도 부작용을 초래할 수 있습니다.
- 가치 있는 코드만 남기고 불필요한 부분을 제거하는 것이 군더더기 없는 설계의 핵심입니다.
동작 변경과 구조 변경
동작 변경
동작 변경은 소프트웨어의 외부적인 기능을 변경하는 작업을 의미합니다. 기능 추가나 로직 수정과 같은 변경이 있으며, 사용자에게 직접적인 영향을 미치는 변화를 포함합니다.
구조 변경: 코드 정리와 리팩토링
구조 변경은 소프트웨어의 내부적인 구조를 개선하는 작업으로, 외부 동작에는 영향을 미치지 않습니다. 이는 코드의 가독성과 유지보수성을 높이기 위한 작업입니다.
켄트 벡은 코드 정리는 마치 미니어처 같은 아주 작은 리팩토링이라고 표현했습니다. 이러한 작은 개선들을 주기적으로 수행 함으로써, 코드의 복잡성을 줄이고 가독성을 높여 코드 품질을 유지할 수 있습니다.
군더더기 없는 코드를 위한 아기 발걸음
XP(익스트림 프로그래밍)에서 켄트 벡은 한 번에 큰 변화를 주기보다, 작고 점진적인 개선을 통해 안정적으로 변화를 이끄는 방법으로 “아기 발걸음” 이라는 개념을 소개 합니다.
아기 발걸음 에서는 ‘올바른 방향이라고 알아챌 수 있는 일 중 당신이 할 수 있는 최소한은 무엇입니까?’ 라는 질문을 던지며, ‘ 많은 작은 단계를 엄청나게 빠른 속도로 밟아나가서 마치 도약하는 속도로 보일 수도 있다.’ 고 전합니다. 중요한 것은 크기가 아니라 의지와 꾸준함 입니다.
군더더기 없는 코드를 위한 실천에서도 이러한 작은 단계가 중요합니다. 코드 정리, 리팩토링, 불필요한 코드 제거 등 작은 개선이 모여 전체 코드 품질을 향상시킵니다.
다음은 Tidy First(더 나은 소프트웨어 설계를 위한 32가지 코드 정리법)에서 켄트 벡이 소개하는 코드 정리법 중 일부를 소개 합니다.
보호 구문
Before
foo(param) {
if (param != null) {
if (param.isValid()) {
return "Processing";
}
}
return "Invalid param";
}
After
foo(param) {
if (param == null || !param.isValid()) {
return "Invalid param";
}
return "Processing";
}
보호 구문은 함수의 진입점에서 잘못된 상태나 예외 상황을 빠르게 처리하는 구문입니다. 이것은 “코드의 세부 사항을 살펴보기 전에 염두에 두어야 할 몇 가지 전제 조건이 있습니다.” 라고 말하는 것처럼 보입니다.
보호 구문은 조건문 중첩을 줄이고 코드 흐름을 간결하게 하여 가독성을 높이는 것을 목표로 합니다.
안쓰는 코드
지워 버립니다. 그게 전부 입니다. 실행되지 않는 코드라면 그냥 지웁니다. 우리에겐 형상 관리 도구가 있습니다.
대칭으로 맞추기
# 초기화 지연 예시
foo()
return foo if foo is not nil
foo := ...
return foo
foo()
if foo is nil
foo := ...
return foo
# 기교를 가한 코드
foo()
return foo not nil
? foo
: foo := ...
# 할당문이 수식이면 더욱 까다로움
foo()
return foo := foo not nil
? foo
: ...
# 조건이 잘 드러나지 않는 수준의 코드
foo()
return foo := foo || ...
각각의 코드가 뜻하는 바는 ‘아직 계산하지 않았다면 foo의 값을 계산하고 임시 보관하세요.’ 입니다. 각자 장단점이 있습니다. 하지만 두 가지 이상의 패턴을 섞어 쓰면 혼란스러워집니다. 코드를 읽을 때 기존과 다르다면 ‘다른 동작의 코드겠지’ 라고 예단하는 경우가 많습니다.
따라서 한 가지 방식을 선택합니다. 다른 방식으로 작성한 코드를 선택한 방식으로 고칩니다.
설명하는 주석
코드를 읽다가 “아, 이건 이렇게 돌아가는 거구나!” 라는 생각이 드는 순간이 소중한 순간입니다. 기록하세요. 모래 속에 묻듯 그냥 두는 것보다 훨씬 나을 것입니다.
불필요한 주석 지우기
코드 만으로 내용을 이해할 수 있다면 주석은 삭제하세요.
if(generator)
... generator 설정을 위한 코드...
else
# generator 가 없다면 default 반환
return getDefaultGenerator()
조건절에 보호 구문을 적용해 정리한 후에는 다음과 같이 바뀝니다.
if(!generator)
# generator 가 없다면 default 반환
return getDefaultGenerator()
...generator 설정을 위한 코드...
불필요하거나 과도한 주석을 제거하여 코드를 간결하게 만드는 작업입니다.
불필요한 주석을 제거함으로써 코드만으로 의도를 명확히 하고, 주석에 의존하지 않는 코드 작성이 목표입니다.
if(!generator)
return getDefaultGenerator()
...generator 설정을 위한 코드...
코드 정리는 언제 해야 하는가?
Tidy First(더 나은 소프트웨어 설계를 위한 32가지 코드 정리법)에서 켄트 벡은 코드 정리를 통해 단순히 코드를 깔끔하게 유지하는 것을 넘어 언제 정리를 해야 하는지에 대한 명확한 기준을 제시합니다. 정리를 해야 할 시점과 정리를 미뤄야 할 시점을 잘 판단함으로써, 코드를 효율적으로 관리할 수 있습니다.
코드 정리를 하지 말아야 할 때
코드 정리가 모든 경우에 필요한 것은 아닙니다. 때로는 정리가 불필요하거나 오히려 시간을 낭비할 수 있는 상황도 있습니다.
- 앞으로 다시는 코드를 변경하지 않을 때 : 이 코드를 더 이상 수정할 필요가 없다면, 굳이 시간과 노력을 들여 정리할 필요가 없습니다.
- 설계를 개선하더라도 배울 것이 없을 때 : 정리를 통해 학습할 기회가 없는 경우, 즉 개선 작업이 의미 있는 발전을 가져오지 않을 때는 정리를 하지 않아도 됩니다.
코드 정리를 나중으로 미뤄야 할 때
때로는 코드를 즉시 정리하기보다는 나중에 작업하는 것이 더 적합할 수 있습니다. 정리할 분량이 많거나, 즉각적인 보상이 없는 경우입니다.
- 정리할 코드 분량이 많은데, 보상이 바로 보이지 않을 때 : 대량의 코드를 정리해야 하는데, 그 보상이 금방 나타나지 않는다면 잠시 미뤄둘 수 있습니다.
- 정리의 보상이 잠재적일 때 : 지금 당장 정리해도 큰 성과가 없고, 그 이익이 미래에 있을 것이라면 우선순위를 낮출 수 있습니다.
- 작은 묶음으로 나눌 수 있을 때 : 전체적으로 한 번에 정리하는 것보다, 작은 묶음으로 나누어 여러 번에 걸쳐 정리할 수 있다면 천천히 진행할 수 있습니다.
동작 변경 후 코드 정리를 해야 할 때
동작 변경이 완료된 후, 곧바로 코드를 정리해야 할 때도 있습니다. 만약 정리를 미루면 비용이 더 커지거나, 작업을 끝냈다는 느낌이 들지 않을 때입니다.
- 코드 정리를 미룰수록 비용이 증가할 때 : 다음에 정리할 때까지 미루면 더 많은 시간과 비용이 필요하다면, 지금 정리하는 것이 더 낫습니다.
- 코드를 정리하지 않으면 완료된 느낌이 없을 때 : 정리하지 않으면 작업이 완료되지 않은 것처럼 느껴진다면, 그때가 바로 정리를 해야 할 때입니다.
코드 정리를 먼저 하고 동작 변경을 해야 할 때
코드를 정리한 후에 동작 변경을 하는 것이 더 효율적일 때도 있습니다. 코드 정리로 인해 동작 변경이 쉬워질 때는, 먼저 정리하는 것이 바람직합니다.
- 코드 정리가 동작 변경을 쉽게 만드는 즉각적인 효과가 있을 때 : 정리 후 동작 변경이 더 간단해지고 명확해질 수 있다면, 동작 변경 전에 먼저 정리해야 합니다.
- 어떤 코드를 어떻게 정리해야 하는지 명확할 때 : 정리해야 할 부분과 방법이 명확하다면, 코드 정리를 먼저 하고 동작 변경을 진행하는 것이 좋습니다.
결론: 군더더기 없는 설계를 통한 간결한 코드 작성
설계는 현재 필요한 기능에 집중하고, 불필요한 복잡성을 제거하여 유지보수가 용이한 코드를 작성하는 데 초점을 맞춰야 합니다. XP의 가치를 바탕으로, 진짜로 가치 있는 것에 집중한 설계를 통해 개발 속도와 코드 품질을 모두 높일 수 있습니다.
동작 변경과 구조 변경을 명확히 구분하여, 필요한 코드만 남기고 군더더기 없는 코드를 작성하는 것이 중요합니다.
- 켄트 벡, 「켄트 벡의 Tidy First?: 더 나은 소프트웨어 설계를 위한 32가지 코드 정리법」, 한빛미디어, 2024, 안영회
- 켄트 벡 , 신시아 안드레스, 「익스트림 프로그래밍(Extreme Programming)」, 인사이트, 2006, 김창준, 정지호
- 조영호 「오브젝트」, 위키북스, 2019