25 Programming Mistakes I Learned After 10 Years of Software Engineering
개요
10년 이상의 소프트웨어 엔지니어링 경험을 바탕으로 작성된 이 글은 복잡성 관리, 소통, 그리고 절충에 대한 실질적인 조언과 함께 경험에서 비롯된 25가지 일반적인 프로그래밍 실수를 다룬다.
주요 내용
* 코드 및 아키텍처 관련 실수:
* 조기 추상화 (Abstracting Too Early): 3-4개의 구체적인 사용 사례가 확보되기 전에 추상화를 시도하면 변경하기 어려운 경직된 추상화가 생성된다. 복제 코드가 잘못된 추상화보다 저렴하다.
* "영리한" 코드에 대한 집착 (Falling in Love with "Clever" Code): 이해하기 어렵거나 복잡한 코드는 유지보수의 부채가 된다. 명확하고 보편적인 코드를 작성하는 것이 중요하다.
* 의존성 비용 오해 (Misunderstanding the Cost of Dependencies): 외부 라이브러리 추가는 버그, 보안 취약점, 업데이트 문제 등 유지보수 비용을 발생시킨다. 꼭 필요한 부분만 직접 구현하는 것을 고려해야 한다.
* 없는 규모에 대한 과도한 아키텍처 설계 (Over-Architecting for Scale You Don't Have): 현재 규모보다 훨씬 큰 규모를 위해 시스템을 설계하면 개발 속도가 저하된다. 현재 규모에 맞춰 구축하되, 확장을 위한 유연성을 확보해야 한다.
* 실패 모드 및 엣지 케이스 무시 (Ignoring Failure Modes & Edge Cases): 정상 경로 외에 시스템 오류, API 응답 오류, 네트워크 연결 끊김 등의 상황을 고려하지 않는 것은 초보적인 실수는.
* 테스팅 및 리팩토링 관련 실수:
* 행동이 아닌 구현 세부 사항 테스트 (Testing Implementation Details Instead of Behavior): 내부 구현 변경으로 인해 사용자 행동이 변경되지 않았음에도 수많은 테스트가 실패하면 테스트가 구현에 너무 결합된 것이다.
* 테스트 없이 리팩토링 (Refactoring Without Tests): 견고한 통합 또는 회귀 테스트 없이 대규모 리팩토링을 시도하는 것은 무모한 행동이다.
* 100% 테스트 커버리지 목표 (Aiming for 100% Test Coverage): 100% 코드 커버리지는 종종 중요하지 않은 부분에 대한 테스트를 늘리고 실제 중요한 엣지 케이스를 간과하게 만드는 허영 지표다.
* "빅뱅" 재작성 오류 (The "Big Bang" Rewrite Fallacy): 기존 코드를 완전히 버리고 처음부터 새로 작성하는 것은 거의 항상 실패한다. 점진적인 리팩토링(예: Strangler Fig 패턴)이 더 효과적이다.
* 커뮤니케이션 및 팀 역학 관련 실수:
* 침묵 속 작업 및 "영웅심리" (Silent Work & "Heroing"): 문제를 혼자 해결하려 고립되는 것은 비효율적이다. 몇 시간 이상 막혔다면 팀에 알리고 도움을 요청해야 한다.
* 코드 리뷰를 자존심 싸움으로 취급 (Treating Code Reviews as an Ego Battle): 코드 리뷰는 코드베이스 보호와 지식 공유를 위한 것이지, 누가 더 똑똑한지 증명하는 자리가 아니다.
* 제품 및 디자인 팀의 조기 참여 부족 (Not Involving Product and Design Early): 비즈니스 맥락을 이해하지 못하고 모호한 요구사항만으로 코드를 작성하면 재작업이 발생한다.
* 기술 전문 용어 과다 사용 (Over-Communicating with Tech Jargon): 비기술 직군에게 기술적인 문제를 전문 용어를 사용해 설명하면 오해가 발생한다. 비즈니스 지표(위험, 지연, 신뢰성, 비용)로 번역하여 소통해야 한다.
* 디버깅 및 운영 관련 실수:
* 추측 기반 디버깅 (Debugging by Guesswork): 프로덕션 오류 발생 시 추측으로 해결책을 적용하는 것은 비효과적이다. 가설을 세우고 로그, 메트릭을 확인하며 근본 원인을 체계적으로 파악해야 한다.
* 로그를 나중으로 미루기 (Treating Logs as an Afterthought): 로그는 오류뿐 아니라 애플리케이션 실행 과정을 기록한다. 부실한 로깅은 문제 해결을 어렵게 만든다.
* 로컬 환경과 프로덕션 환경의 차이 간과 (Assuming Local Environment Equals Production): "내 컴퓨터에서는 잘 돌아간다"는 말은 더 이상 유효하지 않다. 프로덕션 환경의 특성을 고려하여 설계해야 한다.
* 데이터베이스 성능 문제 무시 (Ignoring Database Performance Until It Sinks You): N+1 쿼리나 인덱스 누락 같은 문제는 소규모 데이터에서는 드러나지 않다가 프로덕션에서 시스템 장애를 일으킬 수 있다.
* 마인드셋 및 경력 성장 관련 실수:
* 유행 기반 도구 선택 (Choosing Tools Based on Hype): 소셜 미디어에서 유행하는 최신 기술을 맹목적으로 도입하는 것은 실수다. 핵심 로직에는 안정적이고 검증된 기술을 사용해야 한다.
* 코드에 대한 매몰 비용 오류 (Sunk Cost Fallacy with Code): 많은 시간을 들여 작성한 코드를 더 나은 대안이 나타나거나 요구사항이 변경되어도 계속 유지하는 것은 위험하다.
* 문서화를 귀찮은 일로 여기기 (Treating Documentation as a Chore): 명확하고 간결한 문서(ADR, 온보딩 가이드 등)는 프로젝트의 유산이 된다.
* 비즈니스 도메인 이해 부족 (Not Understanding the Business Domain): 제품의 핵심 목표와 고객의 어려움을 이해하지 못하면 단순한 작업 실행자에 머무르게 된다.
* 단기 최적화만 추구 (Optimizing for the Short Term Only): 마감일을 맞추기 위해 기술 부채를 쌓는 것은 장기적인 생산성을 저해한다.
* 간단한 CRUD 앱의 과도한 엔지니어링 (Over-Engineering Simple CRUD Apps): 모든 애플리케이션에 복잡한 아키텍처가 필요한 것은 아니다. 문제의 복잡성에 맞춰 솔루션의 복잡성을 결정해야 한다.
* 소프트웨어가 사람을 위해 만들어진다는 사실 망각 (Forgetting That Software Is Built for Humans): 최종 사용자와 코드를 읽을 동료 모두를 고려하는 것이 중요하다.
* 학습의 종료를 믿는 것 (Believing You Ever Finish Learning): 소프트웨어 엔지니어링을 마스터했다고 생각하는 순간 뒤처지기 시작한다. 끊임없이 변화하는 기술 환경과 문제 해결 방식에 대한 관점을 발전시켜야 한다.
시사점
이러한 실수를 인식하고 피하려는 노력은 소프트웨어 엔지니어로서의 성장을 촉진하고, 더 나은 품질의 소프트웨어를 더 효율적으로 개발하는 데 기여한다. 모든 시니어 엔지니어들도 이러한 실수를 경험하며 학습하므로, 실수로부터 빠르게 피드백 루프를 구축하고 팀과 지식을 공유하는 것이 중요하다.
댓글
GitHub Discussions