스타트업 5개월차 iOS 개발자의 2023년 회고 - 1부 : 취업 준비 기간
안녕하세요 Duno입니다. 오랜만에 Public한 글을 쓰게 되었네요. Obsidian이나 노션에 Private하게 작성해 두고 올리지 못한 글이 아주 많습니다..! 올해에는 많은 분들께 도움이 될 글을 많이 작성할 수 있기를 바라며, 그 스타트를 2023년 회고로 끊겠습니다.
우선 작년 말에 쓰려고 마음먹었던 회고를 지금에서야 쓰고 있는 저.. 반성합니다. 사내 연말 달리기 프로젝트, 새로운 집 계약 등으로 연말을 정신없이 보냈더니 회고를 쓸 힘도 남아있지 않았었네요 하하. 2023년 회고라고 썼지만, 2023년부터 오늘(2024.01.20)까지의 회고를 남기려고 합니다.
개인적으로 월별 회고를 작성하고 있었는데, 연간 회고를 작성하려니 월별 회고 기록의 존재가 이보다 든든할 수가 없네요. 회고 작성 전에 작년의 기록들을 슬쩍 살펴보니, 작년 상반기는 취업에 모든 힘을, 취업 이후에는 지속 가능한 성장에 모든 관심을 쏟아온 것 같습니다. 그래서 주제가 확연히 구별되는 반기 단위로 내용을 써내려 가보겠습니다.
1부에서는 깊이 있는 고찰보다는, 취업 준비 기간에 대해 정리하는 느낌으로 작성했습니다.
타임라인
1월 - SOPT 공식 앱 릴리즈 - SOPT Makers 2기 모집 tf팀 활동 - 취업 준비를 본격적으로 시작하기 위한 계획 - SwiftUI 스터디 시작 - '지구는 둥그니까' 프로젝트 팀 결성 - 서류 2곳 합격 및 모두 포기 |
2월 - 대학 졸업 - Recordream 앱 릴리즈 - '지구는 둥그니까' : 첫 SwiftUI 프로젝트 구조 설계, 모듈화, CI/CD 구현 - 코딩테스트 60문제 |
3월 - 코딩테스트 40문제 - TCA 학습 및 프로젝트 구현 - SOPT 공식 앱 : Feature 모듈 분리 설계, Interface 모듈 활용 - RIBs, ReactorKit, TCA 학습 -> 나만의 단방향 데이터 플로우 모듈 설계 - 포트폴리오 개선 - 과제 전형을 위한 기본 프로젝트, 체크리스트 준비 - 메이커스 온보딩 - 당근 경력 서류 합격 |
4월 - 당근 과제 탈락 - 네이버 공채 서류 + 코테 합격 - 면접 대비 CS 공부 - tuist + 모듈화 + XcodeProject에 대한 Deep dive - tuist에 contribute - WatchOS + ChatGPT 미니 프로젝트 |
5월 - 카카오 브레인 서류 합격, 과제 탈락 - 네이버 면접 탈락 - 지구는 둥그니까 뷰 구현(메인, 설정) |
6월 - 블루시그넘 서류, 과제, 최종 합격 - 이후 방향성에 대한 고민 + 휴식 |
취업 준비 이야기
취준 결과 정산
서류 탈락 | 과제 탈락 | 면접 탈락 | 최종 합격 |
크래프톤 경력 네이버 Z 경력 카카오 모빌리티 경력 네이버웨일 경력 카카오뱅크 경력 크림 경력 공채 오늘의 집 경력 KT 경력 SKT 경력 카카오 헬스케어 경력 토스 경력 |
당근 경력 카카오브레인 인턴(과제형 코테) * 서류 합격 + 전형 포기 SK 브로드밴드 신입 KT 신입 공채 다우기술 |
네이버 공채 : 1차 면접 탈락 * 전형 포기 비누랩스 |
블루시그넘 |
죄송하지만 대뜸 결과부터 보여드렸습니다. 이렇게 보니 많이도 지원했고, 많이도 떨어졌네요. 지금도 그렇지만 작년 상반기에는 iOS 개발자 공고 자체가 귀했기 때문에, 경력 3~5년차 공고까지도 일단 지원하고 봤습니다.
취업 준비 초기에는 많은 개발자 취준생 분들이 그렇듯, 가능하면 대기업 - 같은 포지션의 선배 개발자들이 많은 곳을 목표로 했습니다. 그러나 여러 기업에 대한 탈락이 누적되고(대부분 경력이었지만), 많은 고민과 몇 번의 전형 포기를 거치면서 깨달았습니다. 제가 'iOS 개발을 하면서, 지속가능한 성장을 이룰 수 있는 회사'를 원한다는 것이었습니다. 제가 전공을 바꾸고 개발자가 되려한 가장 큰 이유가 개발의 즐거움이었고, 취업 조건에서도 '개발'이 주가 되어야 한다는 것을 후기에야 깨달았습니다.
앞서 말씀 드렸지만 대기업을 가고 싶었던 이유 중 하나는 '성장'입니다. 학생 시절부터 지금까지 저는 성장하는 저를 확인하는 일을 참 좋아해 왔습니다. 빠른 성장을 위해서는 규모 있는 앱을 운영하는 대기업에 취업하여, 시니어분들과 함께 일하면 배우는 것이 많을 것이라 생각했습니다. '성장'이라는 항목에 대해서는 스타트업보다 대기업이 무조건 우위라고 생각했죠. 물론 지금은 그 생각이 달라졌고, 이에 대해서는 2부에 서술하겠습니다.
그럼에도 당시의 저는 스타트업이 나름의 장점을 가질 것이라고 판단했습니다. 문제는 좋은 스타트업이 있다면 입사하고 싶었지만, '좋은 스타트업'을 구별할 방법이 없었다는 것입니다. 그래서 스타트업 지원을 보류하고 있었습니다.
그러다 힘을 많이 쏟았던 네이버 공채에 떨어졌습니다. 번아웃도 조금 온 것 같았고 다른 기업의 공고도 없던 시점이었지만, 가만히 있으면 아무 일도 되지 않을 것이기에 새로운 자극이자 지향점이 필요하다고 생각했습니다.
고민을 거듭하다 전부터 존재를 알고 있던, 동문께서 창업한 회사에 지원했습니다. 그러니 감사하게도 전형에 앞서 커피챗 요청을 주셨습니다. 편하게 진행하면 된다고 말씀해주셨지만 커피챗은 처음이었기에 나름 긴장하고 커피챗을 준비(지금 생각하면 과했나 싶지만 회사가 사용중일 가능성이 높은 기술 공부, 컬쳐덱, 뉴스 기사 정독)했습니다.
그렇게 긴장하면서 나갔던 커피챗에서는, 배려를 많이 해주셨던 덕분에 편한 분위기에서 대화를 나누고 올 수 있었습니다. 회사에 대해 설명해주셨고, 저도 회사에 궁금한 것을 질문하며 유익하고 즐거운 시간을 보냈던 것 같습니다. 커피챗 후에는 마법같이 회사에 대한 열의가 솟구쳐서 익숙하지 않은 SwiftUI로 과제도 열심히하고, 면접도 보고, 결국 최종 합격을 할 수 있었습니다.
회사 이야기, 스타트업 이야기는 2부에서 제대로 다루겠습니다.
취업 준비 기록
코딩테스트
취준 초기에는 코딩테스트가 가장 걱정이었습니다. 제 행동 양식의 기반이 되는 철학 중 하나는, '남들과 동일한 노력, 동일한 방법으로는 높은 이상을 거머쥘 수 없다'는 것입니다. 그래서 초기에 여러가지 공부 방식을 연구하고 시도했고, 시간 투자도 많이 했습니다. 이 때의 노력 덕분인지 취준 후기에는 코딩테스트가 더 이상 두렵지 않았습니다. 네이버 공채 코테를 뚫은 이후로 코테에는 자신감도 붙어서, 코테를 요구하는 전형이 오히려 기다려질 정도였습니다(물론 이후에 코테를 볼 일이 없었지만요). 취업 이후에도 간간이 풀어본 코테에 대한 적중률이 높았던 것을 봐서는(예를 들어 최근에 있었던 카카오 코테에서도 80% 이상 정답을 도출해 낼 수 있었습니다), 제 방법이 꽤 유효하지 않았나 싶습니다.
아래는 코딩테스트를 공부했던 방식입니다.
1. 프로그래머스 0, 1레벨 문제를 익히고, 개념을 추출 및 추상화하여 어려운 문제에 도구로 사용한다.
2. 프로그래머스 다른 사람의 풀이에서 나보다 나은 점을 찾는다. 1개의 문제를 풀어도 10개의 다른 모범 답안으로부터 배우자.
3. 자료구조는 고민 없이 손만 움직이면 구현할 수준으로 연습한다.
4. 많이 푼다. 반복되는 패턴을 인지할 수 있게 뇌를 세팅?하자.
5. 이렇게 푼 문제가 쌓이면, 풀면 좋을 것 같은 문제를 구분할 수 있다. 유익한 문제만 골라서 푼다.
6. 마찬가지로 문제 유형도 많이 풀면 보인다. 문제를 직접 푸는 것이 아니라 문제 유형만 빠르게 골라내는 연습도 꽤 도움이 됐다.
7. 문제를 풀었으면 노트 테이킹을 통해 꼭 나와의 대화를 이끌어내자. 아래와 같이 특정 문제를 풀고 배운 점을 간략하게 정리하면 코테를 오랜만에 준비할 때도 뇌를 다시 코테에 익숙했던 때로 돌리기 편해진다. 사진에는 간단한 문제라 드러나지 않았지만, 문제 난이도가 높아질수록 스스로의 사고 방식에 대한 질문을 늘려나가자. (ex: 문제를 풀 때에는 왜 XX라고 생각했을까?)
코딩테스트도 수학처럼 반복을 통해 숙달할 수 있는 영역이라고 생각합니다.
포트폴리오 준비
iOS 신입의 수준이 상향평준화 되는 시점에서 저만의 차별점을 두고자 했습니다. 제가 어필하고 싶었던 부분은 아래와 같습니다.
1. 기술을 빠르게 익힐 수 있고, 공부를 좋아하는 사람이다. 개발이 좋아서 하는 사람이다.
2. 무턱대고 기술을 적용하는 것이 아니라 이해하고 고민하는 사람이다.
3. 적어도 하나의 카테고리에 대해서는 돋보이는 깊이가 있다.
포트폴리오, 이력서는 특정 기업에 지원을 할 때마다 조금씩 바꿔가면서 냈고, 가능하면 피드백을 많이 받으려 노력했습니다. 주변 개발자 분들께 피드백을 요청하고, 오픈채팅방에 도움을 요청하기도 했었네요. 꽤 열심히 살았습니다.
과제 전형 준비
과제 전형 준비도 나름 철저하게 했습니다. iOS 과제 전형은 보통 뷰 구현으로 진행되고, 공개 API를 통한 서버 통신, 복잡한 UI 구현, 특정 패턴 사용 등을 요구합니다. 각 기업이 요구하는 기술 스택으로 이를 구현하고자 했고, 서드파티를 사용하지 못하는 경우도 대비하여 미리 템플릿을 만들어 뒀습니다.
과제 전형의 장점은, 결과가 어떻든 간에 효율적인 성장이 따라왔다는 것입니다. 짧은 시간에 자신이 낼 수 있는 최상의 집중력을 이끌어 낼 수 있기에, 취준생의 입장에서는 꽤 좋은 성장 장치였습니다. 물론 그렇기에 과제 전형이 겹치지 않도록 전형 일정을 잘 계획해야 합니다.
CS 공부
비전공자이기에 CS를 더욱 철저히 공부하려고 노력했습니다. Github에 있는 면접 준비 레포를 모두 살펴보며 질문을 정리했고, 개발 블로그와 대학 강의 및 교재, ChatGPT를 사용하여 모범 답안을 만들었습니다. 이러한 질문-답안 구조를 뼈대로 하여, 효율적으로 복습할 수 있도 마인드맵으로 구성했습니다. 결과적으로 아래 사진과 같은 마인드맵이 과목별로 6개 정도 탄생했습니다.
비록 떨어졌지만 네이버 공채 면접을 준비하면서 어지간한 CS 문제는 모두 대답할 수 있도록 준비를 했었기 때문에, 다른 회사에는 CS에 대한 부담 없이 편하게 지원할 수 있었습니다.
감상
약 반년 가까이 취업만을 보고 달려왔던 사람으로서, 그때의 저에게 해주고 싶은 말들이 있습니다.
1. 독서하자
취준생은 취업이라는 명확한 목표를 향해 달려나가고, 그 과정에서 코테, CS, 포트폴리오와 같은 작은 문제를 해결해 나갑니다. 이와 같이 작은 단위들에만 몰두하다 보면, '자아'와 '삶'에 대해 잊기 쉬워집니다. 제가 그랬었기에, 과거의 저에게 독서를 권하고 싶습니다. 당시에는 책 읽을 시간도 아깝다며 공부를 했었지만, 최근에 독서에 취미를 붙이게 되니 이렇게 소중한 것이 또 없네요.
독서를 통해 조금이나마 자신의 일상을 타자의 시선에서 바라볼 수 있게 됩니다. 동시에 커다랬던 '취업'이라는 목표를 하나의 과정으로 여길 수 있게 되고, 보다 안정적인 멘탈을 통해 더 집중할 수 있었을 거라 생각합니다.
2. 내 꿈은 좋은 회사에 다니는 개발자가 아니라, 좋은 개발자이다.
취업 준비생의 입장에서 '취업'이라는 것은 굉장히 높은 문턱과 같이 느껴집니다. 그리고 취준생들은 좋은 회사에 취업한다는 단일 목표만을 위해 달려나가는 경향이 있습니다. 내 목표를 더 크게 바라보고, 일상에서 이따금 떠올릴 수 있으면 취업의 과정을 조금 더 무던히 받아들일 수 있을 것습니다. 특정 회사에 지원하여 합격하든 탈락하든, 모두 더 좋은 개발자에 한 걸음 다가선 것이기 때문입니다. 적어도 스스로에게는 회사가 아니라 내가 중심이어야 합니다.
목표가 오직 취업이었기에, 역설적이게도 취업이 어려워지게 하는 약점이 생깁니다. 취업을 하나의 과정으로만 생각한다면, 특정 기업의 전형에서 탈락해도 겸허히 받아들일 수 있습니다. 비슷한 맥락에서 취업 이후에 오는 허무감도 방지할 수 있지요!
6개월 간의 기술적인 성장
아래 사진에는 제 소중한 잔디들이 담겨있는데, 회사에 최종합격한 7월에 구멍이 송송 뚫려 있는 것이 꽤 재밌네요.
과연 1월부터 6월까지의 저 잔디들이 무엇을 담고 있는지 정리해보려고 합니다. CS와 코딩테스트 외에 저는 아래와 같은 기술들에 관심이 많았습니다.
모듈화
모듈화, 아키텍쳐, 객체지향은 저의 주요한 관심사였습니다. 그 중에서도 대규모 협업을 가능케 하고, 소스코드를 물리적으로 분리하고 빌드 시간을 줄이며, 그 자체로 하나의 context를 제공하는 모듈화에 푹 빠져있었습니다.
모듈화하면 빠질 수 없는 Tuist는 당시의 저에게 신과 같이 느껴졌습니다. 협업 시에 프로젝트 파일의 컨플릭트가 나지 않는 것만으로도 감사한데, 모듈화라는 새로운 가능성을 열어준 것이었지요. 사실 저는 XcodeProject에 대한 심층적인 이해에 앞서 Tuist를 먼저 사용한 꼴이었기에 처음부터 이해하기는 어려웠습니다. XcodeProject에 대한 이해가 쌓이고, '아 이래서 Tuist가 그렇구나'하는 순간이 찾아올 때마다 즐거웠습니다. nm, otools와 같은 명령어를 통해 프레임워크 및 번들을 분석하기도 하고, Tuist가 아닌 SPM를 통한 모듈화도 해보며 이해를 쌓아나갔습니다.
Tuist와 모듈화, XcodeProject에 대한 이해가 어느정도 올라오고 나서는 마이크로 Features에 대해 고민하게 됩니다. 어떻게 하면 Feature들이 서로 독립적으로 동작할 수 있을지 많은 고민을 했습니다. Swinject, Needle 등을 참고하며 의존성 주입에 대해 고민한 결과, ViewController를 추상화하고 각 모듈에 Builder를 만들어 Feature를 나눌 수 있게 됩니다.
당시에는 인터페이스 모듈에 대한 자료가 많지 않았어서 꽤 뿌듯했었던 기억이 있네요. 이후에는 서로 다른 Feature 간의 화면전환을 담당할 Coordinator를 설계해서 앱에 추가했습니다. PR을 보면 명세도 꽤 열심히 작성했고, 열렬한 고민의 흔적이 남아있습니다. 당시 앱의 기능이 꽤 붙어있던 상황이라 2700줄이 추가되는 큰 작업이었네요.
이러한 관심이 쌓이며 자연스레 Tuist repo에 간단한 기능이나마 추가해보는 일을 했습니다.
회사에 와서 가장 먼저 한 일 중의 하나가 Tuist 적용과 간단한 모듈화였지만, 이제는 Tuist 및 모듈화가 개발자가 사용할 수 있는 여러 도구 중의 하나일 뿐이라고 생각하게 되었습니다.
아키텍쳐와 패턴
개발 공부 10개월차 즈음에 엉클 밥의 클린 아키텍쳐를 처음 접하면서 '좋은 구조란 무엇일까?' 라는 질문을 늘 가슴 속에 가지고 다니게 됩니다. 취준 초기에는 클린 아키텍쳐, Combine 또는 RxSwift를 이용한 데이터 바인딩, MVVM 구조 정도가 제가 가진 아키텍쳐의 한계였습니다. 여기서부터 아키텍쳐에 대한 관심을 꾸준히 유지하며 바운더리를 늘려갔고, 결과적으로 아래와 같은 프레임워크 및 패턴을 익히게 됩니다
- SwiftUI에서의 MVI과 MVVM
- 후술할 TCA
- RIBs, ReactorKit
이러한 관심은 단방향 데이터 플로우로 이어졌고, 저만의 단방향 데이터 플로우를 구축할 수 있었습니다. 지금 보니 수정할 곳들이 많지만, 대충 아래와 같은 모양새입니다.
public
final class DetailReducer: Reducer {
public enum Action {
// View Action
case viewDidLoad
case cellTapped(index: Int)
// Internal Action
case _fetchBookDetail(DetailEntity)
case _fetchError
case _showPDF(index: Int)
}
public struct State {
public var isbn13: String
public var detailModel: DetailEntity?
public var showPDF: (index: Int, url: String) = (0, "")
public init(isbn13: String) {
self.isbn13 = isbn13
}
}
@Published
public var state: State
private let useCase: DetailUseCase
public init(
useCase: DetailUseCase,
initialState: State
) {
self.state = initialState
self.useCase = useCase
}
}
// MARK: - Reduce
extension DetailReducer {
public func reduce(_ state: State, _ action: Action) -> (State, Effect<Action>) {
var newState = state
switch action {
case .viewDidLoad:
return (newState, .task { [weak self] in
guard let self else {
return ._fetchError
}
do {
let result = try await self.useCase.fetchBookDetail(isbn: state.isbn13)
return ._fetchBookDetail(result)
} catch {
return ._fetchError
}
})
case let .cellTapped(index):
return (newState, .action(._showPDF(index: index)))
case ._fetchError:
return (newState, .none)
case let ._fetchBookDetail(entity):
newState.detailModel = entity
return (newState, .none)
case let ._showPDF(index):
guard let model = newState.detailModel,
model.pdf.count > index else {
return (newState, .none)
}
let url = model.pdf[index].url
newState.showPDF = (newState.showPDF.index + 1, url)
return (newState, .none)
}
}
}
SwiftUI와 TCA, Point-Free의 팬이 되다
SwiftUI 스터디 이후에, SwiftUI와 WatchOS, Widget을 모두 활용하는 사이드 프로젝트를 하나 시작했습니다. 그러고선 조금 도전적인 목표를 잡았는데, 바로 TCA의 사용이었습니다. 아마 그때에는 0.3.0 버전 정도 되었던 것 같은데, 몇 없는 자료를 보며 열심히 공부했습니다. 여기도 마찬가지로 tuist와 yFeature를 적용했는데, UIKit과 Coordinator를 사용할 때와는 다른 방식으로 구현해야 해서 설계가 즐거웠던 것 같습니다.
중요한 이벤트 중에 하나라고 생각하는 것은, Point-Free를 알게 되었던 것입니다. Point-Free에서 제공하는 강의들은 그때까지의 제가 가지고 있었던 '코드를 바라보는 시선'을 바꿔주게 됩니다. 한참 수준이 높은 개발자들을 보며, 나중에는 그들과 같은 실력을 가지고 싶다는 꿈을 가지게 됐어요...! 여러 강의 중에서도 특히 Algebreic Data Types이 저에게 큰 충격을 줬습니다. 다시금 공부 의지를 불태우게 되었죠.
HandyGPT : ChatGPT API로 워치앱 만들어보기
당시 ChatGPT가 한참 떠오르던 때에, SwiftUI와 WatchOS 공부도 할 겸 미니 프로젝트 하나 해보자는 생각으로 3일 정도를 몰두했습니다. 단축어와 핸드제스쳐를 통해 GPT와의 대화를 바로 실행하도록 했는데, 취준 생활에 나름 환기가 되었던 프로젝트였습니다.
여기까지 취준 후기인지 회고인지 모를 것이 되었지만, 2부에서는 조금 더 회고다운 회고로 돌아오겠습니다.