소프트웨어 설계의 부패

소프트웨어 설계는 무엇일까? 소스코드 작성하기 전 UML 다이어그램을 작성하는 것? 가끔 몇몇 개발자 분들과 이야기를 할 때 설계는 UML 다이어그램을 작성하는 것이라는 말을 듣는다. 그럼 설계는 UML 다이어그램과 동일 시 할 수 있는가에 대해서 고민해보면 그렇지 않다 라는 결론이 나올 수 있다. 다이어그램은 설계에서 부수적인 부분일 뿐 설계 그 자체가 될 수는 없다고 생각한다. 소프트웨어 설계는 매우 추상적인 것이라 생각한다. 사용자 요구사항부터 시나리오, 모듈, 클래스, 메소드와 더불어 어떠한 형태와 구조를 가질 것인지 프로그램 전체의 형태, 구조와도 관련이 있다고 생각한다. 

과거에 프로젝트를 개발할 때 가끔 머리속으로 설계에 대한 그림이 그려질 때가 있었다. 내 머리속에 들어있는 설계의 청사진이 옳다고 생각하고 한 번에 첫 번째 릴리즈까지 가능한 적이 있었다. 그 순간은 매우 뿌듯하고 기분 좋았으나 점차 내 머리속의 설계는 잘못되었고 설계가 부패한 고기처럼 썩어있다는 걸 확인할 수 있다. 외형적으로 매우 신선해보였으나 내부를 살펴보니 곪고 또 곪아서 어떻게 할 수가 없는 상태가 된 적도 있다. 재설계를 하려해도, 시간적 소모와 지속적인 사용자의 요구사항으로 인해 새로운 설계안도 설계와 동시에 썩어들어가는 기분을 느꼈다.  그럼 언제 내 설계가 잘못되었는지 알 수 있는 방법이 없을까? 부패하고 있다는 느낌이 들때가 언제인지 고민을 하다 로버트 마틴의 ‘클린 소프트웨어’ 란 도서에서 잘 정리해둔 것 같아 인용하여 정리해보려 한다.

지금부터 아래와 같은 조짐이 보이면 그 설계는 부패하고 있다고 판단할 수 있다. 누구나 알고있으면서 쉽게 놓치고 있는 부분이라 생각한다.

경직성 

시스템의 변경이 어려운 상태이다. 변경을 하려보니 다른 여러 부분들까지 변경되어야 하는 구조이다. 단순한 방법으로 변경하려 해보지만 쉽게 변경이 어렵다. 즉 의존성으로 인해 하나의 변경이 의존된 다른 부분까지 모두 영향을 미치게 되는 형태이다. 이런 파급효과는 개발자를 지치게하고 이런 모듈의 변경사항이 많아질수록 설계는 유연성을 점점 잃어간다. 새로운 요구사항이 발생하였을 때 해당 요구사항에 대해 분석하고 추가, 수정의 범위 등 작업량을 산출해 내지만 실제 해당 작업을 하다보면 예상하지 못한 부분에서 변경이 필요한 부분이 있다는 것을 깨닫게 된다. 산출한 작업량보다 잘못하면 2, 3배 이상의 작업량 추정이 발생할 수 있다. 

취약성

특정 부분 설계 변경 시 전혀 상관관계가 없는 부분까지 영향을 미쳐 망가지게 된다. 위의 경직성과 다르게 의존성이 없는데도 그러한 경우가 있다. 변경사항의 영향이 전혀 관계없는 부분까지 망가뜨리게 된다면 개발자는 어떠한 생각이 들까? 문제가 문제를 만들어내는 최악의 경우가 될 것이다. 어떤 모듈의 취약성이 점점 심해질수록 전혀 관계없는 부분에서 계속 문제가 발생하게 되고 그럴 가능성은 점점 커진다. 이슈는 계속 생기게되고 개발자는 지쳐간다. 개발자 중 이슈가 발생했을 때 ‘이 부분은 내가 수정한 부분이 아니에요, 내 이슈가 아니에요’ 라고 말하는 개발자들이 가끔 있다. 안타까운 일이다.

부동성

움직이지 않는 컴포넌트, 음 움직일 수 없는 컴포넌트가 더 어울리는 말인 것 같다. 설계한 시스템에서 다른 시스템에서 재사용할 수 있는 부분은 재사용하는게 가장 좋다. 하지만 가끔 설계한 소프트웨어에서 재사용가능한 부분을 전혀 찾지 못하는 경우가 있다. 다른 시스템에서도 충분히 유용하게 사용할 수 있지만 분리해낼 수 없는 부분들, 분리해내려하면 많은 시간적 소모와 분리 시 발생할 수 있는 위험으로 인해 쉽게 설계를 변경할 수 없는 경우를 말한다.

점착성

점착성이란 간단히 말하면 다른 물질에 끈끈히 달라붙는 성질을 말한다. 설계에서 점착성은 소프트웨어의 점착성과 환경의 점착성이라는 2가지 형태로 나뉠 수 있다. 변경사항이 발생했을 때 개발자들은 변경할 수 있는 여러가지 방법들을 찾게된다. 설계가 유지된 형태일 수도 아닐수도 있다. 설계를 유지한 상태에서 변경하는 방법이 설계를 변경하는 방법보다 어렵다면 그 설계는 점착성이 매우 높은 것이다. 서로 간 너무 끈끈히 붙어있어 수정이 매우 어려운 상황이다. 환경의 점착성은 개발환경에서 비롯된다. 주변 개발환경으로 인해 좀 더 빠른 개발을 위해 설계를 변경하고 싶을 때가 있다. 하지만 설계의 유지는 생각치 않고 잘못된 유혹에 빠져 설계가 변경된다면 옳은 동작을 하지 못할 수도 있다. 개발환경의 개선이 설계까지 영향을 미치는 잘못된 상황을 말이다.

불필요한 복잡성

설계를 하다보면 직접적으로 전혀 쓸모없는 구조가 설계에 포함되어 있을 수 있다. 설계하는 과정에선 전혀 발견하지 못하다가 리뷰를 하다보면 그러한 경우를 발견을 할 때도 있고 소스코드 작성 중에 발견할 수 도 있다. 나중에 필요하겠지 란 생각으로 일단 설계해놓고 전혀 불필요한 구조가 들어가 있는 것은 복잡성만 증가시키는 행위이다. 개발자 스스로 미래의 발생할 수 있는 요구사항에 대해 너무 고민한 나머지, 오버엔지니어링을 발생시킬 수 있다. 처음엔 뿌듯할 수 있다. 나중에 이런 요구사항이 왔을 때 내 설계는 유지된 상태에서 제공을 할 수 있다고, 분명 그 말도 맞는 말이다. 미래의 변경을 대비할 수 있다면 설계의 유연성과 추후 변경사항을 방지해줄 수 있다. 하지만 예상했던 효과와 다른 악영향을 미칠 수도 있음을 항상 고려해야 한다. 지금 전혀 사용하지 않는 구조로 인해 설계는 점점 복잡해져가고 미래의 원하는 성과도 얻지 못할 수 있다. 그런 경우를 더 많이 보았다. 

불필요한 반복

단일 추상 개념으로 통합할 수 있는 반복적인 구조가 설계에 포함되어 있다. 주변 개발자분들 중 가끔 필요한 내용을 Ctrl C + V를 이용해 붙여넣는 경우가 있다. 빠른 기능구현을 위해 ‘복붙’은 매우 유용하지만 사용할 때와 사용하지 말아야할 때를 인식해야 한다. 그렇게 붙여넣은 기능이 여러 곳일 때 문제 발생 시 모든 곳을 찾아다니며 수정하는 경우를 보았다. 리뷰 패치가 올라왔을 때 동일한 수정이 수 십 곳이 되는 경우도 있었다. 중복된 기능은 왜 계속 중복되는 꼭 복붙으로만 해결할 수 있는지에 대한 고민을 한번이라도 했으면 그런 구조는 나오지 않았을거란 아쉬움이 남는다. 적절한 추상화를 통해 반복되는 부분을 없애는 일은 최우선 순위는 아니지만 그 일을 행함으로서 매우 유지보수가 쉬운 소프트웨어 구조를 가질 수 있다. 

불투명성

전혀 이해하기 어려운 애매모호한 구조가 있다. 어떠한 의도인지 이해가 쉽지 않은 구조들은 명료하지 않기에 더욱 변경사항에 유연하게 대처하기 어려운 경향이 있다. 처음엔 명료한 구조였지만 추후 점차 불투명성이 커지는 구조가 될 수도 있다. 지속적으로 명료한 구조를 가지기 위해 노력해야 한다. 시간이 지남에 따라 불투명성으로 인해 구조가 점점 부패해지는 경우를 막아야 할 것이다.

위와 같이 소프트웨어 설계가 썩어들어가는 여러 신호들이 있다. 이를 무시하지 말고 융통성있게 대처할 수 있어야 할 것 같다.

참고 : 로버트 C 마틴 | 클린 소프트웨어