Jonathan Blow의 강연을 떠올리게 됨
그는 생산성 관점에서 접근했음. Braid 개발 초기에는 거의 모든 걸 단순한 배열로 구현했고, 병목이 생길 때만 수정했음
“속도나 메모리보다 더 중요한 건, 프로그램 하나를 구현하는 데 걸리는 인생의 시간”이라는 말이 인상적이었음
게임은 수많은 유사 객체를 초당 60프레임 이상으로 반복 처리하므로, 단순한 배열 기반 구조가 합리적인 기본값임
게임 개발에서는 16ms 안에 프레임을 렌더링해야 하므로, 고정 크기 테이블과 선형 탐색이 흔한 패턴임. 동적 할당의 예측 불가능성을 피하기 위한 구조적 선택임
이 관점은 게임 외의 일반 개발에도 통함. 우리 모두는 마감과 비용 제약 속에서 일하므로, 엔지니어링 시간 자체가 비용임
다만 게임의 교훈을 일반 프로그래밍에 그대로 확장하는 건 조심해야 함. 게임은 재사용보다 특수 목적 코드 중심이고, 일반 소프트웨어는 데이터 중심임
나의 경우는 배열 대신 해시맵으로 시작하는 타입임
Rule 1을 진심으로 받아들이면, Rule 3~5는 자연스럽게 따라옴
병목을 예측할 수 없다는 전제를 인정하면, 단순한 코드 작성과 측정이 유일한 합리적 전략이 됨
실제로 가장 자주 실패하는 건 조기 최적화가 아니라 조기 추상화임. 필요하지 않은 유연성을 위해 복잡한 계층을 만들고, 그게 오히려 유지보수 비용을 키움
“추상화는 자연스럽게 등장해야지, 미리 설계하는 게 아니다”라는 말을 팀 내에서 자주 인용함
조기 추상화는 개발자 시간을 낭비시키고, 기술 부채를 늘리며, 버그 가능성을 높임. 종종 ‘미래의 문제를 대비한다’는 명목으로 생김
나는 성능보다 가독성과 유지보수성을 더 중시함. 그래서 나에겐 Rule 4가 근본이고, Rule 1은 그 결과임
복잡한 설정 파일을 과도하게 분리한 사례를 겪었음. 결국 단순한 YAML 8개 파일로 충분했음
90년대 새벽 2시에 데이터셋 검색 기능을 구현해야 했던 경험이 있음
피곤해서 일단 선형 탐색으로 구현하고 나중에 고치기로 했는데, 실제로는 4시간짜리 테스트 중 6초 차이밖에 안 났음
결국 수정은 했지만, 의미 있는 차이는 없었음
작은 n에서는 오히려 선형 탐색이 더 빠를 수도 있음
하지만 O(n²) 알고리즘은 “배포는 되지만, 결국 운영 중 폭발하는” 위험이 있음
Rule 5에 전적으로 공감함
어려운 문제일수록 데이터 구조와 API의 반복적 개선으로 해결됨. 구조가 잘 잡히면 제어 흐름은 자연스러워짐
LLM은 이런 구조적 사고에는 약함. 복잡한 제어 흐름은 잘 제안하지만, 조합 가능한 데이터 구조 설계는 잘 못함
내 경험상 Rule 5가 사실상 Rule 1임. “코드를 보여주면 혼란스럽지만, 데이터베이스 스키마를 보여주면 모든 게 명확해진다”는 말이 있음
분산 서비스에서는 Rule 5가 자주 무시됨. 여러 HTTP·DB 호출을 나누는 대신, 한 번의 호출로 처리할 수 있는 구조가 더 효율적임
나는 전자공학(E.E.) 출신으로, Rule 3 덕분에 커리어 초반엔 큰 문제 없었음
하지만 나중에 대규모 시스템으로 옮기면서 n이 커지고, 복잡도가 실제로 중요해졌음
Rob Pike가 말하던 시대의 ‘빅 아이언’은 지금의 임베디드 환경과 비슷했음
나는 Rule 3에 일부 반대함. 작은 입력에서는 상관없지만, 큰 입력에서는 빅오 성능이 중요함.
두 알고리즘이 구현 난이도가 비슷하다면, 큰 입력에서 빠른 쪽을 택함
관련 글: Less Than Quadratic
“fancy”의 의미를 문제 도메인에 맞게 해석해야 함. n이 작으면 단순한 접근이 낫지만, n이 크면 고급 알고리즘이 필수임
종종 사람들은 너무 단순한 O(n²) 접근을 택해 운영 중 폭발을 경험함
아버지는 Fortran 시절부터 lookup table을 즐겨 썼음. 반복 계산을 줄이는 고전적 최적화 방식임
Pike의 규칙들이 기존 격언보다 낫다고 생각함
“조기 최적화는 만악의 근원” 같은 문장은 맥락이 사라져 오해되기 쉬움
Pike의 버전은 명확하고 오용하기 어렵음
“Rule 5는 ‘멍청한 코드가 똑똑한 객체를 사용하게 하라’로 요약된다”는 옛 표현이 있었는데,
객체지향 시대에는 오히려 복잡성을 숨기는 잘못된 신념으로 변질되었음
역사적 사고의 연결 고리를 유지하는 건 중요함
“고전 격언의 정신적 클릭베이트”라는 표현은 일종의 재치 있는 비유로 느껴짐
10년 넘게 같은 코드베이스를 운영하면서 Pike의 규칙을 완전히 체화했음 KISS/DRY 원칙을 지키며, 유행 기술보다 검증된 기술을 유지하는 게 장기적으로 안정적이었음
실제로 우리 팀의 개발 원칙 문서는 Pike의 규칙과 거의 동일한 내용임
1990년대 초 C++ 시절, 이중 연결 리스트 대신 단순 배열 재할당으로 바꿨더니
버그가 사라졌을 뿐 아니라 오히려 더 빨라졌음. 비싼 연산을 덜 자주 수행하는 게 좋은 전략임을 배웠음
“측정 없이 튜닝하지 말라”는 규칙과 Jeff Dean의 Latency Numbers Every Programmer Should Know를 비교하면 흥미로움
Dean은 사전 지식으로 성능을 예측할 수 있다고 말함
결국 두 입장은 조화될 수 있음 — 설계 단계에서는 감각적으로 빠른 구조를 택하고, 구현 후에는 측정 기반으로 미세 조정해야 함
진짜 빠른 코드는 두 접근을 모두 사용함. 설계 단계에서 캐시 효율성을 고려하고, 이후 프로파일링으로 병목을 제거함
지연(latency) 수치는 알고리즘의 이론적 한계선을 알려줄 뿐, 실제 성능은 구현과 런타임 환경에 따라 달라짐
‘조기 최적화’가 금지하는 건 국소적 해킹 수준의 튜닝임. 전체 설계에서 속도를 고려하는 건 당연함
Rule 1과 2는 새로운 문제를 다룰 때만 절대적임
같은 도메인에서 반복적으로 시스템을 만들다 보면, 병목 지점을 미리 예측할 수 있음
경험 많은 개발자라면 설계 전부터 대략적인 성능 감을 가질 수 있음
나도 대부분의 경우 병목을 정확히 예측했음. 사전 성능 테스트로 접근 방식을 바꾼 적도 많음
하지만 30년간의 경험상, 병목이 생길 것 같은 감은 맞지만, 정확한 위치나 시점은 예측 불가임
“Rob Pike가 뭘 알겠냐”는 농담도 있었지만, 그는 Unix와 Go를 만든 사람임. 그의 규칙엔 이유가 있음
Hacker News 의견들
Jonathan Blow의 강연을 떠올리게 됨
그는 생산성 관점에서 접근했음. Braid 개발 초기에는 거의 모든 걸 단순한 배열로 구현했고, 병목이 생길 때만 수정했음
“속도나 메모리보다 더 중요한 건, 프로그램 하나를 구현하는 데 걸리는 인생의 시간”이라는 말이 인상적이었음
Rule 1을 진심으로 받아들이면, Rule 3~5는 자연스럽게 따라옴
병목을 예측할 수 없다는 전제를 인정하면, 단순한 코드 작성과 측정이 유일한 합리적 전략이 됨
실제로 가장 자주 실패하는 건 조기 최적화가 아니라 조기 추상화임. 필요하지 않은 유연성을 위해 복잡한 계층을 만들고, 그게 오히려 유지보수 비용을 키움
90년대 새벽 2시에 데이터셋 검색 기능을 구현해야 했던 경험이 있음
피곤해서 일단 선형 탐색으로 구현하고 나중에 고치기로 했는데, 실제로는 4시간짜리 테스트 중 6초 차이밖에 안 났음
결국 수정은 했지만, 의미 있는 차이는 없었음
Rule 5에 전적으로 공감함
어려운 문제일수록 데이터 구조와 API의 반복적 개선으로 해결됨. 구조가 잘 잡히면 제어 흐름은 자연스러워짐
LLM은 이런 구조적 사고에는 약함. 복잡한 제어 흐름은 잘 제안하지만, 조합 가능한 데이터 구조 설계는 잘 못함
나는 전자공학(E.E.) 출신으로, Rule 3 덕분에 커리어 초반엔 큰 문제 없었음
하지만 나중에 대규모 시스템으로 옮기면서 n이 커지고, 복잡도가 실제로 중요해졌음
Rob Pike가 말하던 시대의 ‘빅 아이언’은 지금의 임베디드 환경과 비슷했음
두 알고리즘이 구현 난이도가 비슷하다면, 큰 입력에서 빠른 쪽을 택함
관련 글: Less Than Quadratic
종종 사람들은 너무 단순한 O(n²) 접근을 택해 운영 중 폭발을 경험함
Pike의 규칙들이 기존 격언보다 낫다고 생각함
“조기 최적화는 만악의 근원” 같은 문장은 맥락이 사라져 오해되기 쉬움
Pike의 버전은 명확하고 오용하기 어렵음
“Rule 5는 ‘멍청한 코드가 똑똑한 객체를 사용하게 하라’로 요약된다”는 옛 표현이 있었는데,
객체지향 시대에는 오히려 복잡성을 숨기는 잘못된 신념으로 변질되었음
10년 넘게 같은 코드베이스를 운영하면서 Pike의 규칙을 완전히 체화했음
KISS/DRY 원칙을 지키며, 유행 기술보다 검증된 기술을 유지하는 게 장기적으로 안정적이었음
실제로 우리 팀의 개발 원칙 문서는 Pike의 규칙과 거의 동일한 내용임
1990년대 초 C++ 시절, 이중 연결 리스트 대신 단순 배열 재할당으로 바꿨더니
버그가 사라졌을 뿐 아니라 오히려 더 빨라졌음.
비싼 연산을 덜 자주 수행하는 게 좋은 전략임을 배웠음
“측정 없이 튜닝하지 말라”는 규칙과 Jeff Dean의 Latency Numbers Every Programmer Should Know를 비교하면 흥미로움
Dean은 사전 지식으로 성능을 예측할 수 있다고 말함
결국 두 입장은 조화될 수 있음 — 설계 단계에서는 감각적으로 빠른 구조를 택하고, 구현 후에는 측정 기반으로 미세 조정해야 함
Rule 1과 2는 새로운 문제를 다룰 때만 절대적임
같은 도메인에서 반복적으로 시스템을 만들다 보면, 병목 지점을 미리 예측할 수 있음
경험 많은 개발자라면 설계 전부터 대략적인 성능 감을 가질 수 있음