LINE 개발 조직에서는 성숙한 개발 문화를 만들기 위해 다양한 시도를 하고 있습니다. 클라이언트 앱 품질을 향상시키기 위해 개발 프로세스를 개선하고 있는 LY Mobile Developer Experience Dev 팀에 서도 여러 시도를 해오고 있는데요. 이번 글에서는 이시카와 무네토시 님과 기욱 님이 함께 ‘코드 가독성’을 높이고자 한 노력을 소개합니다.
정기욱 님: LINE의 iOS 앱 개발을 담당하고 있습니다. 주로 iOS 빌드 환경을 개선하고, 빌드에 사용되는 도구를 개발하는 등의 업무를 맡고 있어요. 쉽게 말해 ‘개발자를 돕는 개발’을 하는 셈이죠. iPhone 3GS 발매 무렵인 2009부터 시작해 15년째 일본에서 근무하고 있습니다.
이시카와 무네토시 님: LINE의 Android 앱 개발을 담당하고 있습니다. 기욱 님과 같은 팀에서 일하고 있으며 전사적인 소프트웨어 엔지니어 교육도 하고 있습니다. 9년 전에 입사했을 때부터 기능 개발과 더불어 코드 리뷰 품질 개선, 채용 프로세스 개선 등의 업무에도 참여하고 있습니다.
개발자 경험을 담당하는 팀의 ‘개발 문화’
Q: 개발자 경험을 위한 팀에 속해 있는데요, 어떤 일을 하는 팀인가요?
이시카와 님: 단일 팀이 아닌 조직 전체의 개발 문화와 원칙을 개선한다는 점이 Mobile Developer Experience Dev 팀의 특징입니다. 저희 팀은 조직 전체의 생산성이나 코드 품질을 향상할 수 있는 방법을 고민하고 시도합니다. 예를 들어 코드 변경 사항을 보고 개발자가 어떤 테스트를 해야 하는지 제안하거나, 자동으로 리뷰어를 추가하는 봇을 만들기도 합니다. 앱 개발 팀으로서 이러한 활동을 하는 것이 독특하다고도 할 수 있는데요. 이 슬라이드에서 저희 팀에서 했던 여러 시도를 살펴볼 수 있습니다.
Q. 팀의 특성이 특성이니 만큼 건강한 개발 문화가 자리 잡고 있을 것 같습니다.
기욱 님: 저희 팀은 풀 리퀘스트를 올릴 때 모든 팀원을 리뷰어로 지정하는 원칙이 있습니다. LINE의 클라이언트 개발 조직에서는 Android 팀과 iOS 팀이 나뉘어 있지 않아요. 그렇기 때문에 iOS 개발자가 Android 코드를, 반대로 Android 개발자가 iOS 코드를 리뷰하기도 합니다. 두 플랫폼의 코드를 비교해 읽다 보면 모바일 개발 환경에 대한 이해가 높아져요.
비슷한 맥락으로 봇을 이용한 ‘랜덤 리뷰’도 하고 있어요. 풀 리퀘스트의 1차 리뷰어가 승인하면, 봇이 랜덤으로 2차 리뷰어를 지정합니다. 2차 리뷰어는 평소 접하지 못한 코드를 검토하면서 프로젝트를 보다 넓게 이해할 수 있고, 다른 팀과 교류할 수도 있어요.
코드 리뷰에 규칙을 적용하는 것 외에도 건강한 개발 문화를 형성하기 위해 멤버들과 활발하게 소통하고 있습니다. 코드 리뷰가 방치되지 않도록 데일리 미팅에서 대기 중인 풀 리퀘스트를 다 같이 확인합니다. 규모가 크거나 장기적인 계획이 필요한 구현은 미리 설계 문서를 작성해서 논의하고요. 이외에 주 1회 스터디나 캐주얼한 테크토크 시간을 가지고 있어요.
‘소프트웨어의 구조는 조직의 구조를 닮는다’는 ‘콘웨이의 법칙’이라는 것이 있는데요. '하나의 컴파일러를 만들기 위해 4개 의 팀이 조직되면, 4단계로 빌드되는 컴파일러가 나오게 된다’는 유명한 명제가 있죠. 보통은 조직이 커지고 팀이 분할될수록 소프트웨어도 마찬가지로 확장성을 잃고 복잡해집니다. 저희 팀은 이를 해결하기 위한 열쇠가 긴밀하게 커뮤니케이션하는 개발 문화에 있다는 의견에 뜻을 함께합니다.
글로벌 개발 환경에서 더욱 중요한 ‘코드 가독성’
Q. 이러한 문화가 쉽게 만들어지지 않았을 텐데요, 특히 두 분이 공감하는 부분이 ‘코드 가독성’이라고 들었습니다.
이시카와 님: 입사했을 때부터 ‘읽기 쉬운 코드’에 관심이 있었어요. 입사 전에 선배 엔지니어를 캐주얼하게 만날 기회가 있었는데요, 그분이 제게 'LINE 서비스가 빠르게 성장하는 상황에 발맞춰 코드 품질 개선 방안을 마련해 보자'고 제안했습니다. 이에 입사 후부터 코드 품질 향상 작업을 시작했습니다. 그 과정에서 수많은 코드 리뷰를 진행했는데 같은 피드백을 여러 차례 할 때가 있었어요. 린터(linter)와 같은 도구를 이용해 자동화하는 것에도 한계가 있어, 코드를 쓰고 리뷰할 때 조심해야 하는 점을 자료로 정리해 나갔어요. 앞서 언급한 선배 엔지니어이자 당시 저의 부문장이 ‘자료를 공개하자’는 제안을 주셨고, 그때의 자료를 버전업해 여기에 공개했습니다.
기욱 님: 프로젝트 규모가 클수록, 프로젝트 지속 기간이 길수록 코드 가독성에 대해 더 많이 고민하게 됩니다. 특히 LINE은 대규모 장기 프로젝트인 것과 더불어 ‘글로벌 환경’에서 개발한다는 특징도 있어요. LINE처럼 국적, 문화, 언어 심지어 근무 장소까지 서로 다른 동료와 함께 일하는 환경에서는 원활한 커뮤니케이션이 중요한데요. 코드도 일종의 커뮤니케이션 수단이기 때문에 ‘코드 가독성’이 높다면 상대방의 의도를 파악하기도 쉽습니다.
일반적으로 코드는 사양을 바탕으로 작성합니다. 그런데 개발 기간이 길어지며 사양과 코드가 수차례 업데이트될수록, 사양을 파악하기 위해 코드와 문서를 몇 번이고 확인하게 됩니다. 여기에 글로벌 개발 환경이라면 언어 차이로 사양 파악이 더 어려워지지요. 예를 들어 초기 특정 국가에 한정되었던 사양을 다른 국가로 확장한다고 할 때, 문서가 외국어로 작성되어 있거나 영작문이 서툴게 되어 있으면 이해하기 어렵습니다. 이럴 때 코드 가독성이 높다면, 사양을 파악하기가 훨씬 수월해요. 개발자에게 있어 ‘읽기 쉬운 코드’야말로 가장 명확한 문서나 다름없죠.
물론 문서와 코드는 그 역할이 다르기 때문에 문서 작성은 필요하지만, 문서에만 의존하는 것보다는 코드에서 바로 사양을 읽을 수 있는 편이 더 원활하게 개발할 수 있었어요.
가독성 높은 코드를 작성하기 위한 몇 가지 팁 from '코드 작성 가이드'
네이밍에 사용할 단어를 선택할 때 의미가 제한적인 단어를 사용하면 오해의 소지를 줄일 수 있습니다. 예를 들어 값의 한계를 나타내는 limit이라는 단어는 그것이 상한선인지 하한선인지 모호합니다. 그보다는 max나 min을 사용해야 어느 쪽의 한계인지가 더 명확합니다. (2.3 단어 선택)
직관적으로 이해하기 어려운 코드가 있다면 비형식 주석으로 보완해서 가독성을 크게 향상시킬 수 있습니다. 오해의 소지가 있는 코드에는 주의 사항을 추가하고, 충분히 생각해야 이해할 수 있는 코드에는 이해를 돕는 설명을 추가하는 것이 좋습니다. 특히, 방치해 두면 누군가가 잘못된 방식으로 리팩터링할 여지가 있는 코드에는 반드시 주석으로 주의 사항을 알려야 합니다. (3.3 비형식 주석)
객체가 취할 수 있는 상태의 수가 두 개 이하이고, 그 상태를 전환하는 함수가 한 개인 경우, 가능하면 함수가 멱등성(idempotent)을 지니도록 만드는 것이 좋습니다. 멱등성이란 한 번 실행한 결과와 여러 번 실행한 결과가 동일하다는 개념입니다. (4.3 상태 전이의 설계)
함수가 여러 책임을 지게 되면 함수의 동작을 추상적으로 이해하기가 어려워집니다. 또한 함수의 재사용이 어려워지고 코드 복제의 원인이 되는 등 설계에 악영향을 끼칠 수도 있습니다. 하나의 함수가 지는 책임은 오직 하나이어야 하며, 이를 위해서는 함수를 적절히 분할해야 합니다. (5.1 함수의 책임)
추상화는 가독성을 향상시키는 효과적인 수단 중 하나이지만, 동시에 암묵적 의존 관계의 원인이 되기도 합니다. 따라서 추상화할 때는 어떤 목적으로 추상화할 것인지를 먼저 생각해봐야 합니다. (6.5 의존의 명시성)
Q. 이시카와 님이 '코드 가독성'과 관련해 고민한 내용을 한 군데에 담아냈다고 들었습니다. 이를 기욱 님이 번역했다는 것도 특별합니다.
이시카와 님: '코드 작성 가이드'라는 책에 담았습니다. 이 책의 근간이 되는 슬라이드 파일이 있는데요, 사실 이건 제가 코드 리뷰를 편하게 하기 위해 만든 자료입니다. 코드 리뷰로 제안할 때는 생각을 잘 정리해야 하는데 정리한 내용을 나중에 비슷한 상황에 다시 확인해 보거나 회고할 때 쓰려고 자료를 만들었죠. 비슷한 문제에 있는 다른 사람과 지식을 공유하기도 하고요. 실제로 자료를 공개했더니 많은 분이 긍정적으로 피드백을 주셨습니다. 그러던 중 ‘책으로 만들어지면 좋겠다’고 무심코 이야기했더니, Developer Relations 팀에서 도움을 주셨어요.
저는 이 책의 번역을 같은 팀 동료인 정기욱 님께 부탁했는데, 그 이유가 꼭 그가 일본어에 능통하기 때문만은 아니었어요. 기욱 님은 기술력이 뛰어난 분인데다 무엇보다 저희 팀원 모두에게 신뢰받는 사람이기 때문이었죠. 그리고 같은 팀에서 일하는 동료인 만큼 의사소통에 대해 전혀 걱정할 필요가 없다는 점도 제게 큰 안도감을 주었어요. 실제로 기욱 님은 기존의 표현을 한국어로 번역했을 때 어색함이 없는지, 한국인들에게 더 익숙한 표현으로 바꿔도 내용이 동일할지 등 매우 세세한 부분까지 고려하면서 제게 많은 질문을 주셨어요. 비록 저는 한국어를 읽을 수 없지만, 분명 이 책의 높은 완성도로 번역됐다고 확신할 수 있어요.
코드 개선이 필요하다고는 생각하지만 어떻게 설명해야 할지 모를 때, 이 책에서 힌트를 얻을 수 있을 거예요.
기욱 님: 번역 경험은 전무했지만, 번역서가 만들어지면 같이 일하는 클라이언트 개발자에게 도움이 될 거라는 기대가 컸습니다. 사내 교육 자료로도 사용되는 이시카와 님의 ‘코드 작성 가이드’가 일어와 영어판만 있다는 사실이 늘 아쉬웠거든요. 이시카와 님이 일본 개발자들이 쉽게 읽을 수 있도록 서적을 출판했듯이 저도 한국 동료 개발자를 위해 모국어로 책을 번역하고 싶었습니다.
번역서가 한일 양국에 분산된 팀이 서로 코드를 리뷰할 때 ‘공통된 코드 품질 기준’으로 활용되기를 기대합니다. 업무 시간 외나 휴일에 번역 작업을 하느라 힘들었지만 이렇게 고군분투한 시간이 언젠가 유의미한 일이었음을 깨닫게 되는 날이 올 것이라고 믿습니다. 그때는 성취감에 맘껏 취해 보려고요.
Q. 추가로 코드를 작성할 때 중요하다고 생각하는 것이 있나요?
기욱 님: 지난해부터 생성형 AI가 정말 뜨거운 이슈인데요, 개발 환경에 AI를 보편적으로 적용할수록 중요해지는 것이 있다고 생각합니다. 설계와 구현의 단순함을 강조하는 KISS(Keep It Simple, Stupid) 원칙이 한 가지입니다. AI 시스템은 머신 러닝 모델, 데이터 전처리, 다른 시스템과의 통합 등으로 복잡해지기 쉽습니다. 그렇기 때문에 AI 모델과 그 통합을 보다 관리하고 해석하기 쉽도록 ‘단순함’을 유지하는 것이 더욱 강조될 것이라고 생각해요.
공통 기능을 재사용 가능하게 추상화해 코드 중복을 줄이는 DRY(Don’t Repeat Yourself) 원칙도 더욱 강조될 듯해요. AI 시스템은 사전 학습된 모델, 함수, 파이프라인을 재사용해 시간과 리소스를 절약하고 일관되게 출력할 수 있으니까요. 이외에 TDD(Test Driven Development)와 같이 AI의 신뢰성을 확보하기 위한 원칙도 부각되지 않을까 싶습니다.
이시카와 님: 일반적으로 코드 품질의 척도에는 가독성 외에도 유연성, 확장성, 재사용성, 성능 등 다양한 기준들이 있어요. 물론 각 기준이 모두 중요하지만, 때로는 서로 상충되는 관계일 수도 있어요. 일부 동작의 성능을 높이려다가 되려 코드의 가독성이나 재사용성이 떨어지는 경우가 그렇죠. 이때 우선순위를 어떻게 정할 것인가는 매우 어려운 문제이면서도 동시에 매우 중요한 문제이기도 해요. 사람마다 우선하는 기준이 다르기 때문에 개발자들은 코드 리뷰나 대면 토론을 통해 의견을 나누면서 조율해 나가야 해요. 저는 이러한 과정이야말로 개발의 큰 재미라고 생각합니다. 그런 의미에서 본다면 코드 품질에 있어 가장 중요한 것은 코드 자체의 특성보다 기술적인 토론을 즐길 수 있느냐 없느냐가 아닐까 싶어요.
저의 경우에는 ‘가독성’ 못지않게 코드의 ‘견고성’ 또한 중요하게 생각하는데요, 잘못 사용되거나 잘못 변경되기 어려운 성질을 뜻하는 ‘견고성’이 때로는 적은 코드 변경으로 더 폭넓게 사용할 수 있는 성질, 즉 ‘유연성’과 상충관계가 되기도 하죠. 저는 기능을 확장할 때 비록 적은 양의 코드 변경이라도 그 변경에 실수가 있어 서는 안 된다고 생각하기 때문에 가독성보다 견고성을 우선하는 편이에요. 특히나 대규모 제품 개발에서는 그 코드 변경이 안전하다고 보장할 수 있는 것이 매우 중요하거든요.
더불어 원칙이나 기술이 '왜' 도움이 되는지 생각하는 것이 중요해요. 읽기 쉬운 코드를 쓰기 위해 중요하게 여기는 프로그래밍 원칙이나 특정 기술을 남용하면, 오히려 코드의 가독성이 낮아지거나 버그가 생기기도 합니다. 왜 필요한 것인지 고민하지 않으면 '망치를 든 사람에게 모든 문제가 못으로 보이는' 상황이 될 수 있습니다. 예를 들어 '조기 리턴'이라는 기술은 유명하기 때문에 많은 해설서에서 간단하게 소개하는데요. 저는 '코드 작성 가이드'에서 어떤 때 조기 리턴을 사용하는지 그 이유를 충분히 설명하고자 했습니다. 원칙이나 기술을 적용할 때 '왜 사용해야 하는지' 충분히 고민하는 사고방식을 익힌다면 언어의 패러다임이나 유행하는 설계가 바뀌더라도 휘둘리지 않고 계속 따라잡을 수 있다고 생각합니다.
코드 리뷰 문화를 만들고자 한다면 ‘이렇게’ 해보세요
Q. 많은 개발 팀에서 코드 리뷰 문화를 만들고자 노력하고 있을 것 같아요. 같은 시도를 해 본 입장에서 조언해 주실 점이 있을까요?
기욱 님: 제가 가장 중요하게 생각하는 것은 기술적인 측면은 아닙니다. ‘감정 마찰로 인한 사기 저하’가 일어나지 않도록 주의를 기울여야 한다고 생각해요. 그러려면 리뷰에 사용하는 말투부터 신경 써야 합니다. 특히나 팀이 분산되어 있거나 국제적인 팀의 경우 더 그렇죠. ‘이 코드는 좋지 않습니다. 수정해 주세요’ 대신에 ‘이러한 코드에 대해 경고하는 글을 읽었습니다. 여기 링크가 있으니 참고하세요’와 같은 친절한 말투가 좋습니다. 일부러 칭찬거리를 찾아 코멘트를 남기는 것도 좋아요. 예를 들어 ‘이 부분 마음에 듭니다. 버그가 해결됐는데 가독성도 좋아졌네요’와 같은 식으로요.
또 코드 리뷰가 고착 상태에 빠졌다면, 변경된 코드가 리뷰어의 기준에 도달하지 않았더라도 품질이 어느 정도 개선됐다면 승인을 고려해 주세요. 우리가 추구하는 건 완벽함이 아닌 지속적인 개선이니까요. 그리고 리뷰를 받는 사람은 항상 의연해야 합니다. 어쩌면 고작 다섯 줄 쓴 코드에 여섯 개의 코멘트가 달릴 수도 있어요. 코드가 잘못됐다는 말이 유쾌하지는 않겠지만, 리뷰해 준 동료는 다른 일을 하던 중에 시간을 할애했다는 사실을 기억해야 해요. 도움을 주려는 동료에게 충분히 설명하고, 겸손하게 들어주세요.
이시카와 님: 코드, 설계, 프로세스, 기타 개발과 관련된 것은 무엇이든 좋으니 논의를 즐기고 논의하는 사람의 범위를 넓혀보세요. 코드 리뷰는 하나의 논의 형식으로 볼 수 있는데, 거기에 심리적 안정성이 담보되어 있지 않으면 '코드나 설계에 대한 지적'이 '코드를 쓴 사람에 대한 공격'처럼 보일지도 모릅니다. 평소 다 같이 논의하면서 '사람이 아닌 코드를 대상으로 논의한다 는 것'이나 '잘못된 말을 해도 부끄러운 일이 아니다'는 것을 팀 공통의 인식으로 맞춰두면 좋습니다. 그러면 코드 리뷰에서도 기탄없이 의견을 말할 수 있고, 더 나은 코드를 만들려면 어떻게 해야 하는지 다 같이 진지하게 논의할 수 있습니다.