11P by GN⁺ 2일전 | ★ favorite | 댓글 1개
  • 1982년 애플의 Lisa 소프트웨어 팀이 소프트웨어 출시를 위해 각 개발자의 주별 코드 라인 수를 트래킹하는 정책을 도입함
  • Bill Atkinson은 코드 라인 수는 소프트웨어 생산성의 잘못된 척도라는 의견을 보임
  • 그는 Quickdraw의 리전 계산 엔진을 완전히 재작성하며 약 2,000줄의 코드를 줄이고 성능을 6배 향상시킴
  • Atkinson은 코드 수를 보고하는 관리 양식에 -2000을 기재함
  • 결국 관리자는 Bill에게 양식 제출을 더 이상 요구하지 않음

1982년의 Lisa 소프트웨어 팀과 코드 라인 수 트래킹 정책

  • 1982년 초, Lisa 소프트웨어 팀은 향후 6개월 내 소프트웨어 출시를 목표로 집중을 시작함
  • 일부 관리자는 각 엔지니어가 매주 작성한 코드 줄 수를 추적하는 것이 발전을 도울 거라고 판단함
  • 이를 위해 매주 금요일마다 엔지니어가 작성한 코드 라인 수를 기록해서 제출하는 을 도입함

Bill Atkinson의 생산성 기준에 대한 견해

  • Quickdraw와 사용자 인터페이스를 설계한 Bill Atkinson은 코드 라인 수가 소프트웨어 생산성의 기준이 될 수 없다고 생각함
  • 그는 프로그램을 최대한 작고 빠르게 만드는 것이 목표임을 강조함
  • 코드 라인 수 측정은 오히려 지저분하고 비효율적인 코드를 조장할 수 있다는 문제점 인식이 있음

Quickdraw 리전 엔진 리팩터링 및 최적화

  • Atkinson은 최근에 Quickdraw의 리전 계산 엔진을 더 단순하고 범용적인 알고리듬으로 완전히 재작성함
  • 최적화 결과, 리전 연산 속도를 6배까지 향상시킴
  • 이 과정에서 2,000줄에 해당하는 코드도 자연스럽게 줄어듦

-2000줄 코드 작성 보고와 관리자의 반응

  • 첫 주 관리 폼을 작성하던 중, Atkinson은 코드 라인 수 칸에 -2000이라고 적음
  • 관리자들이 이 숫자에 어떻게 반응했는지는 명확하지 않음
  • 몇 주 후, Bill에게 더 이상 폼을 제출하지 말라고 했으며, 그는 이를 기쁘게 받아들였음
Hacker News 의견
  • 내가 최고의 커밋으로 기억하는 것은 약 6만 줄의 코드를 삭제하고, 모든 상태를 메모리에 저장하던 “서버” 전체를 가벼운 5천 줄 정도의 로직으로 대체한 경험

    • 이 코드는 다른 서비스에 자연스럽게 통합할 수 있을 만큼 충분히 가볍고 메모리 상태도 필요 없었다는 점에서 알고리즘적 쾌거라는 생각
    • 특정 트리를 대상으로 하는 가이드된 하위 그래프 동형성 문제를 해결할 수 있다는 걸 알아냈고, 이 덕분에 일반적인 방향성 이중 그래프를 한 번 순회하면서 출발한 루트부터의 경로만 소량 스택으로 추적해 출력 그래프(트리)를 만들 수 있었던 과정
    • “-60,000 줄 커밋”은 정말 잊지 못할 순간이고, 그 이후로 이만큼 알고리즘적으로 인상적인 일을 해본 적이 없는 아쉬운 감상
      • 나는 업무 환경에서 스크립팅을 많이 하며 프로그래밍의 몇몇 부분에 능숙하다고 느끼는 취미 프로그래머인데, 이런 이야기를 들을 때마다 내가 모르는 세계가 정말 크고, 평생 배워도 모자라겠다는 겸손함을 다시 느끼는 경험
      • 더 많은 맥락을 듣고 싶음. 상태를 저장하던 프로그램을 무상태로 바꾸는 기술이 마법처럼 느껴져서 꼭 배워보고 싶다는 호기심
      • 내가 그래프 이론과 알고리즘에 배경이 있는 수학자인데, 이런 종류의 실제 업무에 내 기술이 적용될 수 있을지 궁금증. 혹시 더 자세한 내용을 공유해줄 수 있는지 구체적으로 질의
      • 목표 그래프가 트리라는 사실은 별로 중요하지 않은 것 같다고 생각. 실제 "가이드된(guided)" 부분이 단일 순회를 가능하게 만든다는 점이 포인트라고 봄
        • 원래 그래프에서 특정 노드에서 출발해, 동형성이 존재한다면 대상 트리의 루트도 반드시 해당 노드와 일치해야 한다고 가정
        • 원래 그래프를 대상 트리의 패턴에 따라 순회하면서 불일치 시 false, 모두 일치 시 true라는 식의 문제 해석. 트리가 아니더라도 시작점을 명확히 지정하면 이 방식이 어떤 하위 그래프에도 적용 가능하다는 추론
      • 요즘 “이진 트리를 뒤집으라” 같은 코딩 면접 문제의 원조가 바로 이런 유형의 프로그래머 때문일지도 모른다는 유머
        • 그래프 이론이 궁금한데 용어가 어렵다는 평범한 개발자를 위한 쉬운 설명을 요청
  • 대학 시절에 신입생들이 좋은 코드를 작성할 수 있다는 경영 방침의 회사를 위해 일했는데, 결국 그들은 증명하지 못한 실패 사례

    • 코드 내에서 버그를 고치고도 동일 버그가 계속 나오길래 분석했더니, 기존 함수에 파라미터를 추가하지 않고 복사본을 만들어 약간씩만 수정하는 반복. 그 결과 코드베이스의 3/4 이상(수천 줄의 Turbo Pascal)을 삭제한 경험
    • 프로젝트의 고객은 Energy 부서였고, 핵물질 재고를 관리하는 프로그램이라 불면증의 밤을 겪은 기억
      • 기존 코드 복사의 장점으로는, 기존 코드의 안정성을 해치지 않고, 관리자의 ‘기여도’ 메트릭까지 챙길 수 있다는 이득이 있다고 풍자적으로 언급. 되돌리기(revert)도 복사본만 지우면 된다는 농담
      • 우리 팀에도 이런 코드 중복을 자주 하는 동료가 있는데, 급한 요구나 목소리 큰 사람들을 위해 빠르게 결과를 내기 위한 습관이라고 봄. 사실 공유 함수 리팩토링과 충분한 테스트가 필요한데 시간을 투자하지 않으려는 근본 문제가 원인
      • 과거 내가 맡았던 외주 개발자들도 비슷한 습관을 보여, 혼란이 발생할 수 있다고 지적했을 때 “그럴 땐 Ctrl+F 사용하면 돼요”라고 대답하던 경험
      • 혹시 위 사례가 Blacksburg 지역에서 일어난 일인지 궁금증
      • 내 경험도 비슷한데, 동남아 지역 여러 국가에 거의 동일한 포털을 운영하는 회사에 근무함. 각각의 포털 소스가 별도의 Git 저장소에 보관됐고, 모든 포털에 공통 적용이 필요한 기능이나 버그 수정을 소스코드 여러 복사본에 일일이 수작업으로 백포팅해야 했다는 당혹스러운 경험
        • “단일 저장소에 다 넣고, 기능 플래그로 포털별 커스터마이징이 불가능하냐” 물었지만 불가능하다고 거절당함
        • 결국 두세 달 만에 4~5개의 포털 코드를 하나의 저장소로 합치고, 기능 플래그와 프레임워크 업그레이드를 적용해서 배포도 매끄럽게 마무리. 이제는 모든 포털에 동시 버그 수정이 가능해서, 반복되는 수작업의 고통에서 벗어난 해방감
  • 관련 주제로, “-2000줄 코드”를 다룬 해커뉴스 인기 스레드들을 링크와 같이 정리해 둠

    • 주기적으로 과거의 명작 글이 재게시(repost)되는 것이 신입 이용자와 기존 이용자 모두에게 유익한 전통이라고 짚음
      • 나는 “-2k lines of code”라면 자동으로 추천(vote)하는 단순한 인간임을 자처
        • 생산성 측정 기준을 한 축의 메트릭으로 관리하려는 클라이언트에게 Atkinson의 사례를 자주 이야기함. 진정한 생산성 지표는 효용성(utility) 기준이어야 하며, 이를 진정으로 정량화할 수 있다면 노벨 경제학상 후보에 오를 수 있다고 생각
  • 내가 맡은 웹 UI 프로젝트는 25만 줄 코드였고, 백엔드 제외 수치

    • 이전 개발자는 똑똑했지만 JS는 처음이었고, 모든 상태를 DOM의 커스텀 속성에 저장, addEventListener로 도배된 구조. 나는 “수도승에게 JavaScript 책 한 권과 독방 10년을 주면 이런 코드가 나올 것”이라는 농담을 할 정도
    • 몇 달간 웹 컴포넌트로 구조 변환하며 5만 줄을 제거했고, 전체 재작성에 착수해 현재는 80% 정도 동일 기능까지만 도달했는데 전체 코드가 경량 1만7천 줄 수준(Vue/pinia 등 라이브러리 미포함)
    • 곧 20만 줄 이상을 삭제하게 될 예정인데, 그것보다 더한 경험은 앞으로도 없을 듯한 은퇴 욕구
      • 나도 비슷한 경험이 있는데, 원작자가 주니어나 다름없던 실력인데 회사 창업자이자 생산성만큼은 뛰어났던 분. 팀 작업이나 타인의 코드 협업 경험 없이 개발하면서 상상 가능한 모든 코드 냄새가 다 들어가 있었던 구조
        • 함수 하나에 수천 줄, 중첩 switch/case/if/else/삼항 연산 10단계, SQL문과 JS/HTML/JS삽입형 HTML이 혼재, 자동화 테스트는 전무했던 PHP/Dojo 시대의 프런트엔드 구조라는 설명
      • “80% 기능만 구현된 경량 코드”라는 설명 자체가 이런 비교의 맹점을 보여준다고 지적. 전체 기능의 일부만 구현된 상태이면 원래 코드만큼 많은 줄이 필요 없다는 점
  • Dilbert 만화에서 무한 보상 구조의 삽화가 있는데, 딜버트 상사가 버그 한 개를 고치면 금전적 보상을 약속하자 Wally가 “오늘은 나도 미니밴 한 대는 코딩해야지!”라는 말을 내뱉음

    • 이런 상황을 “Perverse incentive(역설적 유인)”라고 하는데, 참고 링크로 설명
    • 내 매니저도 이 만화( 이미지 )를 휴게실 벽에 붙여 두었음
    • ‘미니밴’이 무슨 의미냐는 현실적인 궁금증이 등장
  • dotnet/runtime 저장소에서 6만4천 줄을 삭제한 실제 사례를 공유

    • 기존 C# + WinRT interop 지원을 빌트인에서 소스 생성 툴로 대체해, 한번에 확실하게 바꾸는 결단이 필요했던 구조 변경. PR 링크 참고
  • LLM이 개발자 생산성을 얼마나 높였다는 통계를 볼 때마다 이 고전 이야기가 떠오름

    • AI가 코드를 삭제하는 데도 꽤 잘 한다는 반론과 함께, Cursor 관련 커뮤니티에 “AI가 다 삭제했다”는 재밌는 사례 공유
    • 요즘엔 “우리 신규 코드의 X%를 AI가 작성한다!”가 산업계의 즐겨 쓰는 캐치프레이즈라는 언급
    • 새로운 원자력 발전소 건설 및 유지 비용까지 포함한다면, 개발자 생산성 수치가 얼마나 비현실적으로 과장되는지 풍자
  • 나는 CS 전공이 아니고, 일하면서 실전으로 익힌 지식으로 일하는 입장

    • 우리가 하는 프로젝트는 라이브 오브젝트를 사람이 읽기 쉽게 재구성하는 게 목표
      • 최종 표현은 매우 복잡한 여러 타입을 요구하고, 초기 표현은 비교적 단순함
      • 비슷한 데이터 노드들이 있을 경우, 비교해서 결합(즉, 메서드로 추출하고 파라미터를 찾아내는 과정)을 거쳐 가독성을 개선해야 했음
        • 초창기엔 최종 타입으로 변환 먼저 하고 비교를 하다 보니, 타입 조합이 폭발적으로 늘어 관리가 거의 불가능해졌고, 수년간 엔지니어들이 구조를 이해하지 못할 정도의 복잡성까지 달성
      • 이후 hashmap 기반 접근법을 알게 되면서, 동일한 뼈대의 노드를 해시값으로 구분해서 비교 및 결합 후에 최종 타입으로 변환하는 2단계 구조를 적용
      • 타입 현황이 아닌 데이터 중심 추상화로 바꾼 덕에, 엉뚱한 클래스 계층 구조도 단순 속성으로 쉽게 관리 가능
      • 요약하자면 멍청한 다단계 디컴파일러 구조지만, 처리 속도와 가독성이 크게 개선된 경험. 상황에 따라 맞는 은총알은 없지만, 우리에겐 ‘타입’이 핵심 문제였고 이런 해결법이 큰 도움이 되었던 프로젝트
  • 연말 인사평가를 앞두고 사내 모놀리식 저장소의 내 통계를 보니 코드 순감 기준으로 마이너스인 사람이 되었음을 발견

    • API 코드와 타입의 자동생성 코드 제거, 구버전 API 퇴출 등의 이유였지만, 매일 출근해 코드 삭제만 하는 기분이 묘하게 유쾌했던 경험
  • 오래 전 내가 큰 프로젝트에서 PL들이 개발자별 버그 개수(고친 버그, 유발한 버그)를 오프라인으로 수기 작성·벽에 게시하던 참담한 KPI 사례에 충격

    • 나는 연관 프로젝트라 피해갔지만, 한 동료는 “덴마크 국기에서 십자가 부분만 잘라 빨간 공산국기 같은 배치로 꿰매 돌려주고” 관료의 ‘작가 명단’에서 퇴출 당했던 Lars von Trier 감독의 일화에서 영감을 받아, 자신의 버그 카운트 줄을 잘라내 다시 붙여 공개 반발. 다음날 이 명단은 영영 사라져 내게는 소중한 회상
      • “나는 이 리스트에 속하고 싶지 않으니까요!”라는 동료의 단순하고 직설적인 대답이 이 모든 상황을 잘 요약
      • 국기와 리스트를 어떻게 시각화했는지 상상하기가 어렵다는 실제적인 어려움까지 함께 공유