지난주에는 일관된 반환 값을 가진 메서드가 어떻게 코드를 더 단순하게 만들어 주는지 이야기했습니다. 하지만 그것은 어떻게 가능할까요? 올바른 리팩토링은 어떻게 코드를 다루기 쉽게 만들 수 있을까요? 좋은 추상화가 좋고 나쁜 추상화가 나쁜 이유는 무엇일까요? 코드를 무작정 재배치한다고 해서 고품질 소프트웨어가 저절로 완성되는 것은 아닙니다.
이러한 기법들이 왜 효과가 있는지 그 원리를 이해하면, 코드의 어느 부분에 개선이 필요한지 더 잘 파악할 수 있습니다. 그리고 가장 중요한 곳에 적절한 도구를 적용할 수 있게 됩니다.
소프트웨어 개발에서 가장 어려운 문제는 무엇일까?
“컴퓨터 과학에는 단 두 가지 어려운 문제가 있습니다. 바로 캐시 무효화와 이름 짓기입니다.”
– 필 칼튼(Phil Karlton)
물론 이 명언은 어디에서나 접할 수 있습니다. 하지만 실제 소프트웨어 개발 현장에는 더 어려운 문제가 존재합니다. 바로 복잡성 관리입니다. 소프트웨어 개발에서 복잡성은 여러 가지로 정의될 수 있지만, 핵심적으로 프로그램의 복잡성이란 작업하는 동안 머릿속에 담아두어야 하는 정보의 양을 의미합니다.
소프트웨어를 더 많이 작성하다 보면 한 번에 머릿속에 담을 수 있는 양도 자연스럽게 늘어납니다. 하지만 최고의 개발자에게도 한계는 있습니다. 프로젝트가 너무 복잡하면 정신적 처리 용량을 초과하게 되고, 프로그램의 여러 영역을 잊어버리기 시작합니다. 최악의 버그는 바로 프로젝트의 한 부분을 변경하면서, 그 변경이 같은 프로젝트의 전혀 다른 부분에 어떤 영향을 미치는지 인식하지 못했을 때 발생합니다.
가정을 통한 단순화
만약 기억력이 사진처럼 정확해서 프로그램의 모든 부분이 서로 어떻게 맞물리는지 완벽히 기억할 수 있다면, 버그가 훨씬 줄어들겠죠? 하지만 그런 기억력을 기르기란 쉽지 않습니다. 대신 한 번에 한 가지에만 집중할 수 있는 것만으로도 비슷한 효과를 얻을 수 있습니다.
소프트웨어 개발의 많은 모범 사례는 한 번에 머릿속에 담아야 할 것들의 수를 줄이는 데 초점이 맞춰져 있습니다. 몇 가지 예를 들어보겠습니다.
반환 값의 일관성: 상황에 따라 서로 다른 종류의 데이터를 처리하는 방법을 고민하는 대신, 한 가지 종류의 데이터를 다루는 방법만 생각하면 됩니다.
추상화: 코드를 더 간단한 인터페이스 뒤로 숨기는 방법입니다. 잘 설계된 추상화라면 추상화가 어떻게 동작해야 하는지만 생각하면 되고, 내부 구현이 어떻게 되어 있는지 걱정할 필요가 없습니다.
테스트: 다른 영역을 작업하는 동안 실수로 코드를 망가뜨리는 것을 방지해 줍니다. 실수로 깨뜨린 코드는 테스트가 잡아줄 것이라고 가정할 수 있으므로, 현재 작업 중인 코드에만 집중하고 문제가 생긴 부분은 나중에 수정하면 됩니다.
테스트 주도 개발(TDD): 예상한 대로 동작하는 코드를 작성하는 데 도움을 줍니다. 테스트를 통과하는 가장 단순한 구현에만 집중하면 됩니다. 너무 단순해서 실제로 기대한 대로 동작하지 않더라도 테스트가 이를 잡아줄 것입니다.
이러한 기법들을 올바르게 활용하면 유용한 가정들을 세울 수 있습니다. 이러한 가정 덕분에 머릿속에 담아두어야 할 것들이 크게 줄어듭니다. 코드가 시스템 전체에 미칠 무수한 결과까지 일일이 걱정하지 않아도 되므로, 더 좋고 신뢰할 수 있는 코드를 작성할 수 있습니다.
반면에 이러한 기법을 잘못된 곳에 적용하면 실제로 확인해야 하는 코드를 숨겨버리게 됩니다. 코드가 숨겨지면 세운 가정이 때때로 틀리게 되고, 오히려 코드를 망가뜨릴 가능성이 더 커집니다!
바로 이 때문에 나쁜 추상화는 추상화가 아예 없는 것보다 더 나쁘며, '메서드 추출' 리팩토링을 마법처럼 반복한다고 해서 코드가 저절로 좋아지지 않는 것입니다.
올바른 리팩토링, 올바른 위치
명확한 코드란 자신이 무엇을 하는지 솔직하게 드러내는 코드입니다. 알 필요가 없는 것을 숨기는 것만큼이나, 알아야 할 것을 보여주는 것도 중요합니다. 리팩토링을 수행하거나 소프트웨어 모범 사례를 적용할 때는 최종적으로 만들어진 코드가 복잡성을 얼마나 잘 줄여주었는지 생각해 보세요. 코드의 나머지 부분이 좋은 단순화 가정을 세우도록 돕고 있는가요? 아니면 지나치게 단순한 인터페이스 뒤에 핵심 지식을 묻어두고 있는 것은 아닌가요?