
기술적 취향은 단순한 기술 능력과는 다릅니다. 기술적으로 뛰어나면서도 취향이 좋지 않을 수 있고, 반대로 기술은 부족하지만 좋은 취향을 가질 수도 있습니다. 일상에서 맛을 구분하는 것처럼, 기술적 취향도 능력이 따라주기 전에 먼저 생겨날 때가 있습니다. 예를 들어 요리를 할 줄 몰라도 맛있는 음식과 그렇지 않은 음식을 구분할 수 있듯이, 만들어본 경험이 없더라도 어떤 소프트웨어를 좋아하는지는 알 수 있습니다. 기술 능력은 공부와 반복으로 쌓을 수 있지만, 좋은 취향은 더 신비로운 과정으로 형성됩니다.
소프트웨어 취향을 가늠할 수 있는 몇 가지 기준은 다음과 같습니다:
- 어떤 종류의 코드가 ‘보기 좋다’ 느껴지고, 어떤 코드는 ‘보기 싫다’고 느끼나요?
- 어떤 설계 결정이 정말 마음에 들고, 어떤 결정은 그냥 무난하다고 생각하나요?
- 어떤 소프트웨어 문제는 너무 신경 쓰여서 회사 밖에서도 계속 머릿속에 맴돌고, 어떤 문제는 그냥 대수롭지 않게 넘기나요?
저는 취향이란 ‘현재 하고 있는 프로젝트에 가장 적합한 엔지니어링 가치를 채택하는 능력’이라고 봅니다.
왜 취향은 기술 능력과 다른가
위 기준들이 단순히 기술 능력의 일부라고 생각하지 않나요? 예를 들어 좋은 코드는 당연히 보기 좋은 코드 아니냐고요? 저는 그렇게 보지 않습니다.
예시를 하나 들어볼게요. 개인적으로 저는 for 루프를 사용하는 것보다 map과 filter를 활용한 코드가 더 깔끔해 보입니다. 이걸 단순히 기술적으로 제가 맞고 다른 사람들은 틀렸다고 생각할 수 있지만, 사실 그건 복잡한 문제입니다. 예를 들어 Golang 같은 언어는 아예 map과 filter를 포함하지 않는데, 이것은 당위적인 이유에서 그렇습니다. for 루프가 성능 면에서 더 이해하기 쉽고, 두 개씩 처리하는 등 다른 반복 방법으로 확장하기도 쉽기 때문이죠. 저는 이런 이유보다는 map과 filter의 장점이 더 마음에 들어서 for 루프를 덜 쓰는 것일 뿐입니다. 그래서 for 루프를 선호하는 엔지니어가 기술적으로 부족하다고 말하는 건 지나친 오만이라고 생각해요. 그들은 저와 다른 기술 능력을 가지고 있고, 단지 중요하게 생각하는 가치가 다를 뿐입니다.
즉, 이 의견 차이는 가치관의 차이에서 비롯된 것입니다. 저는 이 점을 「I don’t know how to build software and you don’t either」라는 글에서 썼습니다. 큰 기술적 논쟁에도 분명한 답이 있을지 몰라도, 현실의 소프트웨어 엔지니어는 그 답을 알 위치에 있지 않습니다. 한 사람이 커리어에서 경험할 수 있는 범위는 제한적이기 때문입니다. 우리는 모두 각자의 경험, 즉 각자 가지고 있는 엔지니어링 가치 세트에 부분적으로 의존할 수밖에 없습니다.
엔지니어링 취향이란 무엇인가
소프트웨어 엔지니어링의 거의 모든 결정은 **트레이드오프(상충관계)**의 문제입니다. 대개의 경우 한 쪽이 절대적으로 더 나은 선택은 아니며, 각 선택지마다 장단점이 존재합니다. 예를 들어, 성능을 더 올리려다 보면 어느 정도 한계 이후에는 가독성이 나빠질 수밖에 없듯이, 기술적 가치들 사이에서 어려운 선택을 해야 할 때가 많습니다.
이 점을 진심으로 이해하는 것이 (내 생각에) 소프트웨어 엔지니어로서 성숙도를 가장 잘 드러내는 지표입니다. 미숙한 엔지니어는 자신이 내린 결정에 대해 지나치게 경직적입니다. 항상 X가 낫다거나 Y가 낫다고만 생각하죠. 반면 경험 많은 엔지니어는 대부분 결정의 양쪽 면을 고려하려 합니다. 왜냐하면 어느 쪽에도 저마다 장점이 있음을 알기 때문입니다. 핵심은 기술 X가 Y보다 낫냐가 아니라, 이 특정 상황에서 X의 이점이 Y를 뛰어넘느냐입니다.
즉, 미성숙한 엔지니어는 자신의 취향에 대해 너무 융통성이 없습니다. 자신이 좋아하는 것을 알지만 그걸 마치 원칙 있는 기술 입장인 양 착각하는 것이지요. 그렇다면 한 엔지니어의 취향은 무엇에 의해 결정되는 걸까요?
내가 보기에, 엔지니어링 취향은 당신이 가장 중요하게 생각하는 여러 엔지니어링 가치들의 집합입니다. 예를 들면:
- 복원력(Resiliency): 인프라 일부가 실패했을 때(서비스 다운, 네트워크 단절) 시스템이 계속 동작하는가? 사람이 개입하지 않아도 복구 가능한가?
- 속도(Speed): 이 소프트웨어가 이론적 한계에 비해 얼마나 빠른가? 꼭 필요하지 않은 작업이 경로상에서 이루어지고 있지는 않은가?
- 가독성(Readability): 소프트웨어를 빠르게 파악하고 신규 엔지니어가 쉽게 적응할 수 있는가? 함수들은 짧고 이름이 적절한가? 문서화는 잘 되어 있는가?
- 정확성(Correctness): 시스템이 불가능한 상태를 표현할 수 있는가? 테스트, 타입, 어서트 등으로 얼마나 견고히 막아놓았는가? 퍼징(fuzzing) 같은 테스트 기법을 쓰는가? 극단적으로는 Alloy 같은 형식적 검증 방법으로 프로그램이 증명되었는가?
- 유연성(Flexibility): 시스템 확장이 편한가? 수정이 쉬운가? 뭔가 변경해야 할 때 얼마나 많은 부분을 건드려야 하는가?
- 이식성(Portability): 특정 운영 환경(예: MS 윈도우, AWS)에 종속되어 있는가? 다른 환경으로 재배포할 때 큰 기술적 작업이 필요한가?
- 확장성(Scalability): 트래픽이 10배 늘어나면 시스템이 버틸 수 있는가? 100배는? 과도하게 자원을 잡아놓아야 하는가, 아니면 자동으로 확장되는가? 병목 구간은 어디인가?
- 개발 속도(Development speed): 시스템 확장은 얼마나 빠른가? 대부분 엔지니어가 작업할 수 있나, 아니면 전문가가 필요하나?
이밖에도 세련됨, 최신 기술 사용, 오픈 소스 활용, 운영 비용 등 다양한 가치들이 있습니다. 이 모두 중요하지만, 모든 엔지니어가 동일한 비중으로 여기는 것은 아닙니다. 당신의 취향은 이들 가치 중 어떤 것을 더 우선시하느냐에 따라 달라집니다.
예를 들어, 속도와 정확성을 개발 속도보다 우선시한다면 파이썬보다 러스트를 선호할 가능성이 높습니다. 확장성을 이식성보다 중시한다면 특정 클라우드 환경(AWS 등)을 적극 활용하는 쪽에 찬성할 겁니다. 복원력을 속도보다 중시한다면 트래픽을 여러 지역에 분산시키려 할 테고요.
더 세밀하게 쪼갤 수도 있습니다. 가독성을 중요하게 생각하는 두 엔지니어가 있다고 해도, 한 명은 함수가 짧은 것을, 다른 한 명은 호출 스택이 짧은 것을 더 따질 수 있습니다. 정확성을 중요시하는 이들도, 한쪽은 철저한 테스트를 중시하는 반면 다른 쪽은 형식 검증에 더 무게를 둘 수 있죠. 하지만 근본 원칙은 같습니다: 많은 엔지니어링 가치들이 존재하고, 서로 충돌하는 경우가 많기 때문에, 각 엔지니어는 자신이 더 중요하게 여기는 가치를 좀 더 강하게 추구할 수밖에 없습니다.
나쁜 취향을 구분하는 방법
앞서 말했듯이, 여기서 언급한 모든 가치들은 중요합니다. 그럼에도 불구하고 나쁜 취향이 존재할 수 있습니다. 소프트웨어 엔지니어링에서 나쁜 취향이란, 당신이 선호하는 가치들이 지금 맡은 프로젝트와 맞지 않는 경우를 말합니다.
대부분은 이런 엔지니어와 함께 일해본 경험이 있을 겁니다. 그들은 자신이 과거에 효과적이었다고 믿는 방법론이나 기술(형식적 방법, Golang 재작성, 루비 메타프로그래밍, 크로스 리전 배포 등)을 프로젝트에 강력히 주장합니다. 프로젝트에 적합한지 상관없이 자신의 선호를 밀어붙이죠. 어느새 내부 지표 대시보드에 높은 신뢰성(예: 99.999%)을 맞추느라, 신입 엔지니어가 내용을 이해하기 어려운 시스템이 되어버립니다.
즉, 나쁜 취향의 대부분은 유연성 부족에서 옵니다. 저는 “이건 베스트 프랙티스니까”라며 결정을 정당화하는 엔지니어들을 항상 의심합니다. 어떤 기술 결정도 모든 상황에 맞는 절대적인 ‘베스트 프랙티스’란 없습니다! 당면한 특정 문제에 맞는 올바른 판단을 내리는 것이 중요합니다.
흥미로운 점은, 나쁜 취향을 가진 엔지니어는 고장난 나침반과 같다는 겁니다. 적절한 위치에 있을 땐 나침반이 북쪽을 가리키지만, 움직이기 시작하면 잘못된 방향을 알려주죠. 마찬가지로, 그들이 선호하는 가치가 프로젝트에 딱 맞는 특수 영역에서는 꽤 효과적일 수 있습니다. 하지만 프로젝트가 바뀌거나 일자리가 변하거나 프로젝트의 성격이 바뀌면 곧바로 문제가 터집니다. 특히 2021년 이후 어려운 시기에는 어떤 작업도 오래 지속되지 않습니다.
좋은 취향을 구분하는 방법
좋은 취향은 기술능력보다 훨씬 포착하기 어렵습니다. 그 이유는 좋은 취향이란 특정 기술 문제에 맞는 올바른 엔지니어링 가치를 선택하는 능력이기 때문입니다. 따라서 누군가가 좋은 취향을 가졌는지 판별하려면 단순한 문제나 기술적 사실에 대한 질문으로는 불가능합니다. 실제 문제와 복잡한 현실 맥락이 있어야 합니다.
당신이 참여한 프로젝트가 성공한다면 좋은 취향을 가졌다고 볼 수 있습니다. 프로젝트 설계에 의미 있게 기여하지 않는다면(단순한 업무만 한다면), 설계 방향에 동의한 프로젝트는 잘 되고, 동의하지 않은 프로젝트는 어려움을 겪는 걸로 판단할 수 있습니다. 중요한 건 다양한 유형의 프로젝트 경험이 필요하다는 겁니다. 만약 오직 한 프로젝트나 비슷한 프로젝트만 겪었다면, 단지 그 프로젝트에 적합한 것일 뿐입니다. 여러 프로젝트를 경험해도 익숙하지 않은 영역에서 좋은 취향이 있다는 보장은 없습니다.
좋은 취향을 기르는 방법은 명확하지 않지만, 여러 프로젝트를 겪으며 그중 어느 프로젝트가(또는 어느 부분이) 수월하고 어려운지 주의 깊게 살피는 걸 권장합니다. 이 과정에서 가장 강조할 점은 유연성입니다. 소프트웨어를 만드는 올바른 방식을 절대적인 규칙으로 받아들이지 않도록 노력해야 합니다. 저 역시 좋은 취향을 천천히 길러 왔지만, 누군가는 더 빨리 익힐 수도 있을 겁니다. 프로그래밍 경험에 비해 취향이 더 앞서가는 천재들도 분명 있을 테니까요.
이 글에 관한 Hacker News 댓글 토론에서는, 좋은 취향이 초보자와 일할 때 어떻게 적용되고 그들의 취향을 약간 반영해야 효과적으로 배울 수 있도록 도움을 줄 수 있다는 의견도 있었습니다. 또 “취향이란 개념이 소프트웨어 엔지니어링에서 필요 없고, 모든 결정은 하나의 정답이 있다고 본다”는 반대 의견도 있었는데, 저는 매우 납득하기 어렵다고 생각합니다. 각 엔지니어링 문제에는 여러 허용 가능한 해답이 있고, 최종 선택은 개인 기호로 귀결된다고 보는 편입니다. 또 다른 댓글은 고객이나 비즈니스 측면에 대한 언급을 원했는데, 저는 여기서 매우 기술적인 결정도 취향에 영향을 받는 점을 강조하고 싶었습니다.
원문: What is “good taste” in software engineering?
blog by ash에서 더 알아보기
구독을 신청하면 최신 게시물을 이메일로 받아볼 수 있습니다.
