개발자와 라면 조리법

라면 봉지 뒷면에 써있는 조리법을 한번 들여다보자.

(1) 물 550ml와 건더기 스프를 넣고 물을 끓인다.
(2) 분말 스프와 면을 넣은 후 4분 더 끓인다.

3번은 먹는 방법에 대한 권장사항이니 제외하면 두 단계라고 볼 수 있다. 근데 실제로 라면을 끓이는 자신의 모습을 상상해보면 이보다 훨씬 많은 단계들이 숨어있다.

(1) 냄비를 꺼낸다.
(2) 냄비에 물 550ml와 건더기 스프를 넣는다.
(3) 물과 재료가 담긴 냄비를 가열한다.
(4) 물이 끓기를 기다린다.
(5) 물이 끓기 시작하면 면과 분말 스프를 넣는다.
(6) 4분 더 끓인다.
(7) 불을 끈다.
(8) 그릇에 옮겨 담는다.

이보다 더 자세하게 서술할 수도 있다. 들여다보면 ‘냄비를 가열한다’에도 여러 단계가 생략돼있다. 심지어 장비에 따라서도 다르기 때문에 분기가 필요하다.

(1) 인덕션이라면 전원을 켜고 버튼을 눌러 온도를 높인다.
(2) 가스레인지라면 가스밸브를 열고 다이얼을 돌려 점화한다.
(3) 휴대용 버너라면 가스통을 흔들어 넣고, 잠그고, 점화한다.

하지만 그 어떤 라면 조리법에도 위 같은 내용이 포함되진 않는다. 왜냐면 이정도 상세한 내용은 독자가 이미 알고 있다고 간주하거나, 실은 라면 회사가 알 바 아니기 때문이다. 너무 당연한 말이라고 생각할 수도 있겠지만 이런 류의 코드는 꽤 흔하다. 함수 이름에 표현된 것보다 더 많은 일을 하거나 지나치게 세부적인 구현부가 드러나기도 한다. 이런 경우 보통 if문, for문이 많고 코드가 장황하다.

가령 fetchRecentArticles 라는 함수를 마주쳤다고 상상해보자. 이 함수가 수행하는 작업은 아래와 같다고 예상할 수 있다.

(1) 저장된 아티클을 적당히 불러온다.
(2) 최근 X일 내에 생성된 것들을 골라낸 후 반환한다.

그런데 막상 함수를 들여다보니 함수 안에서 로컬 캐시를 확인하고, 없으면 서버 API 호출을 해서 데이터를 가져와서 파싱하고, 저장소에서 데이터를 불러오기 위한 키 값도 정의하고, switch문으로 아티클의 종류에 따라 각기 다른 필터링 로직을 생성하고 있다면 어떨까. 막상 핵심 부분은 장황한 코드 속에 파묻히게 된다. 코드를 수정하려고 해도 어디를 건드려야할지 한참을 찾아야한다. 라면 물을 끓인다는 것만 알면 되는데 불을 어떻게 지펴야 하는지까지 설명하고 있는 셈이다.

‘왜 자석은 서로 밀어내는가?’란 기자의 질문에 리처드 파인만이 대답을 한 영상에서도 비슷한 의미를 찾을 수 있다. 같은 질문이라도 질문자가 누구냐(물리학 전공자, 일반인, 외계인 등)에 따라, 또는 질문자가 무엇을 알고 싶어하느냐에 따라 설명은 천차만별이 된다. ‘그건 그냥 그런거야’와 같이 한마디 답변이 될 수도 있고, 설명이 꼬리에 꼬리를 물고 끝도 없이 자세하게 설명할 수도 있다.

본인이 쓴 코드가 적절한 수준의 로직만 드러내고 있는지 고민해보자. 함수의 역할에 맞는 작업만 하고 있는지, 아니면 온갖 세부 로직을 장황하게 늘어놓고 있는게 아닌지 살펴보고 손봐야 한다. 그런데 ‘적절한 수준’이란 것엔 정답이 없다. 코드가 속해있는 클래스나 모듈에 따라 다르다. 코드를 읽는/쓰는 사람의 역량에 따라서도 달라질 수 있다. 누구에게는 간결한 코드가 누구에게는 더 이해하기 어려운 코드일 수 있다. 코드를 리팩토링 하다보면 또 기준이 바뀔 수도 있다. 모든게 유동적이다. 딱 떨어지는 기준은 없지만 독자의 입장에서 자신의 코드를 한번이라도 더 읽어보고, 함수를 짧게 만드는 연습을 하고, 동료끼리 코드 리뷰를 하면서 적절한 수준으로 맞춰갈 수 있다.

객체는 하나의 책임만 가져야 한다는 단일 책임 원칙을 지키는게 결코 쉽지는 않지만 함수 단위에서부터 시작해보자. 함수를 간결하게 만들수 있게 됐다면 다음으로 클래스 수준에서도 적용해본다. 단일 책임 원칙은 모든 패턴이나 아키텍처의 시작이다. 즉 단일 책임 원칙을 지키지 못하면 어떤 패턴을 쓰던, 어떤 아키텍처를 도입하던 시간이 흐를수록 결국 스파게티 코드가 될 확률이 높다. 언어 문법도 코드를 더 간결하게 표현하기 위한 수단으로써 공부를 하면 길을 잃지 않을 수 있다. 함수를 짧게 만들고 클래스를 작게 만드는 연습을 많이 하자.

같이 읽어볼만한 글

스위프트로 다시보는 객체지향 프로그래밍: 피해야할 코딩 습관

Sourcery 개발자로부터 배우는 모바일 아키텍처와 개발자 경험

iOS 개발자라면 한번은 들어봤거나 써봤을 오픈소스 툴 Sourcery를 만든 Krzysztof Zabłocki와 팟캐스트 녹음을 했는데 작년 엉클밥을 봤을 때와 비슷한 큰 자극와 영감을 얻었습니다. Krzysztof는 좋은 앱 아키텍처와 개발자 툴을 만들어서 개발자 경험을 개선하는 것에 목표를 두고 여러 툴을 만들면서 현재 뉴욕타임스에서 iOS 팀을 리딩하고 있는 개발자입니다.

잘못된 선택보다 올바른 선택을 하는게 더 쉬운 구조가 좋은 아키텍처다.

이 분은 모바일 아키텍처와 프로그래밍을 굉장히 실용주의적인 관점으로 해석하고 실행에 옮기시는 분이란 인상을 받았습니다. 그는 좋은 아키텍처를 구분하는 기준은 그 아키텍처를 쓰는 개발자가 얼마나 행복한가로 판단해야 한다고 합니다. 또한 좋은 아키텍처란 ‘잘못된 선택보다 올바른 선택을 하는게 더 쉬운 구조’라고 합니다. 왜냐면 인간은 여러 갈래가 있을때 쉬운 길을 택하는 경향이 있기 때문이죠. 좋은 코드를 짜기 위해 아키텍처와 싸워야하는게 최악의 상황이라고 합니다.

그래서 이분이 지금까지 만든 것들을 보면 의외로 간단한 아이디어에서 시작하지만 매일 매일 프로그래밍하는 개발자들의 생산성을 증가시켜주거나, 불필요한 반복 작업을 줄여서 실수를 줄여주거나, 코드를 좀 더 좋은 구조로 짜게 강요(?)하는 마법을 부리는 것 같습니다. Protocol extension으로 앱 로깅을 담당하는 싱글턴 객체를 숨기면서 유닛테스트도 할 수 있게 해주는 방법이라던지, 유저가 버그 리포트를 했을 당시 유저의 앱의 상태를 복원할 수 있는 데이터 스냅샷 기능 등을 보면 기존 코드를 많이 뜯어고치지 않는 간단한 방식으로 팀 전체의 개발 및 디버깅 경험을 개선시켜줍니다.

애플 엔지니어들마저 베껴간 Sourcery

더 대단하고 인기 많은 툴도 있습니다. Sourcery라는 툴은 스위프트에서 Equatable이나 Codable 프로토콜 등을 쓸 때 자동으로 구현 코드를 생성해주는 툴입니다. 지금이야 스위프트 자체에서 지원하는 부분이 있지만 초창기에는 디폴트 구현를 지원하지 않아서 모든걸 다 수동으로 구현해줘야 했을때 만들었다고 합니다. 이걸 만들고 얼마 지나지 않아 애플 엔지니어들마저 내부에서 사용하기 시작했다고 합니다. 재밌게도 그걸 알게된건 애플 엔지니어들이 회사 정책 때문인지 오픈소스에 직접 PR을 보내진 못하고 트위터 비공개 DM으로 패치를 보내주면서 버그를 고쳐 달라고 요청이 들어오기 시작했다네요.

애플의 거짓말을 들춰낸 Objective-C Playground

또 하나 놀라운 일화는 애플이 WWDC에서 스위프트 플레이그라운드를 발표하면서 옵젝씨로는 이런거 못한다고 말한걸 듣고 빡쳐서 불과 12시간만에 옵젝씨 플레이그라운드를 만들어버림으로써 애플이 틀렸다는걸 증명해버렸습니다. 이 프로젝트는 옵젝씨 뿐 아니라 스위프트까지 지원하고, 애플에서 만든 스위프트 플레이그라운드와는 비교도 안되게 훨씬 빠르다고 자랑합니다. 심지어 플러터처럼 앱 hot reloading도 할 수 있게 해버렸네요. ‘Code Injection’이라는 키워드를 처음 배웠습니다.

iOS 아키텍처와 테스팅

마지막으로 이 분은 iOS 개발을 하기 전에는 게임 엔진도 만들고 그래픽 개발도 하고 웹/백엔드 개발도 해봤는데, 모바일 진영이 그 중 제일 테스트코드 짜기를 꺼려하는 분위기라고 합니다. 그 이유 중 하나는 아마도 애플이 제시하는 MVC가 테스트하기 극도로 안좋은 아키텍처이기 때문인거 같다고 하네요. 일단 테스트가 잘 되려면 UIKit과 완전히 분리된 로직만 담당하는 클래스가 있어야하는데 “애플의 MVC”는 기본적으로 injection도 없고 composition도 없어서 그게 어렵다는 의견을 제시합니다. 그럼 대체 애플은 왜 십 수년간 MVC만 미는가, 좀 더 나은 아키텍처를 밀어주는 변화는 없을까란 질문에 대해서도 꽤 그럴듯한 답변을 내놨습니다.

일단 MVC 외에 인기있는 주류 아키텍처로는(2017년 발표 당시) MVVM과 VIPER(또는 여타 unidirectional architecture)가 있는데요. 먼저 MVVM은 FRP스러운 바인딩이 있어야하는데 이건 잘 만들기도 어렵고 당장 UIKit과 잘 맞지 않아서 후보가 될 수 없고, VIPER는 어려워서 배우기 쉽지 않다고 합니다. 애플은 신규 개발자들이 애플 플랫폼에 쉽게 들어오기를 바라기 때문에 이렇게 어려운 아키텍처를 밀어줄리는 없다고 하네요. 아키텍처에 대한 폭넓은 인사이트는 몇 년 전에 했던 인기 많았던 발표를 참고하시면 되겠습니다. Good iOS Application Architecture: MVVM vs. MVC vs. VIPER. 2020년 현재, Combine과 SwiftUI가 생겼으니 MVC를 벗어나기 쉬워졌을까요?

바로 오늘 도움이 되는 실용적인 코드와 툴을 만들어내는 개발자

이분은 프리랜싱과 컨설팅을 한 적이 있어서 그런지 개발 생산성과 코드 재사용성을 끌어올리는 아키텍처와 tooling에 전문가셨고, 특히 본인이 필요해서 만든 툴로 인해서 얼마를 벌었다는걸 구체적인 액수로 말하는게 정말 인상적이었습니다. 왜냐면 프리랜서는 시간이 수입으로 직결되니까 툴을 만들어서 매일 반복 작업으로 쓰이던 시간을 줄이거나 예전 프로젝트에서 썼던 코드를 재활용할 수 있게 되면 그게 곧바로 수입으로 계산될 수 있기 때문이겠죠. 엉클밥이나 GoF 옹들이 이론과 이상향을 제시하는 분들이라면 Krzysztof는 그 이론과 디자인 패턴을 바탕으로 당장 오늘 도움이 되는 실용적인 코드와 툴을 만들어내는 개발자 같았습니다. 특히, 매일 해야하는 디버깅과 코딩에서 최대한 반복 작업을 없애고 좋은 아키텍처가 퍼질 수 있게 꾸준히 무언가를 만들고 고민하는 모습에서 정말 큰 영감을 얻을 수 있었습니다.

Tags: mobile architecture, developer experience, Krzysztof Zabłocki  

개인과 팀이 성장하는 모바일 개발 환경

어제 페북에 들어갔다가 어느 회사 iOS팀의 채용 공고를 보게 됐다. 보통 채용 공고는 훑어보면 복지, 기술 스택 등의 키워드 위주로만 몇 개 눈에 띄는데 이 채용 공고는 기술 블로그처럼 내용이 술술 읽혔다. 예전 팀에 있을때 도입하고 싶었던 많은 것들이 이미 구축되어 있었다. 혼자서 팀원들을 설득해가면서 조금씩 도입해봤기 때문에 이만큼의 모바일 개발 환경을 구축하는데에 많은 노력과 시간과 시행착오가 들어갔을 거라는걸 알았다. 고개를 끄덕이면서 읽다가 문득, 내가 쪼렙일때 이 글을 읽었다면 어땠을까란 생각이 들었다. 경험이 부족하고 아는게 별로 없으니 뭐가 좋은건지, 이게 나한테 어떤 영향을 주는지 잘 몰랐을거 같다. 그동안 이런 개발 환경이 있을 때와 없을 때를 다 경험해 봤기 때문에 이제는 안다. 이런 크고 작은 것들이 모여서 내가 회사에서 보내는 시간의 질을 결정한다. 단순하고 반복적인 일이 적고, 개발 도중 흐름을 끊는 사건이 적어야 한다. 그래서 개발에 집중할 수 있는 시간이 많이 확보되는게 업무 시간의 질이고 이 시간이 개발자의 성장과 연결된다.

배포 자동화

“매 커밋마다 모든 코드가 테스트되며, 하루에도 수십 번 구성원들에게 개발 중인 빌드가 공유됩니다.”

배포 자동화는 클릭 한번(혹은 0번)으로 앱을 빌드하고 내부 사용자나 외부 스토어까지 바로 전달할 수 있는 환경을 의미한다. 배포는 단순하고 반복적이면서 자잘하게 시간이 오래걸린다. 예전 팀에 처음 갔을때는 반만 자동화되어있었다. 앱을 배포하려면 먼저 앱 버전이나 빌드 넘버를 올려줘야하는데 이걸 누군가가 수동으로 커밋을 하고, PR을 만들고 규칙에 따라 굳이 테스트도 다 통과해야하고, 마지막으로 또다른 개발자가 PR을 승인 해줘야 비로소 버전을 올릴 수 있었다. 프로세스가 이러하다 보니 구성원들에게 앱을 전달하려고 할때마다 무려 개발자 두 명의 업무 흐름이 끊어졌다. 이런 방법에 문제를 느껴서 꾸준히 개선을 해나갔고 결국에는 시리로 배포를 할 수 있을 정도로 자동화를 해서 배포에 소요되는 노력과 시간을 엄청 줄였다.

개발에 몰입하려면 방해받지 않는 연속된 시간이 정말 중요하다. 특히 개발자에게 30분 두 번은 1시간과 결코 같지 않다. 하루에 수십 번 빌드가 공유된다는건 배포가 완전히 자동화돼있어서 개발자는 업무 중에 배포에 신경쓸 일이 없다는 뜻이고 구성원들도 다른 팀원을 방해할 필요없이 가장 최신의 앱을 설치해볼 수 있다는 뜻이다. CI/CD가 구축되어 있어서 이런 종류의 자잘한 방해 업무가 최대한 없는게 좋은 환경이다.

피쳐 플래그

“피쳐 플래그를 도입하여 사용자에게 매주 배포할 수 있는 환경을 만들었습니다.”

피쳐 플래그란 백엔드가 내려주는 불리언 값으로 앱의 기능을 껐다 켰다 할 수 있는 장치다. 피쳐 플래그가 없으면 어떤 기능이 개발되는 동안에는 마스터 브랜치에 코드를 밀어 넣을수 없어서 별도로 피쳐 브랜치를 관리해야 한다. 기능이 규모가 크고 개발이 오래 걸릴수록 점차 마스터와 피쳐 브랜치가 멀어져서 나중에 합칠때 많은 고생을 한다. 심지어 머지 컨플릭을 잘못 수정해서 코드가 유실되고 기능이 망가지는 일도 겪어봤다. 이런 일을 겪고나면 마스터 브랜치에 코드를 병합하는 일이 중대한 일이 돼서 걱정과 두려움도 생긴다. 열심히 개발해서 테스트까지 잘 마쳤는데 코드 머지하는 마지막 단계에서 문제가 발생할 수 있다는건 개발자를 위축시킨다.

개발 인원이 적어서 한번에 기능 하나만 개발할 수 있고 그 사이 앱을 배포할 일이 없다면 이런 환경의 필요성을 느끼지 못할 수 있다. 그러나 피쳐 플래그가 구축되어 있으면 여러 개발자가 동시에 각자 다른 기능 개발을 하면서도 마스터 브랜치 하나만 유지하면 되기 때문에 브랜치 관리가 훨씬 쉽고 그 와중에 실배포도 무리없이 할 수 있다. 개발이 덜 된 코드가 있더라도 백엔드 값을 통해 미완성 기능을 유저한테 숨길 수 있기 때문이다. 이렇게 되면 개발자는 브랜치 관리나 머지 컨플릭 등에 신경을 덜 쓰고 온전히 개발에 더 집중할 수 있다. 피쳐 플래그의 또 다른 장점은 출시된 기능에 문제가 발견됐을때 임시 방편으로 기능을 꺼버려서 유저한테 미치는 영향을 줄일 수 있다는 점도 있다.

코드 리뷰와 짝 프로그래밍

“코드 리뷰는 iOS 팀의 핵심 문화입니다. (중략) 페어 프로그래밍을 종종 활용합니다.”

이민석 이노베이션아카데미 학장님은 ‘리뷰 없이 만들어진 코드는 사채다’라는 말을 하셨다. 정말 공감가는 말이었다. 업계에서 기술 부채라는 용어를 쓰는데, 개발자 한명이 혼자서 만든 코드는 고리대금 악성 사채처럼 기술 부채를 많이 발생시킨다는 뜻이다. 자신이 짠 코드를 자신과 동일시 하거나 지나친 애착을 가지고 변화로부터 보호하려는건 정말 좋지 않다. 코드는 팀원들 모두와 공동명의로 된 자산이라는 생각으로 다뤄야한다. 코드 리뷰를 하면 기술 공유가 되고 팀이 전체적으로 같이 성장한다. 개발하다 보면 가끔씩 자만감에 ‘이건 진짜 완결성 있게 만든거같다. 리뷰에서도 별다른 의견이 나올만한 부분이 없겠지’ 싶은데도 다른 동료의 눈에서 개선점이 발견되고 새로운 아이디어가 생기고 몰랐던 기술을 배울수 있다. 서로의 코드를 보여주지 않고 지적하지 않으면 개인으로나 팀으로나 성장할 수 없다.

짝 프로그래밍은 코드 리뷰의 상위 호환이다. 개발 실력이 비슷한 두 명이 하는것보다는 비대칭적인 실력을 가진 두 명이 하는게 효과적이다. 구글에서는 짝 프로그래밍을 거쳐 만들어진 코드는 코드 리뷰 승인을 받은 것으로 간주한다고 한다. 짝 프로그래밍까지는 아니지만 내가 신입일 때 사수님이 옆자리에 앉혀놓고 코딩을 하고 디버깅을 하는 모습을 보여준 경험에 대해서는 예전 글에서도 언급한 적이 있는데 정말 큰 도움이 됐고 아직까지 기억에 남는다. 얼마 전에는 내가 알려주는 입장에서 신입 개발자와 짝 프로그래밍을 했는데 반응도 좋았고, 나도 생각을 정리하고 설계를 더 탄탄하게 할 수 있는 좋은 계기였다. 시니어 개발자와 하는 짝 프로그래밍은 주니어 개발자에게 정말 값진 시간이다. 나보다 잘하는 사람으로부터 기술과 노하우를 1대1로 전수받고 질문도 마음껏 할 수 있는 기회는 어디가서 돈 주고도 못 산다.

단순하고 반복적인 일이 적고, 온전히 개발에 오래 집중할 수 있는 시간이 많은게 좋은 환경이다.

그러기 위해서는 반복적인 업무를 자동화하는게 필수적이다. 또한 코드 리뷰 문화가 자리 잡혀 있으면 개인은 물론 팀이 전체적으로 같이 성장할 수 있다. 위 기준와 사례를 통해서 어떤 회사를 가야할지, 어떤 팀에 가야할지, 혹은 어떻게 자신의 주변 상황을 개선해야 더 성장할 수 있을지 고민인 주니어 개발자분들에게 도움이 됐으면 한다.

Tags: mobile platform, growth, mobile ci/cd  

How to search files in Xcode

Some of the most useful “Power Xcode Tricks” from the try! Swift World online workshop by @ericasadun

Search Scope

Create custom scopes
You can create custom search scope to limit your search within a subset of your code. For instance, create a scope to search only within your small team's scope.
Exclude certain files ⭐️
Xcode doesn't provide out-of-the-box filter functionality for this. But you can use regex to exclude certain files to create useful search scopes. For example, you can exclude test files from your search.
Other handy search scopes
Tests Only, Swift Only, Objective-C Only, headers, etc.
Search history
Related items

Navigation Pane

Find files with keyword
Find files with keyword X or Y
Wildcard
Recenty opened files
Modified file
Open sibling folders ⭐️
This functionality applies to everywhere with the similar triangle (e.g. Find tab in Navigator Pane, etc)

Open subfolders ⭐️
This functionality applies to everywhere with the similar triangle (e.g. Find tab in Navigator Pane, etc)

Others

File history
Reveal in Project Navigator ⭐️
Edit all in scope

Tags: xcode