私は生涯を通じてテクノロジーに情熱を注いできました。 子どもの頃はTurbo Pascalから始め、その後は組み込みシステム、フロントエンド/バックエンド開発、機械学習のプロジェクトに取り組んできました。
iOS/macOSと出会ったのは、大学の短期講座がきっかけでした。 1か月もたたないうちに、新しい言語を習得し、Readdleでインターンシップを得ました。 その5年後、私はPrincipal Engineerになりました。 それでもなお成長を続けるために、新しいチームメイトのメンタリングや面接への参加、そしてリーダーシップスキルの向上に取り組んでいます。
Appleプラットフォームの経験がまったくない状態から今の役割に至るまでの道のりを通じて、自分の学び方を振り返り、成長を後押ししてくれた重要な方向性を整理してみようと思うようになりました。 自分の経験は、行き詰まりを感じていたり、次に何をすべきか迷っていたりするほかのエンジニアにとっても役立つはずだと私は考えています。
ここでは、私の助けになり、そして皆さんの助けにもなるかもしれない重要なアプローチとリソースを紹介します。
サイドプロジェクトが私の成長を加速させた理由
ミドルレベルに達した頃、私はキャリアの停滞にぶつかりました。 タスクは素早く効率的にこなせるし、バグも問題なく修正できるし、新機能のアーキテクチャ設計についても十分に理解できていると感じていました。 ですが、自分と本当のSenior Engineerを分けるものが何なのか、なかなか理解できませんでした。
その変化は徐々に起こりました。 振り返ってみると、その違いは仕事での大きなプロジェクトでも昇進でもなかったのだと気づきました。 それは、仕事以外の時間にコードを書いて過ごした積み重ねでした。
平日の夜や週末には、小さなプロジェクトを作っていました。純粋に楽しみのためのこともあれば、アイデアを試すためのこともありました。 こうしたサイドプロジェクトのおかげで、普段の担当範囲を超えた現実の問題に触れることができました。 そうした実践的な経験はそのまま仕事にも生き、見慣れない課題に取り組むときの強みになりました。
最も大きな学びは、ソフトウェア開発における多くのスキルが、単一の言語やプラットフォームに縛られないということでした。 いくつか例を挙げると:
- iOS/macOSアプリのアーキテクチャについて読んでいても、Web開発や組み込みシステムの中に似たようなパターンを見つけることは十分にあります。
- 機械学習の文脈で身につけたPythonの知識は、まったく別の分野でCIプロセスを自動化するために必要なスクリプトを素早く書く助けになります。
- オペレーティングシステムの基礎を知っていれば、どのプログラミング言語でも共通する問題の大きな分類を理解しやすくなります。 結局のところ、どんなプログラムも、言語に関係なく最終的には似た形でオペレーティングシステムとやり取りするからです。
- 私が最初のほうに読んだ本のひとつが、Effective Java—もう何年も使っていない言語についての本でした。 でもその本から、幅広く応用できるオブジェクト指向の原則を学びました。 そういう知識こそ、しっかり身につくものです。
- プログラミングを楽しめるなら、こうしたサイドプロジェクトは仕事のようには感じられないはずです。 私の経験では、最高のエンジニアとは、ものづくりと学ぶことが好きだからコードを書く人たちです。
あらゆることを学ぶ方法
人によって、ほかの人よりも学ぶのが速く見えることがあります。 それは新しいプログラミング言語かもしれないし、パターンやアーキテクチャかもしれないし、あるいはチェスの習得のように開発とはまったく関係のないことかもしれません。 私は、その理由は学ぶこと自体がスキルであり—鍛えられるメタスキルだからだと考えています。
自分自身の学習の歩みを振り返る中で、新しいテーマに取り組むときの繰り返し現れるパターンに気づきました。 これは、学校や大学で複数の分野を並行して学んでいた時期に、脳が似たパターンを最適化するようになったことに由来しているのだと思います。 そのおかげで、より速く学べるようになりました。
今では、新しいことを学ぶための明確なプロセスがあります。 このプロセス自体が画期的だとは思いませんが、そのおかげで学習にも自己成長にも、集中して意図を持って取り組み続けることができています。 このセクションでは、私の学習アプローチの3つの段階であるScreening、Structuring、Practiceについて説明します
スクリーニング
新しいスキルを学ぶとき、良い情報源を選ぶことは極めて重要な第一歩です。 ここでは、私の経験に基づくいくつかのおすすめを紹介します:
- ほとんどのトピックに関する情報は、無料で手に入ります。 その内容が本当に独自のものだと確信できるのでなければ、コースや講義にお金を払う必要があることはめったにありません。 ただ、学び始めたばかりなら、本当に価値のある洞察と質の低い内容を見分けるだけの目はまだ養われていないはずです。
- テキストベースの資料は、特に読むのが速い人にとって、動画よりたいてい簡潔で理解しやすいものです。 時間がたつにつれて、私は不要な情報を素早く流し読みしてふるい落とすことを覚えましたが、それは動画コンテンツではより難しいことです。
- 時間がたつにつれて、私は流し読みをして不要な情報を見分ける力を身につけましたが、動画素材では直線的で時間がかかるため、それはできません。 また、動画の中で適切な瞬間を探すよりも、テキストの一節をブックマークしたりコピーしたりするほうが簡単です。
- 特にプログラミングやテクノロジーの分野では、英語のリソースはほかの言語のリソースよりはるかに見つけやすいです。 だからこそ、英語を素早く読んで理解できることは必須です!
- 古典的な名著を飛ばしてはいけません。 何度もおすすめされる本(Clean CodeやDesign Patternsなど)は、今でも手に入る中で最良の教材であることが少なくありません。
- また、異なるテーマにまたがる自分だけの本のライブラリを作ることもおすすめします。 そうすれば、いつでも信頼できる資料を手元に置いておけます。 私は個人的に、パソコンの中にシンプルなフォルダを作って管理しています。
構造化
しっかりした情報源をいくつか集めたら、私はその情報を構造化します。 このプロセスには次のことが含まれます:
- 情報源を処理すること。 本や記事を読みながら、重要なポイントをブックマークで強調したり、後で参照できるようにノートに書き写したりしています。
- 情報を相互参照すること。 特にテーマが主観的な場合は、複数の解決策や視点を比較することがとても重要です。 複数の異なる情報源で一致している情報は、正しい可能性が高いです。 情報源どうしで内容が食い違うときは、たいてい、そのテーマについて自分自身の経験をもっと積むまで判断を保留します。 その後、理解が深まれば最適なアプローチを選べるようになります。
- 知識を一元化すること。 受け取った情報や見つけた情報をすべて分析するには、それらを一か所に保存しておく必要があります。 私は知識の一元化にObsidianを使っています。 無料ですし、markdown形式はとても便利だと感じています。
- 保存すること。 記事や役立つリンクは、たいていシンプルなmarkdownのリストに保存しています。 そうすることで、ブラウザ履歴を掘り返さなくても特定のリソースをすぐ見つけられます。 さらに、将来そのテーマに戻ったときには、すでにしっかりした土台が保存されています。
実践
読むだけでは足りません。 何かを作って初めて、本当に学べるのです。 私は、学ぶすべてのテーマを小さなプロジェクトを作ることで定着させるようにしています。 プログラミングに関していえば、これは通常、必要なスキルを適用できることを示すシンプルなアプリケーションを作ることを意味します。 短時間の実践でも、理解の穴はすぐに明らかになります。 必要なことはすべて理解したつもりでいても、実装を始めてわずか10分で思いがけない問題にぶつかることがよくありました。
特に印象に残っている例のひとつが、UIアーキテクチャを学んだことです。 iOS開発の文脈で初めてMVVMを学んだとき、私はそのアーキテクチャはシンプルでわかりやすいものだと思っていました。 でも、基本的なToDoリストアプリを作ってみようとしたとたん、知識の抜けにすぐ気づきました。 資料では、ViewがViewModelとどうやり取りするか、そしてViewModelがModelとどう関わるかは説明されていましたが、何を誰がどう作るべきなのかについては、どれも触れていませんでした!
私のアプリには、現在のToDoタスクを表示するテーブルがありました。 タスクごとに別々のViewModelを作るべきなのか? それとも、テーブル全体に対して単一のViewModelを作るべきなのか? それとも、両方のViewModelが必要だったらどうするのか? どちらを誰が作るのか? こうした疑問をきっかけに、似たアーキテクチャでコンポーネントをどう調整するかを理解できるようになりました。
その後、PDF Expertの開発に携わっていたとき、チームでMVVMの導入を試すことになりました。 私はそのアーキテクチャを組み立て、その機能開発を進める中でチームを支える役割も担うことができました。 それは、あの小さくて雑然としたToDoアプリをまず自分ひとりで作っていなければ、得られなかった種類の経験です。
サイドプロジェクトに関する私のおすすめ
- インスピレーションとアイデアを見つけること。 たいていはまずアイデアがあり、そのあとでそれを具体的な学習目標に結びつけます。 主な目的は経験を積むことなので、アイデアが独自である必要も、とりわけ実用的である必要もありません。 たとえば、習慣トラッカーアプリを作ろうと決めるかもしれません。 そこから、アーキテクチャに集中することもできるし、このアイデアを使ってアニメーション付きの印象的なUIを設計することもできます。 あるいは、このアプリのためにサーバーを作る必要があるかもしれません? それは新しいバックエンド技術を試す絶好の機会になるでしょう。
- “done”を定義しましょう。 すべてのプロジェクトを本番投入できるレベルまで仕上げようとすると、それぞれに多くの時間を割く必要があります。 だから私は、各プロジェクトで達成したいマイルストーンを定義する必要があると考えています。
- 完璧は善の敵です。 “完璧な”解決策を探すことにとらわれすぎると、やる気を完全に失ってしまうかもしれません。
- 不要な作業を最小限にすること。 アーキテクチャを学ぶためのアプリで、正確なカラーパレットは本当に重要でしょうか? あるいは、ロギングシステムは? 最も価値があったのは、単一の学習目標に集中したプロジェクトでした。 優先度の低い細部に費やす時間を減らせば、そのぶん本当に重要なことにより多くを注げます。
ソフトウェアの作り方を変えた10のテーマ
ここでは、私が自分で掘り下げ、キャリアに影響を与えた10の分野を紹介します。

UIアプリケーションアーキテクチャ
UI中心のプロジェクトに携わったことのあるエンジニアなら、定番のコード構成パターンには馴染みがあるはずです。 MVC、MVP、MVVMを聞いたことがない人などいるでしょうか? 私の経験では、シンプルな理論知識だけでも新しいプロジェクトを始める自信にはなりますが、実践経験がないと、少し複雑になっただけで崩れてしまうことがよくあります。
私はかつてMVVMの仕組みを完全に理解していると思っていましたが、実際に試してみた経験はありませんでした。 そのことに気づいたのは、小さなMVVMアプリケーションを開発してみたときです。 クラスの寄せ集めを一貫した構造にまとめ、画面遷移や組み立てを行うには、coordinatorやrouterが必要だということが明らかになりました。 その経験から、私は重要な教訓を学びました。どんな場面にも当てはまる万能なアーキテクチャはないのです。 あるプロジェクトでうまく機能するアーキテクチャが、別の場所では不向きなこともあります。
デザインパターン
開発者面接を受けたことがある人なら、デザインパターンに関する質問に出会ったことがあるはずです。 多くのエンジニアは、理論上は特定のパターンを理解していても、実践ではうまく適用できないように見えます。 Tそのギャップを埋める最も簡単な方法は、特定のパターンの実装に焦点を当てた小さなプロジェクトを作ることです。
原著では、よくテキストエディタが例として使われています。 私の経験では、さまざまなドキュメントエディタには多くのデザインパターンを使う必要があります。 それはテキストエディタかもしれないし、画像エディタ、あるいは図を作成するプログラムかもしれません。
テスト
コードテストは、安定したコードベースの礎です。 そして、その考え方は単純に見えても – “とにかくテストを書け!” – 実際に役立つテストを書くのは、たいてい決して簡単ではありません。
最大の課題は、テストの保守にもチームのリソースが必要になることです。 コードをリファクタリングするたびにテストを書き直さなければならないなら、そのテスト全体の価値は疑わしくなります。 この概念はTest Fragilityとして知られていますが、私の経験では、あるべきほどには広く知られていません。 テストの理論については、たとえばこの本で学べます。
テストを強く意識することは、コード品質にも影響します。 一般に、テストを前提に書かれたコードは、よりモジュール化され、よりクリーンでシンプルなAPIを持つようになります。 実際にテストを試してみるのは簡単です – 既存のプロジェクトにテストを組み込むか、テストを書くことに重点を置いた新しいプロジェクトを始めればいいのです。
アルゴリズムとデータ構造
現代のソフトウェア開発では、アルゴリズムの知識は厳密な必須条件ではありません。 日々の業務では必要ないかもしれないのに、多くの企業はいまだに面接でアルゴリズムの課題を出しています。 それでも私は、アルゴリズムを学ぶことに時間を投資する価値はあると考えています。楽しくて面白いからです。 しかも今では、LeetCodeのようなプラットフォームを通じて、こうしたテーマをインタラクティブに学べます。
ACM ICPCのようなアルゴリズム競技プログラミングの大会に参加する機会があれば、ぜひ挑戦してみることを強くおすすめします。 たとえこの知識が最初は直接役に立たないように見えても、コード最適化の技法はどんなプロジェクトにも応用できますし、チーム制の競技会に参加した経験は、きっと懐かしく思い出せるものになるはずです。
マルチスレッド
マルチスレッドはとても魅力的なテーマです。 基本概念すら理解しないまま、何年もコードを書き続けることもできます。 メインスレッドをブロックするとアプリがフリーズすることは、どの開発者も知っています。 しかし、何か問題が起きたとき、マルチスレッドコードを本当に理解し、出来事のタイムライン全体を頭の中で描ける開発者だけが、あの捉えどころのない幽霊のようなバグを診断できます。
私の考えでは、同期プリミティブやスレッド、そしてこうした概念を軽視したときの結果を理解していることは、ミドルレベルの開発者とSeniorの開発者を分ける重要な要素のひとつです。 基本概念を理解するには、無料の書籍The Little Book of Semaphoresをおすすめします。
実践経験を積むには、特にバックグラウンド処理自体が複数スレッドを使う場合、重いバックグラウンド処理を行い、その結果をUIと同期するプログラムを書いてみるとよいでしょう。 物理プロセスのシミュレーションは、この種のプロジェクトの良い出発点になります。
グラフィックスプログラミング
グラフィックスプロセッサは、ほとんどの開発者が直接触れる必要のあることがめったにない、コンピュータの数少ない部分のひとつです。 大半のアプリケーションでは、UIレンダリングはCPU上で行われるか、実際のGPUデバイスから抽象化されているため、意識する必要すらありません。 しかし、画面上の要素数が十分に増え、高レベルの抽象化では必要なフレームレートに追いつけなくなると、より深く掘り下げる必要があります。 GPUが解決するよう設計されている問題を理解し、何をレンダリングすべきかをGPUに“説明”できるようになれば、似たような状況で素早く解決策を見つける助けになります。
グラフィックスプログラミングを学ぶ古典的なプロジェクトは、ゲームエンジンを作ることです。 私と同じようにコンピュータゲームが好きなら、それらがどうプログラムされているのか気になったことがあるはずです。 Metal、DirectX、OpenGL、Vulkanを学ぶためのリソースはオンライン上にたくさんあります。 ただ、自分のプロジェクトが次のUnreal Engineになるとは期待しないでください。 ですが、自作エンジン上で動く小さなゲームを作れるところまでたどり着ければ、魅力的な課題に出会い、価値ある知識を得られることは間違いありません。
組み込みプログラミング
身の回りのごく小さな電子機器でさえ独自のプログラムとプロセッサで動いていると初めて知ったとき、私はすぐに魅了され、自分でも似たものを作ってみたいと思いました。 ただし、マイクロプロセッサ向けの開発には多くの制約があります。 こうしたシステムのメモリは通常128キロバイト未満で、動的メモリ割り当てはたいてい使えません。
組み込みコードの作成とデバッグには、多くの難しさがあります。 しかしそのぶん、自分のコードが現実世界で動き出すのを目にできます。 単純にLEDを点滅させるだけでも、私にとっては大きなブレークスルーに感じられました。 マイクロコントローラの仕組みを理解することは、現代のCPUやオペレーティングシステムの仕組みを理解するための重要な第一歩です。 組み込みデバイスを扱う際には、プラットフォーム固有のアセンブリ言語(通常はARM)に踏み込む必要が出てくることさえあります。
今では、組み込み開発を始めるのはこれまでになく簡単です。 STM32系のような手頃な価格のマイクロコントローラは出発点として最適で、USB接続のビルトインプログラマを備えたすぐ使えるボードも多くあります。 ダイナミックな室内照明から、自作のスマートホームIoTハブまで、可能性は無限です。
逆アセンブラ
ときには、自分のコードをもう一段深いレベルで見られることが、非常に大きな価値を持ちます。 たとえばAppleプラットフォーム向けの開発では、Apple製の、ほぼクローズドソースなライブラリを扱うことがよくあります。 何かが期待どおりに動かないときは、通常、Feedback Assistant経由でチケットを送って、返答を待つ必要があります(ときには何年も!)。 しかし逆アセンブラを使えば、内部をのぞいて、そのクローズドソースコードが実際にどう動いているのかを理解できることがよくあります。
自分のプログラムのアセンブリコードを理解することも、特に最適化の文脈では役立ちます。 コンパイル後のコードを調べて初めて、自分のコードが本当に何をしているのかを把握できます。 個人的には、この目的のためにmacOSでHopper Disassemblerを使っています。
コンパイラ
プログラミングの世界には独自の“秘密クラブ”があります。最も多くのエンジニアに影響を与えるプロダクトを作っている人たちのことを考えると、行き着くのは、私たちのお気に入りのプログラミング言語を支えるコンパイラを作っている人たちです。 自分でコンパイラの勉強に時間をかけるまでは、こうしたプログラムは純粋な魔法のように感じられました。 しかし、基礎を学んだとしても、その魔法の霧は、プログラミング言語そのものを丸ごと作り上げた人たちの卓越さを、なお完全には理解させてくれません。
ありがたいことに、このテーマに関するリソースや書籍は豊富にあります。 私のお気に入りは、Engineering a Compilerと、もちろん古典的名著のDragon Bookです。 自分自身のプログラミング言語の開発に踏み込みたいなら、LLVMのKaleidoscopeチュートリアルから始めることができます。 “実務の”ソフトウェア開発では、コンパイラエンジニアでない限り、この知識によって、言語の振る舞いや不可解なエラーへの理解をはるかに深めることができます。 さらに、ほとんどのコンパイラはオープンソースなので、大規模で影響力の大きいプロジェクトに貢献することもできます。 たとえば、Swiftリポジトリへの貢献は、どの開発者のポートフォリオにも大きな価値を加えます。
オペレーティングシステムの基礎
コンパイラ以上に複雑なプロジェクトがあるとすれば、オペレーティングシステムが真っ先に思い浮かびます。 私たち開発者は、ほとんどの時間をコンピュータ上での作業に費やしているため、オペレーティングシステムも、自分たちが書くプログラムと同じように、単なる別のプログラムにすぎないということを驚くほど忘れがちです。 ハードウェアの上に築かれた巨大な抽象化レイヤーによって、各ユーザー空間プログラムがそれぞれ専用のプロセッサと専用メモリを持って動いているかのような錯覚が生まれます。 こうした抽象化は非常に精巧で、一度書いてコンパイルしたコードが、非常に多様なハードウェア構成でも確実に動作します。
オペレーティングシステムがどう動くのかを理解する出発点としては、Operating Systems: Three Easy Piecesという本がおすすめです。 また、iOSやmacOSの内部構造に特に興味があるなら、無料のリソースMacOS X and iOS Internalsをおすすめします。 OSがどう機能するのかへの理解は、ハードウェアと私たちが書くコードの間にある最後のギャップを埋めてくれます。 開発者にとってこれは、自分のプログラムが実行されるときに何が起こっているのかを、ほぼ完全に制御し理解できることを意味します。
まとめ
振り返ってみると、私は厳密な計画に従っていたわけではありません。 ただ、学び続け、作り続け、自分が興味を持ったものを追いかけ続けていただけです。 その好奇心が、やがてキャリアになりました。
今の状態に満足しつつも次に何をすべきか迷っているなら、幅を広げてみてください。 何か新しいことを探求してみましょう。 サイドプロジェクトと学習に投じた時間は複利のように積み上がり、Junior、Middle、Senior、Principalの間にある差も—思っているより速く—縮まり始めます。
学ぶべきことはいつだってまだあります。 でも、プロジェクトをひとつ重ねるたびに、失敗をひとつ経験するたびに、そして新しい概念をひとつ学ぶたびに、あなたは前に進んでいます。 作り続けてください。
— Andrii Zinoviev, Principal Product Engineer
Engineeringチームの一員となって、何百万人ものユーザーに影響を与えたいですか? ぜひ募集職種をご覧ください!
The Readdle Team