지속가능한 소프트웨어를 지탱하는 조건
개요
개발자라면 누구나 기술부채 때문에 고통받은 경험이 있을 것 같습니다. 저 또한 다양한 기술부채를 겪었고 그 과정에서 어떻게 하면 생산성을 유지하면서 지속 가능한 소프트웨어를 만들어갈 수 있을지에 대해 고민해왔습니다. 그 덕분에 여러 방법론을 학습하고 실제로 적용해볼 수 있는 기회를 얻었습니다. 이번 글을 계기로 지속가능한 소프트웨어를 지탱하는 조건에 대한 저의 경험과 생각을 정리하고자 합니다.
지속가능한 소프트웨어를 지탱하는 조건
이카루스의 날개
백엔드 개발자로 일한 지 어느덧 3년이 지났습니다. 커리어 동안 담당했던 웹서비스 모두 4년 이상 된 레거시 시스템이었고 다양한 형태의 기술 부채를 안고 있었습니다.
소프트웨어를 담당하는 동안 기술부채 개선에 성공하여 사용자 경험이나 개발생산성을 향상시킨 적도 있습니다. 반면 복잡한 사정 때문에 개선을 하지 못하여 프로젝트 내내 기술부채가 발목을 잡았던 경험도 있습니다. 이 과정에서 생산성의 관점에서 ‘지속가능한 소프트웨어’의 중요성을 크게 느꼈습니다.
일정 수준 이상의 생산성을 유지하기 위해선 소프트웨어의 기술적 복잡도가 적절한 수준에서 관리되어야 합니다. 이런 점에서 기술적 복잡도는 이카루스의 날개와 비슷합니다. 너무 높이 날면 태양에 닿아 추락하고, 너무 낮게 날면 바닷물에 빠져 날개가 젖어버립니다. 지나치게 단순해도, 지나치게 복잡해도 지속가능하기 어려운 것입니다.
너무 낮은 기술적 복잡도
기술적 복잡도가 지나치게 낮으면 당장 첫 개발은 빠르게 진행될지 몰라도 (사실 개발 속도가 빠른 것도 동의하기 어렵습니다. 테스트까지 고려하면 오히려 느립니다) 유지보수나 확장이 매우 어렵습니다. 예를 들어 저는 아래 사례를 겪은 적 있습니다.
- 수백 줄 길이의 메소드
- 온갖 책임을 떠맡고 있는 슈퍼 클래스
- 각종 비즈니스 로직이 우겨 넣어진 한방 쿼리
‘클린코드’, ‘리팩토링’ 등의 명저에서 명확한 해결방법을 제시함에도 불구하고 위 사례는 흔하게 접할 수 있는 것 같습니다. 그만큼 기술부채를 관리하지 않는 회사가 많다는 반증이기도 합니다. 기술부채들이 누적되어 도저히 손을 댈 수 없는 끔찍한 스파게티 괴물이 된 사례도 종종 전해 듣습니다. (SI업계에서는 종종 ‘차세대 프로젝트’라는 고통스러운 방법으로 해결하고는 합니다)
너무 높은 기술적 복잡도
반면 오버엔지니어링도 해롭습니다. 예시를 들자면
- 아직 도메인 복잡도가 낮음에도 섣불리 도입한 복잡한 아키텍쳐 (ex: 헥사고날 아키텍처)
- 아직 트래픽이 많지 않음에도 섣불리 도입한 MSA
- 쿠버네티스 등의 러닝커브가 높은 기술 등
이런 선택들은 팀의 경험이나 리소스가 받쳐주지 않을 경우, 오히려 생산성과 안정성을 해치는 원인이 됩니다. 최악의 경우에는 내부 구성원 누구도 제대로 소화하지 못하는 블랙박스가 되어버릴 수 있습니다.
예시로 저는 쿠버네티스에 대한 지식이 전혀 없는 상태에서, 기존 개발자들이 모두 퇴사한 쿠버네티스 기반 프로덕트를 혼자 맡아 운영한 경험이 있습니다. 다행히 쿠버네티스를 빠르게 익혀 위기를 넘길 수 있었지만 지금 생각해도 피말리는 기억입니다.
기술적 복잡도 관리에 필요한 역량
기술적 복잡도 관리의 어려움
기술적 복잡도의 적절한 수준을 판단하기 위해서는 아래 예시를 포함하여 여러 요소를 복합적으로 고려해야 합니다. 기술적 결정은 오답은 있어도 명쾌한 정답은 없는 회색지대인 셈입니다.
도메인의 복잡도
도메인이 복잡하다면 오히려 클린 아키텍처, 도메인 주도 설계(DDD) 등의 도메인을 순수하게 유지할 수 있는 아키텍쳐 도입이 필요합니다.
비즈니스 성장 속도
빠르게 성장 중인 비즈니스라면, 다소 러닝커브가 있는 기술이라도 선제적으로 도입해 두는 것이 향후 확장성에 도움이 됩니다.
가용 리소스
인원이 적거나 변동이 잦은 있는 조직이라면 러닝커브가 높은 기술 도입은 되려 독이 될 수 있습니다. 때로는 누구나 이해할 수 있는 단순한 구조가 더 나은 선택입니다.
경험에서 나오는 통찰력
회색지대에서 올바른 판단을 내리기 위해서 가장 중요한 역량으로 경험에서 나오는 통찰력을 꼽고 싶습니다.
예를 들어 저는 Spring 프레임워크 기준으로 신규기능을 구현할 때 가능한 아래의 내용을 지키고 있습니다.
- 이메일, 알림톡 등 외부서비스를 이용하는 비즈니스 로직은 인터페이스를 구현하도록 한다
- 의존성 역전을 적용하여 언제든지 외부서비스를 유연하게 교체하기 위함입니다.
- Repository layer는 Controller layer에서 호출하지 않고 반드시 Service layer에서 호출한다
- 대부분의 기능은 단순 CRUD로 시작해도 언젠가 다양한 비즈니스 로직이 추가됩니다. 이 때 Repository layer가 산발적으로 호출되고 있다면 변경이 어렵습니다.
- 결제, 회원가입 등 추후 다른 유형이 추가될 것이 확실한 기능의 경우 전략패턴, 템플릿 메소드 패턴 등의 디자인패턴을 선제적으로 적용합니다.
위 내용은 KISS 원칙에 어긋날 수 있습니다. 하지만 저의 경험 상 결과적으로 오히려 유지보수와 확장에 유리했습니다.
물론 저도 쌩신입 시절 의욕에 불탄 나머지 불필요한 디자인패턴을 적용하는 등 의도치 않게 오버엔지니어링을 한 경험이 있습니다. 시행착오도 겪고 도메인 지식과 비즈니스 경험을 착실하게 쌓은 덕분에 조금씩 시야를 넓히고 있습니다.
복잡도를 조절하는 양심
두번째로 양심을 꼽고 싶습니다. 커리어에 욕심이 있는 개발자라면 누구나 ‘화려한 일’을 하고 싶어합니다. 트래픽, 매출 증가 등의 비즈니스 임팩트는 하고 싶어도 달성하기 어려운 일입니다. 반면 오버엔지니어링은 감시자만 없다면 비교적 쉽게 적용하고 나의 커리어로 삼을 수 있습니다.
회사에 필요한 일을 진실되고 냉정하게 판단하고 실천하는 것이 진짜 프로정신입니다. 저 또한 오버엔지니어링의 유혹에 흔들릴 때가 있습니다. 다행히 아직까지는 프로로서 자존심 덕분에 유혹에 넘어간 적은 없습니다.
마무리하며 - 나에게 하는 다짐
이 글을 쓰는 목적 중 하나는 스스로 각오를 다지기 위함도 있습니다.
최근 김형석님의 링크드인 글과 저서 ‘면접의 질문들’을 읽고 저의 일에 대한 태도를 회고해 보았습니다. 지금까지 팀원 중 가장 열심히 일했다고 자부하고 있지만, 직장인으로 살면서 단 한 번도 요령을 피워본 적이 없다면 거짓말이겠습니다. 하지만 돌이켜보면 저는 일을 대할 때 순수한 열정과 진실한 태도를 잃지 않았습니다. 특히 긍정적인 부분을 꼽자면 저는 일을 대하는 태도를 의식적으로, 점진적으로 개선해왔습니다.
저는 지금 제 자신의 기초공사를 하고 있습니다. 꾸준히 내실을 다지면 언젠가 그 내실이 단단한 기반이 되어 더 크고 멀리 갈 수 있을 것이라 믿습니다.
어쨌든 저에게 있어 코딩이란 낭만입니다. 과정 자체가 즐겁기에 낙관과 함께 성장하고 있습니다.
참고자료
책 : 면접의 질문들