개발다운 개발에 대해...

어쩌다가 2년 반 전에 내가 했던 프로젝트의 코드를 보게 되었다. 코드가 너무 구렸다.
그때도 나는 나름 설계나 코드 품질에 신경을 많이 썼었는데, 지금 돌이켜보면 역량이 많이 부족했었던 것 같다.
내가 개발다운 개발을 한 지가 얼마나 됐을지에 대해 생각해보았다. 길게봐도 반년이 채 안되는 것 같고, 깐깐하게 보면 아직도 많이 부족한 것 같다.
이제서야 슬슬 뭘 좀 알아가고 개발다운 개발을 시작하는 단계라고 생각이 들었다.

아무튼 그래서 내가 생각하는 "개발다운 개발" 의 기준에 대해 써보려고 한다.
물론, 지극히 개인적인 생각이며 각자가 일하는 도메인과 상황에 따라 매우 다를 것임을 인정한다.

1. 프로그래밍 언어와 Good Practice 들에 대한 깊은 이해.

"언어는 도구에 불과하다" 라는 말이 있다. 그냥 문장 자체적으로만 보면 물론 맞는 말이다.
하지만, "불과하다" 라고 표현하기에는 언어는 너무나도 중요한 도구이다. 그리고 정말 공부를 많이 해야하는 도구이다.
언어는 사고를 지배하고, 언어를 공부하고 이해한다는 것은 생각하는 법과 철학을 배우는 것이다.
오랜 시간동안 전 세계적으로 여러 프로젝트들이 개발/연구되고 다양한 사람들이 토론/합의하면서 발전한 소프트웨어 기술과 패러다임들이 프로그래밍 언어에 그대로 녹아들어간다.
즉, 언어를 깊게 공부함으로서 소프트웨어 개발에 대한 철학과 통찰, 패러다임, 트렌드를 알 수 있다.
그리고 언어를 깊게 공부한다는 것은 그 언어에서의 Good Practice 들을 공부하고 숙달하는 것을 포함한다.
언어의 feature spec 이 도구라고 한다면, Good Practice 는 도구를 사용하는 방법이다.
단순히 언어의 문법을 익히고 라이브러리에서 어떤 기능을 제공하는 지 아는 것이 중요한게 아니라, 어떤 상황에서 어떻게 사용해야하는 지에 대한 Good Practice 를 제대로 아는게 핵심이다.

내 개인적 기준에서, 이 부분에 대해서 개발다운 개발을 하기 위한 '최소한의' 조건은 아래와 같다.
  • 자신이 주력으로 사용하는 언어에 대해 최신 버전(표준)과 커뮤니티 동향을 지속적으로 tracking 해야 한다.
  • 자신이 하는 프로젝트에서 사용가능한 것들중 가장 효율적이고 합리적인 (가능한 최신의) 언어/컴파일러 버전을 사용해야 한다.
  • 자신이 하는 프로젝트에서 사용하는 언어 버전과 거기에서의 Good Practice 들을 제대로 이해하고 있어야한다.

2. 자동화된 유닛테스트 및 테스트 고도화.

소프트웨어 개발에 있어서 가장 중요한 것중에 하나가 테스트라고 생각한다.
좋은 테스트의 조건은 두가지라고 생각한다.
  • 자동화된 테스트. 수동으로 테스트할 필요없이 언제든지 소프트웨어의 결함여부를 자동으로 테스트할 수 있어야한다.
  • 가능한 많은 부분을 커버할 수 있어야한다. 즉, 테스트의 빈틈이 최대한 적어야한다.
이 두가지를 만족하기 위한 최선의 방법이 "자동화된 유닛테스트" 이다. 클래스/모듈들 각각을 별개로 테스트할 수 있어야 테스트의 빈틈을 최소화할 수 있다. 그리고 테스트가 자동화되어야지만, 매번 테스트하기 위해 낭비되는 리소스를 막을 수 있고 테스트를 수시로 수행할 수 있다. 자동화된 유닛테스트가 잘 작성되어 있어야지만, 지속적인 리펙토링이 가능해지고 코드 품질을 높게 유지할 수 있다. 자동화된 유닛테스트는 CI와 연동하고 code coverage report 를 뽑음으로서 더욱 빛을 발할 수 있다.
그러나, 이것은 이상적인 이야기이고 현실적으로 힘든 경우들이 있다. 테스트를 자동화하는 것이 불가능하거나 너무 까다롭다던지, 테스트 단위를 너무 잘게 쪼개는 것이 현실적으로 비효율적인 경우들이 있다. 이런 경우들에 대해서는 물론 현실적인 타협이 필요하다.

자동화된 유닛테스트만으로 소프트웨어의 정상동작 여부를 완벽하게 파악할 순 없다. Integration Test 가 분명히 필요하고, Performance Test 나 블랙박스 테스트등 다양한 관점과 방법으로 테스트를 수행해야한다. 평소 개발 단계에서는 유닛테스트만 수행하고, 릴리즈 시에 블랙박스 테스트를 수행하는 등 시점에 따라 수행해야할 테스트가 달라져야할 수도 있다.
어찌됐든 테스트에 대해서 심도있게 고민하고 고도화하는 것이 소프트웨어 품질을 높이고 전반적인 개발/릴리즈 프로세스를 빠르게 하는데 핵심적인 역할을 한다고 생각한다.
따라서 개발다운 개발을 하기 위해선 테스트를 중요하게 여기고 심혈을 기울여야만 한다.

3. 지속적인 리펙토링.

프로젝트가 진행되면서 요구사항은 끊임없이 변경되고 추가된다. 그러면서 코드베이스의 기존 설계는 점점 무너지고, 코드는 점점 읽기어렵고 유지보수하기 어려워진다. 그러면서 점점 버그가 많아지고, 새로운 기능을 추가하는 것이 어려워진다. 새로운 개발자가 합류했을 때에도 코드베이스를 파악하는데 시간이 오래걸리고, 점점 주인을 잃은 코드들이 많아진다. 코드가 스파게티처럼 꼬여있고 툭하면 사이드이펙트가 생기기때문에, 개발하기가 싫어진다.
이러한 비극을 막기위해서는 지속적인 리펙토링이 필수적이다. 요구사항과 코드의 변경에 대해 항상 리펙토링을 수행해서 코드와 설계를 깔끔하게 유지해야한다. 그리고 이러한 리펙토링을 지속적이고 수시로 수행하기 위해서는 2번의 자동화된 유닛테스트와 테스트 고도화가 필수 전제조건이다.
리펙토링과 테스트코드는 떼어놓을 수 없는 관계라고 생각한다. 리펙토링을 하기 위해서는 테스트코드가 필요하고, 테스트코드를 짜기 위해서는 코드가 testable 해지도록 리펙토링해야만 한다. 코드베이스가 리펙토링과 테스트코드 없이 오랜 기간동안 개발/유지보수 되는 경우, 나중에 가서는 리펙토링과 테스트코드 작성 두 가지 모두 너무 까다로워져서 어찌할 수 없는 상황이 되는 경우를 경험해봤다.

4. 문서화.

문서화가 빈약한 경우, 무언가 개발/업무를 할 때 계속해서 동료 개발자들에게 물어보거나 직접 다시 조사해봐야한다. 그리고 새로운 개발자가 합류할 때, 불필요한 시행착오가 많아지고 일일히 구두로 알려줘야한다. 따라서 상당히 많은 리소스가 낭비되고, 여러 개발자가 합류하고 떠나는 과정에서 버려지는 지식들이 생기게 된다.
따라서, 문서화에 신경을 쓰는 것은 매우 중요하다. 그러나, 그렇다고 해서 코드베이스와 분리된 별도의 문서가 많아지는 것은 좋지 않다. 별도로 문서화해야하는 것들을 최소화하는 것이 좋다. 최대한 많은 개발/업무 프로세스를 자동화해서 일일히 머릿속에 알고 있지 않아도 되도록 하고, 코드는 그 자체로 self-documenting 하도록 작성해야한다. 테스트코드 또한 일종의 요구사항 문서의 역할을 수행한다고 생각한다. 그리고 세계적으로 표준화되있거나 널리 알려진 것들을 채택하고 사용하는 것이 문서화 부담을 줄여준다고 생각한다.

코드에 직접적으로 드러나지 않는 동기, 작성이유 등은 반드시 문서화해야한다. 특히, 클래스/함수의 thread-safety가 제대로 문서화 되어있지 않은 경우, 찾기 힘든 하이젠버그가 발생할 가능성이 높아지고, thread-safety를 파악하기 위해 코드를 상세하게 분석해야만 하는 경우가 생긴다.
코드에 관련된 문서화는 별도의 문서를 만들기보다 코드 주석에 doxygen 같은 스타일로 문서화하는 것이 좋다.

5. 코딩 컨벤션 확립. 정적분석 툴 도입. 코드 리뷰. 효율적인 개발 프로세스.

여러 개발자가 같은 코드베이스에서 작업하기 때문에, 개발자들의 코딩하는 스타일이 최대한 일치하는 것이 좋고 개발자들이 생산해내는 코드 품질이 상향 평준화되는 것이 좋다.
이것을 위해 코딩 컨벤션이 필요하다. 코딩 컨벤션은 세계적으로 통용되는 Good Practice 들을 기반으로 해야하며, 프로젝트의 도메인과 상황, 개발자들의 기술수준을 고려해서 확립되어야 한다. 그리고 최대한 단순하고 분량이 적아야 좋다고 생각한다.
그러나 코딩 컨벤션이 있더라도 개발자들이 지키지 않으면 무용지물이다. 따라서 개발자들이 코딩 컨벤션을 지키도록 강제하기 위해, 정적 분석 툴을 사용하는 것이 좋다. 정적 분석 툴은 CI에 연동되어 사용함으로서, 개발자들의 실수를 미연에 방지하고 Good Practice 를 지키도록 강제할 수 있다.
그러나, 코딩 컨벤션과 정적분석 툴로는 코드 품질을 관리하는 데 한계가 있다. 결국에 개발자 상호간의 코드 리뷰가 필요하다고 생각한다. 코드 리뷰는 개발자들이 서로 각자의 코딩 스타일을 맞춰가고 코드 품질을 상향 평준화하는 데 큰 도움이 된다.

그리고 위에서 언급했던 것들을 포함해서 효율적이고 적합한 개발 프로세스와 관련 툴들을 갖추는 것이 중요하다. 애자일 패러다임, XP 실행관례들부터 해서 CI, 이슈트래킹, 협업, 외부와의 소통등을 어떻게 효율적으로 할 것 인지에 대해 고민하고 개선해야한다.

6. 도메인과 비지니스에 대한 이해.

아무도 필요로 하지 않는 기능을 아무리 잘 만들어봐야 의미가 없다.
현재 자기가 개발하고 있는 소프트웨어의 도메인에 대해 공부하고, 회사의 비지니스 목표와 가치를 이해해야한다.
전문 경영인들이 따로 있더라도, 결국 소프트웨어를 작성하는 실무자는 개발자이기 때문에 개발자가 비지니스에도 관심을 가져야 유의미한 소프트웨어가 나온다고 생각한다. 정말 회사와 비지니스에 도움이 되는 개발을 해야한다.
이렇게 하기위해서는 회사도 비지니스에 대한 의사결정과 정보를 투명하게 공개하고 접근성을 높여줘야한다.

또한 주어진 요구사항을 잘 분석해야하며, 오버엔지니어링을 하지 않도록 조심해야한다.
1년 반전까지만 해도 나는 오버엔지니어링에 심취해 있었다. 오버엔지니어링은 기술적인 호기심을 채우고 실력을 쌓는 측면에서는 좋지만, 진정한 프로페셔널로서의 모습은 아니다. 주어진 요구사항을 만족하는 최소한의 코드를 작성하는 것이 좋은 개발이라고 생각한다.

7. 좋은 개발 문화 만들기 및 뛰어난 인재들과 함께하기.

마지막은 개발다운 개발의 기준이라기 보다, 개발다운 개발의 기준을 만족하기 위한 방법이다.
결국에 개발다운 개발을 하기 위해서는 나 자신 뿐만 아니라 주변 개발자들도 개발다운 개발을 해야만 한다.
그러기 위해서는 결국 뛰어난 인재들과 함께 일해야한다. 그리고 계속해서 공부하고 고민하고 토론하는 좋은 문화를 만들어야한다. 서로 의견을 개진하고 잘못된 점을 말하고 주도적으로 행동하는 데에 거리낌이 없어야한다.
좋은 개발 문화안에서 좋은 인재들이 모이면, 개발다운 개발이 저절로 될 것이라고 생각한다.



개발다운 개발에 대한 나의 생각을 써보았다.
나는 아직 도메인지식과 비지니스에 대한 이해가 부족한 것 같고, 시간이 지날수록 이게 얼마나 중요한지 더더욱 느끼는 것 같다. 요구사항에 대해 잘 파악하고 분석하는 것이 가장 중요한 과정이라고 생각한다.
아무튼 계속해서 열심히 해야겠다~

댓글

댓글 쓰기