ゆめみの次期未経験者向け iOS コードチェック特別課題を徹底解説

# 2023 年 5 月 1 日更新

長らくお待たせしましたが、本日から、この課題が正式リリースされました！そのため、本記事の内容も、公開に合わせて修正を入れ、ChatGPT に文言のブラッシュアップをしてもらいました。差分が気になる方は、ぜひ[編集履歴](https://qiita.com/lovee/items/674280065e0241528014/revisions)からご確認ください。

---

# モチベーション

弊社の iOS エンジニアのコードチェック課題が[変更され](https://speakerdeck.com/lovee/a-brief-description-about-the-new-code-check-for-ios-engineer-in-yumemi-inc)てから早くも 2 年以上が経ちました。この間、多くの方が応募してくださり、弊社の iOS エンジニア採用基準も年々向上しています。

しかしながら、新たな悩みが浮上してきました。現行のコードチェック課題は中途採用の即戦力を測るには効果を発揮していますが、新卒や未経験者に対しては厳しすぎるのではないかという問題があります。具体的には、チームでの開発経験の有無によって結果が大きく変わり、「ポテンシャル」を測ることが難しい状況です。また、初期のコードチェック課題の時と比べても、既存の枠組みに囚われて力作がなかなか現れない寂しい現実です。

そこで、やはり新卒の方には「ポテンシャル」が重要だと考え、新しい課題を考案しました。既存の課題は「即戦力」を測る目的で効果的ですので、新卒や未経験者はポテンシャルを評価できるには特別課題作成して、応募者に課題の選択肢を与えるようにしました。

# ゴール

「ポテンシャル」を測るためには、やはり初期の課題と同じ、テーマを与えてアプリをゼロから作成してもらうのが最適だと思いました。同じテーマだからこそ評価としての比較が可能ですし、何より当時は実際に学生さんからたくさんの華やかな成果物をいただいた実績があります。問題は、何のテーマを選ぶかです。弊社は性質上、Stand-Alone なアプリの開発は基本あり得なく、何かしらの Web API 通信が発生する非同期処理が必ずあります。実は、弊社の初期の課題ではユーザが入力した文字列にふりがなを振ることがテーマでした。その際、サードパーティの Web API に依存していました。しかし、他社への依存も良くないですし、何より通信が課題の一部であるにも関わらず、OS の標準機能で読み仮名を振ることができるため通信を行わない応募者もいました。そこで、通信しなければ課題が解けないものを選ぶことにしました。長考の末、自社で占いの API を作ってしまえばいいとアイデアが浮かびました。

ところが、占いのロジック自体は容易ですが、大量のパターンを作成するのは手間がかかります。最初は[でたらめ文章ジェネレーター](https://garily.github.io/BullshitGenerator-Japanese/)を利用できるかと考えました[^bullshit-generator]が、実際に試してみると出鱈目な文章は読むに堪えませんでした。そこで、パターン数を絞り込む方向で考え、最終的に **「あなたと相性のいい都道府県を占ってあげる！」** というテーマを決定しました。都道府県は 47 パターンしかなく、適切な文章も容易に集められるためです。

[^bullshit-generator]: 本課題を考案した当時はまだ ChatGPT サービスが公開されていませんでした。今ならとりあえず ChatGPT にとりあえず恋愛運とか金銭運とか色んなものを 100 パターンずつ作って貰えばいいですが。

# 課題内容

すでに公開済みですので、ぜひ[こちら](https://yumemi-ios-junior-engineer-codecheck.app.swift.cloud)をご覧ください。

ゴールのセクションでも説明しましたとおり、今回の課題も実際の API と通信しながらレスポンスを表示するアプリになります。ただし通常課題と違い、今回の課題は「明確なチケット」はありません。何よりポテンシャルを図りたいですので、以前の[採点記事](https://qiita.com/lovee/items/d76c68341ec3e7beb611)に書かれた「設計」や「保守性」の部分は、もちろん引き続き指摘事項には入りますが、採点への影響は比較的に薄いと考えてもらって大丈夫です。その代わり、アプリ自体の完成度のほうが大きく比重を占めます。

では完成度をどのように測るかというと、そこがまた非常に難しい問題で、弊社内でもまだ意見がまとまっておりません。そのため、最初の数ヶ月は筆者を含むコードチェックレビューチームメンバーによるモブプロ的な形で採点する予定です。提出物の数をある程度こなせたら、もしかするとガイドライン的なものも公開できるかもしれませんが、今のところはまだ未定です。ただ一つ個人的な指標を言うと、「Hot, Simple and Deep」というデザイン原則があり、アップル製品（少なくともジョブズ時代の製品）はまさにその体現と言っても過言ではないと思いまして、これができたアプリは、個人的には非常に完成度の高いアプリだと思います（まあただのデタラメ占い API でどんな Deep なアプリが作れるかはさておき）。

## Hot, Simple and Deep

ChatGPT によると、Hot Simple and Deep は概ねこんな意味です：

> 「ホット (Hot)、シンプル (Simple)、ディープ (Deep)」というコンセプトは、年月を経て様々なプロダクトデザイナーや開発者によって言及されてきた非公式のデザイン原則です。特定の個人や正式な理論に明示的に帰属されていませんが、他の確立されたデザイン原則や哲学と類似点があります。
>
> 例えば、「ホット」の概念は、デザインの魅力と美的魅力に密接に関連しており、これはアメリカの心理学者であり著者であるドナルド・A・ノーマンの業績に遡ることができます。彼の著書「エモーショナルデザイン: 私たちが日常のものを愛する（または嫌う）理由」では、ユーザーと製品の間に肯定的な感情的つながりを築くために美学が重要であることを強調しています。
>
> 原則の「シンプル」な側面は、KISS（Keep It Simple, Stupid）原則とシンプルさの概念を連想させます。KISS原則は、1960年代に米海軍によって提唱されたとされ、設計者に作業をシンプルに保つよう奨励しています。これにより、対象のユーザーによって簡単に理解され、使用されることが保証されます。さらに、ミニマリストデザインやユーザーエクスペリエンスデザインの原則も、シンプルさと使いやすさを提唱しています。
>
> 最後に、「ディープ」の理論は、製品が見た目にも魅力的で使いやすく、複雑な実世界の問題に対処できることを目指しています。このアイデアは、「機能デザイン」という概念に関連付けられることがあり、ユーザーのニーズを満たすための製品の有用性と効果性を優先しています。
>
> 要約すると、「ホット、シンプル、ディープ」は、特定の起源を持つ正式なデザイン理論ではありませんが、さまざまなデザイン哲学や分野からのアイデアと原則の組み合わせを反映しています。この概念は、視覚的に魅力的で使いやすく、機能的に効果的な製品を作成することを目指すデザイナーにとって有益なガイドラインとして機能します。


# 舞台裏

実は[このバックエンドをオープンソースにしました](https://github.com/yumemi-inc/ios-junior-engineer-codecheck-backend)ので、興味ある方はぜひチェックしてみてください！

そうです、すでに API の Base URL で察した方もいるかもしれませんが、今回の API は Swift で実装されたものです！ある意味私が業務で Server-Side Swift をどうしても書きたいから、と言うのも今回の課題を考えたモチベーションの一つです。そしてプラットフォームはバックエンド全く未経験でも簡単に書き始められる Swift Cloud を選びました。Swift Cloud については[以前の記事](https://qiita.com/lovee/items/2c4c4624d0f4a399bacd)で色々説明しましたので今回は割愛します。一つだけ補足しますと、この API では一応個人情報もどきな何か[^privacy-ish-info]も送信するので、URL に直接クエリを入れるのではなく、Request Body で送信することにしました。ところが前回の記事は GET メソッドで Request Body を取り出す実装を紹介しましたが、実際にこのように実装すると、[iOS はそもそも `GET` メソッドで `httpBody` を付け加えられない](https://qiita.com/uhooi/items/e82c8d294a8465a3e6f3)と怒られてエラーが返されます。RFC では [GET メソッドの Request Body はセマンティックが定義されておらず](https://www.rfc-editor.org/rfc/rfc7231#section-4.3.1)、そのため[処理する際は無視すべき](https://www.rfc-editor.org/rfc/rfc2616#section-4.3)と定めているからです。新しい [QUERY メソッド](https://horovits.medium.com/http-s-new-method-for-data-apis-http-query-1ff71e6f73f3)も議論されていますが、現在まだ正式リリースされていないため、多少違和感あるのは否めないが今回は POST メソッドで実装することにしました。

[^privacy-ish-info]: もちろんこの課題に関して、弊社は個人情報の収集は一切行っておりません。課題として入力を受け付けているだけで、入力されたデータの永続化等は一切実施しておりません。そもそも、本物の個人情報を求めるものではありません。

現状のリクエストには名前、血液型、生年月日及び本日の日付を必要とし、それは自由なテキスト、値限定のテキスト、そして整数値が含まれた特定データ構造があります。またレスポンスには都道府県の名前以外に、県庁所在地、簡単な概要、海岸線の有無、県民の日（もしあれば）の日付、そして県のシルエットの画像への URL が返されます。それはテキストの長文、短文及び URL 形式の他に、真偽値や整数値が含まれた特定データ構造、さらにはそもそも項目がないかもしれない Optional もあります。これらのさまざまな形式のデータフォーマットは処理のみならず、どのように入力／出力インターフェイスを構築するかも、応募者の皆さんのスキルにかかっています。

ただし現状はスケジュールの都合で、無効なデータをもらった時などのエラーの出しわけまだできておらず、全て 500 エラーになってしまいます。そしてユーザからもらう情報やユーザへ返す情報も将来増減する可能性があります。そのため API の安定な運用を考えてきちんとバージョン分けを考える必要があります。そこで最初はパスでバージョン分けをしよう、つまり `"/v1/my_fortune"` のように分けようと思いました。しかし、これだととりあえずバージョンを指定せず最新を取りたい場合、バックエンド側では同じ処理をルーティング分けのために 2 回書かないといけなくて、あまりいい解決法が思い浮かびませんでした[^versioned-routing]。そこで会社の同僚と相談したら、パスでバージョン指定ではなく、ヘッダーでバージョン指定すればいいのではとアドバイスをもらいました。それでできたのが上記 `"API-Version"` のヘッダー指定です。

[^versioned-routing]: 一応 `func post(_ path: String, optionallyAfterVersion versionPath: String, handling: Handling)` のようなメソッドを作ってその中でバージョン分けを書く方法も考えてはみましたが、`optionallyAfterVersion` の部分のラベルはやはりどうしても長くなってしまって読みにくくて微妙でした）

以上、次期未経験者向けの iOS コードチェック課題のチラ見せでした。ご意見やアドバイスがあればぜひ聞かせていただけると嬉しいです。