예전 팀 리드가 복붙 코드가 항상 나쁜 건 아니라는 꽤 강한 생각을 갖고 있었음
DRY 원칙 때문에 본능적으로는 틀렸거나 논쟁적으로 들렸지만, 그는 매우 실용적인 사람이었고 주로 큰 테스트 코드베이스에 이 원칙을 적용했음
똑똑한 공용 인터페이스를 억지로 만들기보다, 단순하지만 더 크고 중복이 많은 코드베이스가 유지보수하기 쉬울 수 있다는 논리였음
요즘 LLM을 쓰면서 같은 생각으로 돌아가고 있는데, 이제는 더 중요한 소프트웨어 부분에도 적용하게 됨
코드 생성은 빠르고, LLM도 단순하지만 중복이 많은 코드베이스에서 더 잘 맞힐 가능성이 있어 보임
특히 테스트에서는 완전히 WET, 즉 “타이핑을 즐기자” 쪽임
중복을 줄이려고 테스트에 추상화를 너무 많이 넣으면 테스트를 이해하기 어려워지고, 미묘하게 틀릴 위험도 있음
더 나쁜 건 테스트 대상 코드의 추상화를 재사용하면, 테스트도 그 코드와 같은 방식으로 틀릴 수 있다는 점임
또 애플리케이션 코드와 달리 테스트는 사실상 공짜로 “합성”됨
테스트 하네스를 심각하게 망치지 않았다면 테스트를 마음대로 추가하거나 삭제해도 다른 테스트에 영향이 없고, 통합 마찰이 없으니 중복을 피해야 할 이유도 하나 줄어듦
Andrew Kelley가 코딩하는 걸 보면서 좋은 교훈을 얻었음
라이브 코딩을 공유해줘서 고맙게 생각함
기억이 맞다면 뭔가를 시작할 때 자기가 만들려는 것과 가장 비슷한 코드를 찾아 통째로 복사한 뒤 거기서 수정하는 일이 자주 있었음
“둘이 공유하는 추상화가 뭔지 앉아서 한참 생각하지 않는다고?” 싶었는데, 그냥 복붙하며 밀고 나가고 나보다 훨씬 생산적이었음
최근 Bun에 병합된 PR 150개 중 108개가 메모리 안전성 관련이었고, 오류 경로에서 정리를 빠뜨리거나 use-after-free, 초기화되지 않은 읽기, 범위 밖 접근, 재진입 같은 문제였음
그중 75개는 소멸자, 이동 의미론, 빌림 검사기가 있는 언어라면 컴파일되지 않았을 것이라고 함
배포하는 PR 세 개 중 하나가 “오류 경로에서 해제를 깜박함”인 셈임
108개 중 약 88개는 Zig에 있고, C++ 쪽 약 14개는 대부분 참조 순환과 GC 동시성 경쟁처럼 어떤 언어에서도 남는 잔여 범주라 함
그래서 Zig→Rust 차이는 실제이며, Zig 버그는 정확히 소멸자와 소유권으로 고칠 수 있는 종류이고 C++ 쪽은 이미 바닥에 가까움
더 강한 컴파일 타임 보장이 없으면 이건 계속 고양이와 쥐 게임으로 남음
제안은 가장 큰 버그 범주를 계속 개별 수정하지 말고 구조적으로 제거하자는 것임
– bun/docs/rust-rewrite-plan.md at claude/phase-a-port · oven-sh/bun · GitHub
“나머지 5%의 경우에는 comptime이 없으면 괴롭고, 동등한 결과에 reliably 도달하는 유일한 방법은 코드 생성”이라는 부분은 저자가 무슨 뜻인지 명확하지 않음 절차적 매크로에 대해 아무 말도 하지 않기 때문임
Zig의 comptime은 정말 멋지지만, Rust의 매크로 시스템도 절대 무시할 물건이 아님
제대로 만들기는 좀 번거롭지만 많은 일을 할 수 있음
코드 생성이 괜히 나쁜 평을 듣는 면도 있다고 봄 build.rs 스크립트로 꽤 많은 짜증 나는 문제를 코드 생성으로 해결해왔고, 실행도 잘됨
물론 나중에는 후회할지도 모르겠음
글의 핵심 주장은 대략 이렇게 보임
자료구조별로 할당자를 커스터마이즈하는 특정 사례에서는 코드 복붙 비용이 어려운 문제였음
Rust의 일부 타입 시스템 기능이 더 편리함. 다만 해당 예시에서 Rust의 타입 설계를 Zig로 포팅하고 comptime으로 API 형태를 강제하라고 에이전트에게 시킬 수 없다는 건 믿기 어려움
비트 플래그나 SoA 같은 기능에서는 코드 가독성이 중요하지 않음
컴파일이 메모리 안전성 오류의 부재를 보장한다면 “100배” 더 많은 코드를 리뷰할 수 있음
Rust가 좋은 언어인 건 맞지만, 그래도 이건 좀 과함
코딩 에이전트 광고처럼 보임
코딩 에이전트가 프로그래밍 언어 선택에 어떤 영향을 주는지에 대한 솔직한 생각처럼 보임
아니면 Zig를 위한 역심리 광고일 수도…
같은 저자의 링크된 글에서 나온 내용임: 그래픽스 프로그래밍에서 아주 흔한 실수는 좌표 공간을 혼동하는 것이고, 타입 시스템은 어떤 좌표 공간과 변환이 유효한지를 타입으로 표현할 만큼 강력하다고 함
통화, SI 단위와 야드파운드 단위 거리·무게, 검증된 문자열과 사용자 제공 문자열 및 비밀값 등에도 같은 얘기가 가능함
또 잘 관리하면 상태 타입으로 불가능하거나 sound하지 않은 상태를 막을 수 있음
하지만 개인적으로 Rust에서 가장 원하는 기능은 데이터 경쟁의 완전 제거임
관리형 언어에도 데이터 경쟁은 있음
“그냥 Go 쓰라”는 Go에서는 모든 것이 스레드 사이에서 참조로 가변이고, 슬라이스 체조까지 붙음
가장 순수하고 안전한 쪽에 속하던, 예전엔 완전 장난감 언어였던 JavaScript조차 모든 await가 잠재적 경쟁임
everything-is-an-EventEmitter 패턴의 사악함은 제쳐두고 말임
그래서 맞음. GC만 있었다면… 🤫
핵심을 약간 숨기고 있는 느낌임
코딩 에이전트는 Python과 JavaScript도 아주 잘 다룸
Rust보다 나은지는 주관적으로 손을 흔드는 영역이지만, 그렇다고 많은 작업에 그 언어들을 고르지는 않을 것임
문제는 Zig의 기능이 자주 바뀌는 데 있는 건지, 아니면 단순히 더 새 언어라서 AI 학습 데이터가 혼탁한 건지 궁금함
Zig는 Rust보다 쓰기는 더 어렵고 읽기는 더 쉬운 편이라고 느낌
AI 시대에는 쓰는 코드보다 읽는 코드가 더 많아서, 나는 Zig 쪽을 선호하게 됨
지금 생성되는 코드 양을 보면 Rust가 더 매력적이라는 말은 첫 단계일 뿐임
컴퓨터가 코드를 더 많이 쓰게 될수록 더 형식적인 언어가 유리해질 것임
동적 타입 논쟁의 또 다른 단계처럼 보임
“동적 타입은 인간에게 더 쉬운데, 왜 기계를 위해 같은 걸 세 번씩 명시해야 하지?”라는 식임
타입, 수명… 그 밖에 기계가 쓰고 소비하기 더 쉬운 것은 또 무엇일까
미래의 컴퓨터가 코드를 작성하는 언어로 인간이 직접 코딩하기는 얼마나 어려워질지 궁금함
Lobste.rs 의견들
예전 팀 리드가 복붙 코드가 항상 나쁜 건 아니라는 꽤 강한 생각을 갖고 있었음
DRY 원칙 때문에 본능적으로는 틀렸거나 논쟁적으로 들렸지만, 그는 매우 실용적인 사람이었고 주로 큰 테스트 코드베이스에 이 원칙을 적용했음
똑똑한 공용 인터페이스를 억지로 만들기보다, 단순하지만 더 크고 중복이 많은 코드베이스가 유지보수하기 쉬울 수 있다는 논리였음
요즘 LLM을 쓰면서 같은 생각으로 돌아가고 있는데, 이제는 더 중요한 소프트웨어 부분에도 적용하게 됨
코드 생성은 빠르고, LLM도 단순하지만 중복이 많은 코드베이스에서 더 잘 맞힐 가능성이 있어 보임
중복을 줄이려고 테스트에 추상화를 너무 많이 넣으면 테스트를 이해하기 어려워지고, 미묘하게 틀릴 위험도 있음
더 나쁜 건 테스트 대상 코드의 추상화를 재사용하면, 테스트도 그 코드와 같은 방식으로 틀릴 수 있다는 점임
또 애플리케이션 코드와 달리 테스트는 사실상 공짜로 “합성”됨
테스트 하네스를 심각하게 망치지 않았다면 테스트를 마음대로 추가하거나 삭제해도 다른 테스트에 영향이 없고, 통합 마찰이 없으니 중복을 피해야 할 이유도 하나 줄어듦
테스트에서는 이걸 DAMP로 표현한 걸 본 적 있음: “Descriptive and Meaningful Phrases”로, 고유성보다 가독성을 강조하는 원칙임
이 원칙은 비슷한 코드를 반복하는 식의 중복을 만들 수 있지만, 테스트가 더 명백하게 올바르게 보이게 해줌
https://testing.googleblog.com/2019/12/…
Go 커뮤니티에도 비슷한 말이 있음: “작은 복사는 작은 의존성보다 낫다” https://go-proverbs.github.io/
라이브 코딩을 공유해줘서 고맙게 생각함
기억이 맞다면 뭔가를 시작할 때 자기가 만들려는 것과 가장 비슷한 코드를 찾아 통째로 복사한 뒤 거기서 수정하는 일이 자주 있었음
“둘이 공유하는 추상화가 뭔지 앉아서 한참 생각하지 않는다고?” 싶었는데, 그냥 복붙하며 밀고 나가고 나보다 훨씬 생산적이었음
Bun의 Zig → Rust AI 재작성 타이밍을 생각하면 흥미로움 https://xcancel.com/jarredsumner/status/2053063524826620129#m
그중 75개는 소멸자, 이동 의미론, 빌림 검사기가 있는 언어라면 컴파일되지 않았을 것이라고 함
배포하는 PR 세 개 중 하나가 “오류 경로에서 해제를 깜박함”인 셈임
108개 중 약 88개는 Zig에 있고, C++ 쪽 약 14개는 대부분 참조 순환과 GC 동시성 경쟁처럼 어떤 언어에서도 남는 잔여 범주라 함
그래서 Zig→Rust 차이는 실제이며, Zig 버그는 정확히 소멸자와 소유권으로 고칠 수 있는 종류이고 C++ 쪽은 이미 바닥에 가까움
더 강한 컴파일 타임 보장이 없으면 이건 계속 고양이와 쥐 게임으로 남음
제안은 가장 큰 버그 범주를 계속 개별 수정하지 말고 구조적으로 제거하자는 것임
– bun/docs/rust-rewrite-plan.md at claude/phase-a-port · oven-sh/bun · GitHub
“나머지 5%의 경우에는 comptime이 없으면 괴롭고, 동등한 결과에 reliably 도달하는 유일한 방법은 코드 생성”이라는 부분은 저자가 무슨 뜻인지 명확하지 않음
절차적 매크로에 대해 아무 말도 하지 않기 때문임
제대로 만들기는 좀 번거롭지만 많은 일을 할 수 있음
코드 생성이 괜히 나쁜 평을 듣는 면도 있다고 봄
build.rs스크립트로 꽤 많은 짜증 나는 문제를 코드 생성으로 해결해왔고, 실행도 잘됨물론 나중에는 후회할지도 모르겠음
글의 핵심 주장은 대략 이렇게 보임
Rust가 좋은 언어인 건 맞지만, 그래도 이건 좀 과함
코딩 에이전트 광고처럼 보임
같은 저자의 링크된 글에서 나온 내용임: 그래픽스 프로그래밍에서 아주 흔한 실수는 좌표 공간을 혼동하는 것이고, 타입 시스템은 어떤 좌표 공간과 변환이 유효한지를 타입으로 표현할 만큼 강력하다고 함
통화, SI 단위와 야드파운드 단위 거리·무게, 검증된 문자열과 사용자 제공 문자열 및 비밀값 등에도 같은 얘기가 가능함
또 잘 관리하면 상태 타입으로 불가능하거나 sound하지 않은 상태를 막을 수 있음
하지만 개인적으로 Rust에서 가장 원하는 기능은 데이터 경쟁의 완전 제거임
관리형 언어에도 데이터 경쟁은 있음
“그냥 Go 쓰라”는 Go에서는 모든 것이 스레드 사이에서 참조로 가변이고, 슬라이스 체조까지 붙음
가장 순수하고 안전한 쪽에 속하던, 예전엔 완전 장난감 언어였던 JavaScript조차 모든
await가 잠재적 경쟁임everything-is-an-EventEmitter 패턴의 사악함은 제쳐두고 말임
그래서 맞음. GC만 있었다면… 🤫
핵심을 약간 숨기고 있는 느낌임
코딩 에이전트는 Python과 JavaScript도 아주 잘 다룸
Rust보다 나은지는 주관적으로 손을 흔드는 영역이지만, 그렇다고 많은 작업에 그 언어들을 고르지는 않을 것임
문제는 Zig의 기능이 자주 바뀌는 데 있는 건지, 아니면 단순히 더 새 언어라서 AI 학습 데이터가 혼탁한 건지 궁금함
Zig는 Rust보다 쓰기는 더 어렵고 읽기는 더 쉬운 편이라고 느낌
AI 시대에는 쓰는 코드보다 읽는 코드가 더 많아서, 나는 Zig 쪽을 선호하게 됨
지금 생성되는 코드 양을 보면 Rust가 더 매력적이라는 말은 첫 단계일 뿐임
컴퓨터가 코드를 더 많이 쓰게 될수록 더 형식적인 언어가 유리해질 것임
동적 타입 논쟁의 또 다른 단계처럼 보임
“동적 타입은 인간에게 더 쉬운데, 왜 기계를 위해 같은 걸 세 번씩 명시해야 하지?”라는 식임
타입, 수명… 그 밖에 기계가 쓰고 소비하기 더 쉬운 것은 또 무엇일까
미래의 컴퓨터가 코드를 작성하는 언어로 인간이 직접 코딩하기는 얼마나 어려워질지 궁금함