🐥

ゆめみ社のFlutterエンジニア採用課題に取り組んでみた

2022/07/26に公開約7,800字

背景

先月、偶々ゆめみ社のFlutterエンジニア採用時のチェック課題がGitHubに公開されているのを知り、内容をざっと見てみると多言語対応やダークモード対応など網羅性が高く、単純に良い学習になりそうと思って取り組んでみました。
サービスの要件次第では海外配信想定がなかったり、リリース時期に重きを置いて多言語対応・ダークモード対応を省くこともあり、この機会に一通り触ってみようと思った次第です。
特に評価ポイントの以下の部分は、一般的に言及されるエンジニアとしての能力はもちろん、アクセシビリティや表現方法、品質維持など、ユーザーと近い領域を担うアプリ開発者において大事なポイントだと思っています。

- 簡潔性・可読性・安全性・保守性の高いコード
- Dart の言語機能を適切に使いこなせているか
  - テスト
  - テストが導入しやすい構成
  - Unit・UI テストがある
- UI/UX
  - エラー発生時の処理
  - 画面回転・様々な画面サイズ対応
  - Theme の適切な利用・ダークモードの対応
  - 多言語対応
  - アニメーションなど
- CI/CD
  - ビルド
  - テスト
  - リント
  - フォーマット
  - 仮のデプロイ環境

https://github.com/yumemi-inc/flutter-engineer-codecheck

余談ですが、ゆめみ社は ゆめみオープン・ハンドブック のような組織図や福利厚生なども全てオープンに公開していて、日々新しい取り組みを率先して行っていて良いですね👏

本記事の内容

こちらは、以前話題にもなっていたフロントエンドのコーディング試験に対する記事で、Reactに明るくない私でも要所が網羅されていてキャッチアップできたので、参考にしました。

https://bufferings.hatenablog.com/entry/2022/06/11/232314

とはいえ、一応公開されている課題内容ではありますが、全てを記載してしまってはせっかく入念に作られたであろう課題の意味が薄れてしまう気がするので、個人の独断と偏見で項目を絞って記載します。

また、「普段使っていないけど気になっていたパッケージ」なども積極的に採用しており、それが必ずしも最良な選択とは限らない点をご了承下さい。

以下、冒頭の評価ポイントからアクセシビリティを中心に掻い摘んで記載します。

成果物

こちらが、READMEに記載されていた動作要件です。

動作要件
- 何かしらのキーワードを入力できる
- 入力したキーワードで GitHub のリポジトリを検索できる
- GitHub のリポジトリを検索する際、GitHub API(search/repositories)を利用する
- 検索結果は一覧で概要(リポジトリ名)を表示する
- 検索結果のアイテムをタップしたら、該当リポジトリの詳細(リポジトリ名、オーナーアイコン、プロジェクト言語、Star 数、Watcher 数、Fork 数、Issue 数)を表示する
Search Search - dark
Not Found Detail - ja Detail - en

簡潔性・可読性・安全性・保守性の高いコードか

関心ベースの構成

これらの基準を満たしているかどうかは分からないですが、今回はディレクトリ構成を関心ベースで作ってみました。この手の話題は、以下にある記事やツイートなどでも日々議論されていますが、個人的なこれまでのプロジェクトでは機能単位で区切っていたので心機一転試してみました。
結論、今のところ結構しっくり来ていて「この〇〇に関するファイルはどこに置こう?」といった思考リソースを費やすことが以前より少なくなった気がします(まだプロジェクト規模が少ないからかもしれないですが)。
最初、共通利用されるようなfeaturesに入らないものはどうしよう、とは思ったのですがcommonを箱のように置いてからは取り回ししやすく、良い塩梅でバランス取れている感触がありました。一長一短だとは思うので既存プロジェクトを差し替えるまではしないですが、今後の新規プロジェクトでは基本的に関心ベースで作っていこうと思っています。

.
├── common
│   ├── extensions
│   ├── providers
│   └── widgets
├── features
│   ├── base
│   ├── repo
│   └── settings
├── gen
├── l10n
├── services
│   ├── api
│   └── paging
└── theme
    ├── extensions
    └── theme_mode

https://codewithandrea.com/articles/flutter-project-structure/

単方向データフロー

前述のディレクトリ構成の通りですが、特にクリーンアーキテクチャやDDDのような形式張ったアーキテクトというものは採用していません(個人的には結構この手の理論がイマイチ理解できておらず、その恩恵がまだ腑に落ちていないだけかもしれませんのでその点はご容赦下さい🙏)。
とは言え、データの流れを単方向にする点だけは意識しており、以前ツイートされていた monoさんの手書きアーキテクト を強く意識して書いています。今回だとGitHubからAPIでデータをフェッチする形となるので、FutureProviderでWidget層に流し込むイメージです。
一方、ユーザーによる操作(今回だと検索フォームの入力)では、UIからデータソース層へ流れる形になります(図のBのライン)。

UI/UX(アクセシビリティ)

Themeの適切な利用・ダークモードの対応

Flutter 3からTheme Extensionが追加 され、ThemeDataを自由に拡張することができるようになり、以前よりダークモードへの対応がしやすくなりました。

このTheme Extension, 非常に便利なのですが定義時に都度leap,copyWithを追記する必要があり中々に面倒という課題がありました(Github Copilotが賢いので許容という声もありますが、毎月$10のサブスクは少し悩んでしまいますよね)。

今回は、以上の課題感に対するソリューションとして公開されているtheme_tailorというパッケージを使ってみました。

https://pub.dev/packages/theme_tailor

使い方は至ってシンプルで、@tailorというアノテーションをつけてbuild_runnerを走らせるだけです。あとはThemeExtension継承クラスを自動で生成してくれます。


class _$AppColors {
  static List<Color> background = [Colors.white, Colors.black];
}

一点、自動生成されるBuildContextの拡張だけ気になりましたが、ひとまず上辺だけ触ってみた感想としては悪くなかったです。ただ確かに、ThemeExtensionを弄る機会は少ない(今回も一度生成して残り少し調整した程度)なので、わざわざパッケージ依存増やして自動生成に頼るかは悩みどころですね🤔

多言語対応

公式の Internationalizing Flutter apps | Flutter の通りに行いました。他のアプローチとしてはpub.devでlocalization用のパッケージがいくつかあり候補になるそうですが、今回は特に気になることはなかったので至ってシンプルに公式通りで済みました。
その他、特に言及することはないですがVS Codeを使っている方はぜひこちらをご利用下さい。便利すぎです。

https://twitter.com/_mono/status/1543802124534153217?s=20&t=PKPO0EA1crTEiWlmm-W6zQ

異なる解像度やアクセシビリティを動的に切り替えて確認

前述したアクセシビリティ周りの確認には device_preview を使うと捗ります。

https://pub.dev/packages/device_preview

enabledプロパティを持っているので、公式ドキュメント通り!kReleaseModeとすると、リリースモード以外で有効になります。ただ使ってみるとわかりますが、スマートフォンサイズでは設定値を変更するのが煩わしいので、個人的にはmacOSのみオンにするのが気に入っていて以下の指定にしてます。

DevicePreview(
  // DevicePreviewはスマートフォンサイズでは設定がしづらいので、macOSでのビルドのみ使うように指定。
  // iOS/Androidビルドでは操作感を確かめる用途もあるのでデバイスプレビューは使わない。
  enabled: !kIsWeb && Platform.isMacOS && kDebugMode,
  builder: (context) => const App(),
),

1点注意として、macOSビルド時にはデフォルトでクライアントネットワークの設定がなされていないため、DebugProfile.entitlementsに以下を追加する必要があります。

DebugProfile.entitlements
  <dict>
+   <key>com.apple.security.network.client</key>
+   <true/>
    ...
  </dict>

操作感はこちらのツイートのとおりです。

https://twitter.com/h_tsuruo/status/1551105787363495936?s=20&t=fewGIAK8TLW6NUwuCh0j6A

以上を踏まえて、device_preview を駆使しながら主に下記の観点を中心に確認します。

- Device(Model):
  - 解像度の違いでレイアウトが崩れていないか
  - 視認性が落ちていないか
  - OSの仕様で壊れていないか
- Locale:
  - 対応の漏れやタイポがないか
  - 改行位置がおかしくないか
  - 表現に違和感が無いか
- Theme:
  - カラーが潰れていないか
  - 視認性が落ちていないか
- Orientaion:
  - 特にLandscape状態時にoverflowしていないか
  - SafeAreaを干渉していないか
- Text scaling factor:
  - 拡大/縮小時にレイアウトが崩れていないか
  - 見切れてしまう箇所が無いか

Text scaling factorについては、ユーザービリティ観点では可変にするべきだと思いますが、要件次第では固定にせざるを得ない場面もあると思います。そういった場合でもこちらの記事の通り、ある程度の設定を許容しつつmin()で制限してしまうのが丁度よい塩梅だなと最近思っています。

https://zenn.dev/ktakayama/articles/1b741f765b4f24#特定の範囲内なら文字サイズの変更も許可したい

device_previewも便利ではありますが単に普通のアプリケーションの機能の一つなので、iOSシミュレータのような高機能(キャッシュの削除やスクリーンムービーの作成等)は無く、好みや場面に応じて開発しやすい方を選ぶと良いと思います。iOSシミュレーターはToggle Appearanceをショートカットで切り替えられる一方、Locationは再起動がかかってしまうので一長一短という感じですかね。
また、最終的には実機での確認がメインとなるはずなので、あくまでその前段の「開発サイクルを早めるための一つのアプローチ」程度に思っておくと良いと思います。

まとめと余談

今回はゆめみ社のFlutterエンジニア採用時のチェック課題を試してみました。評価ポイントで挙げられていた項目を全て満たせたわけではないですが、改めて手を動かしてみると自分が苦手な部分や学習が必要な領域がより明確になって良い機会でした。個人的にはあまりテストを書く癖を付けられておらず弱い部分だと気づき、その辺り中心に改めて学習を進める必要があると認識しました。
昨今、アプリエンジニアやフロントエンドエンジニアもUIやアクセシビリティに対する深い知識や感性が求められ、カバー範囲が益々広がってきていると感じます。これに加えて、各プラットフォームの理解に始まり、直近だとiOS 16, Android 13の新仕様や変更の追従、アプリストアの諸々など担う領域はたくさんありますね。個人開発でこれらを全て1人でこなしている人を見ると、いつもすごいなと感心しています。
昔に議論(?)があったこちらの記事の主張についても、flutter runして手元で動くものを作る程度を指しているのであれば納得できるものの、世の中のプロダクションレベルな開発をしているアプリエンジニアはそうとも限らないので、どこまでを見据えるかで感覚は変わってくると思いました。あくまで個人的には、本記事で取り扱ったような部分をケアして作り込もうとすると、「難しくない」という感覚は持てませんでした(感じ方は人それぞれで良いと思います)。
というより、アプリ開発に限らずフロントエンドもバックエンドもやはりソフトウェア開発は謙遜無くどれも大変ですよね(会社の同僚にバックエンドコアのエンジニアがいますがキャッチアップや成長が早すぎて圧倒されている)。業界のトレンドにアンテナは張りつつも、自分が得意な領域を見定めてしっかりスキルを磨いていこうと思いました。

最後に、前述の余談に関連してエンジニアのキャリア形成を考える上で参考になるスレッドだったので引用しておきます。

https://twitter.com/_mono/status/1548302419263889408?s=20&t=ifMK6cJT8LfHs9mUciwKSg

参考

Discussion

ログインするとコメントできます