10人以下のエンジニアチームでコードの品質を守る為に試した事

モバイルゲームクライアント開発のテクニカルディレクターなどを最近やっている須藤 崇浩 | 面白法人カヤックと言います。

こちらは 面白法人グループ Advent Calendar 2022 の24日目の記事です。

明日はクリスマスですね。クリスマス翌日に売れ残って割引されたスイーツを買って美味しい思いをするのが好きです 🎂

本記事では表題に関して、昨年から参加しているモバイルゲーム開発案件で立ち上げから試行錯誤してる事について書いていきます。

「何故か開発後半でコードが複雑になってメンテナンスしづらくなる」「人間に書かせるべきでは無いのではないか?」..などコードの品質について悩んだ経験のある方に多少なりとも参考になる内容になれば幸いです。

目次

コードレビュー

https://2.bp.blogspot.com/-ymQR_t5od9o/W-Jm_B10YbI/AAAAAAABQB0/GeqYiSNhtRchjCQ91IBEPj0gWuEcA7tgACLcBGAs/s250/review_woman_star5.png

大雑把に以下の理由でレビュワー2人体制で進めてます。

  • 片方が調子悪い場合でももう片方でカバー出来そうだから
  • レビュー箇所のメンテナンス出来る人を増やしたいから(でも全員で見るのは効率が悪いので絞っている)
  • レビューの品質追求以外に、メンバーの教育目的にも使いたいから

また、後述する様に開発時期によってレビュワー選定の基準がありました。

開発初期

この時期には品質のブレを少なくした方が「チームとして良いとされるコード」がシステム全体に行き渡り、チーム全体でのイメージを固めるまでの速度が早いのでレビュワーを少数に限定してます。

そもそも初期は人数も少ない場合が殆どなので基本的に相互レビューする様な関係になるしか無いんですが。

「チームとして良いとされるコード」とは?

ちなみにこれについて少し脱線して解説します。

良いコードは一般的なイメージとしてもある程度固まっている印象がありますが、その上で一緒にコードを書いていくチームの上限にあたる実力に沿った形で議論→合意を繰り返して固めていくものだと思っています。

なので、「一般的に良いとされるコード」と「チームとして良いとされるコード」は一応分別して書いてます。

でも長いので、以降は「良いコード」に省略させていただきます。

開発後期

開発日数が積み重なりチームの練度が上がってきたらレビュワーの選定基準を変えてます。

状況に応じて以下の様な役割と目的を分類してレビュワーをアサインしています。

  • 新人(能力関係なくチームに入りたての方):良いコードについてコードレビューする事で理解を深めて欲しいから
  • 良いコード書ける人:レビューを通じてより良い設計や書き方を指摘してほしいから
  • 将来そこ周辺をメンテするかもしれない人:レビュイーに比べると自分で書いてないので理解度では劣るけど、レビューする事でふんわりレビューした機能への理解が深まるので将来そこ周辺の実装をお願いできるかもしれないから

新人のオンボーディング

https://4.bp.blogspot.com/-2nvNWQTBx_Q/UqmP9kvlyHI/AAAAAAAAbpE/i8sNkx5ixWo/s400/pool_oyako.png

開発している途中で人の入れ替わりがあったり、開発体制を拡大するためにエンジニアを増員する事があります。

基本的には新人の経験やスキルによりますが、2ヶ月くらいの間はOJTの対象として迎え入れています。

気をつけている点は以下です。

複雑度の低いシステムから徐々に難易度を上げていく

参考になる実装を提示しながら実装方法について解説してます。

  • 画面の作り方
    • 一部の要素のみの変更
    • 画面の新規作成
  • 新規種類のアセット追加作業
  • サーバーと通信する実装など...etc

実装前の設計を慣れてる人と一緒にやる

システム全体の理解度が他メンバーに比べて低い状態なので、コードレビュー時の議論や指摘を抑えるための対策で実装に入る前に以下を確認しています。

(コードレビューはレビュイーとレビュワーのシステム理解度や実力にギャップが大きい程マージまで時間がかかると思っているので)

  • 開始から実装完了までの段取り確認
  • どういったクラスを設計すればよいか、どの周辺システムを使えばよいか...etc

同じIDE使う

https://resources.jetbrains.com/storage/products/rider/img/meta/rider_logo_300x300.png

私のチームはUnityを使っている案件なのでみんなで同じRider: JetBrainsのクロスプラットフォーム.NET IDEを使うという方針があります。

理由としては以下になります。

  • IDEの機能についての共有がしやすい
  • Pluginも便利なのあったら共有できる
  • コーディングスタイルを制限させてコードレビューでの指摘を減らす

コーディングスタイルを制限させてコードレビューでの指摘を減らす

制限させる事によってインデントやスペースなどのスタイルが担当者によって左右されなくなるので、文章としてのコードが読みやすくなる恩恵があります。

私のチームではEditorConfigファイルを共有してそれを各自のIDEに導入しています。

設定にコーディングルール違反などの漏れパターンがあったら更新してチームメンバーに再共有されます。

EditorConfigは各テキストエディターに幅広くサポートされてるので、Rider以外を絶対に使いたい方が居ても一応許容できる体制にはしています(RiderはUnityに対するサポートが手厚いので強く推奨してますが)

エンジニアを短期間に複数人入れない+人数を増やしすぎない

https://2.bp.blogspot.com/-H-ZPcOcnZkU/XNE_Jk2ir0I/AAAAAAABSvA/OnrEKa0SnnQ6CMltT3inmGlm4nXrTVE4gCLcBGAs/s450/kids_oonawatobi.png

先程も触れましたが基本新人が慣れるまでの期間を2ヶ月くらいと見て、少なくともその間にまた新人をチームに入れないようにしています。

割れ窓理論というものがあり、システムの中で一部でも品質の低いとみなされるコードがあってそれが見れる状態にあると、たまたまそれを参考にしたりした人が他のシステムにもその品質を流用されてしまい低い品質が広がってしまう可能性があると思うので気をつけています。

最大人数

また、最大人数にも気をつけています。

開発する製品の規模や種類にもよりますが、一般的なモバイルゲーム開発においてクライアントエンジニアは10人以下になるのが理想だと肌感で思っています。

同じシステムを触る人間が10人を超えると人力では品質保証が難しく、静的解析やアーキテクチャの制限度合いを上げるなどの対策をしなければいけないと思っているので。

(何か自動化の余地があったり、期間で動くものを作らなければいけないスケジュールの場合....などの問題があることが多いと勝手に思ってます。)

大人数での開発について考える事自体は楽しいですが、可能ならやらずに済むのが楽だと思ってるし、製品規模やスケジュールに適した体制やアーキテクチャや品質目標を採用すべきだと思っています。

その他ここで触れてないことについて

テストコードを書く

過去に2案件程で試したのですが、コスパを考えると割にあわない経験をしたので個人的に諦めてます。(周りでもっと成功事例が増えれば再挑戦したいです)

理由としては以下がありました。

  • ゲームクライアントを構成する要素の多くは画面に表示される情報になるため、そこのテストをどうするかが難しい
    • 弊社だとせいぜい以下の様な仕組みを実行する程度に済ませています

techblog.kayac.com

  • ゲーム制作は試行錯誤のイテレーションが多く、その試行錯誤の多くにクライアント側の表示内容に関する制御処理が多く、更新頻度が高いから
  • コードのみで完結して、仕様変更の影響を受けにくいまとまった処理など(OSSのライブラリや、ゲームシステムの基盤など)に対しての品質保証には有効だとは思っています

おわりに

ここまでお読み頂きありがとうございました。

こういった事柄に関する知見はプロジェクトや環境によって異なる解決(≒正解)があるのと、つい外向けに出すと綺麗事を並べたり事実をボカしてしまうので難しいのですが、なるべくそのままの状況をお伝えしました。

もし宜しければ「私はそう思わない」「うちはこうしてる」...など感想をTwitterやブクマでシェア頂けると嬉しいです!!

Unityを使い始めた頃に困っていた事、悩んでいた事

こんにちは。カヤックアキバスタジオでエンジニアをやっている臼井です。

この記事は 面白法人グループ Advent Calendar 2022 の17日目の記事です。

今回はUnityを使い始めた頃に困っていた事、悩んでいた事についてお話しします。

はじめに

ここ最近、僕の周りでもプログラムを勉強するためにUnityを使い始める人が増えてきました。
その中で、色々な悩みを聞く機会が増えてきたので、自分が使い始めた頃どうだったかな?
というのを振り返ってみようと思います。
(昔の記憶でうる覚えのため、勘違いや間違いがあってもご了承ください。)

困っていた事、悩んでいた事

Unityバージョン

Unityを使うにしてもどのバージョンを使うのか、使い始めてからどのタイミングでバージョンアップするのか等々悩む事がありました。
この辺りはプロジェクト内で決めればいいのですが、知見がある人がいないと中々決まらないものですよね。
今みたいにLTSもなく、Unity起因のバグで地雷を踏む事も多かった印象がありバージョンを決めるのも苦労してた気がします。

Warning

ビルドエラーとは違いwarningが出ていても実行はできるため、スルーされがちなのですが意図しない挙動になっていてバグが発生する事もありました。
warningをちゃんと潰していたらこんな事にはならなかったのに・・・。
という事もあり、最近は定期的にwarningがないか確認しながら開発しています。

public変数

Unityだからという訳ではないですが、public変数を使ってる事でどこからでも値が変更できてしまい、意図しない箇所から設定されバグが発生することも多々ありました。 public変数お手軽なので使いたくなりますよね。
Unityを触り始めた方でバグに遭遇し解決できずに辞めてしまう人も多い印象があるので、public変数を使わない形から始めるのもいいかもしれないなと思いました。

missing

使用しているファイルを気づかずに削除してしまい、missingが発生して動作しなくなる事も多々ありました。
当時は、このファイル削除してもいいですか?と聞きながら対応してた気がします。
今はmissingの箇所を検索したりファイルが使われてるか検索する機能を作って対処しています。
それでも発生する時は発生しますが。

Find、GetChildを使用したインスタンス取得

オブジェクト名、何番目というのを指定してインスタンスを取得する処理を書いていて、オブジェクト名や構造が変わる事でインスタンスが取得できずにエラーが発生する事が多々ありました。

  • ルール決めをしっかりおこなえていない
  • prefabを使う人と作る人が別々だった
  • etc

と、理由は色々あると思いますが、構造が変わる事で破綻するような処理をなるべく書かないというのが一番かなと思いました。

文字コードの違いによる文字化け

当時はwindows、mac半々くらいで開発してたりしていたので、文字コードの違いによる文字化けで困る事が多く、その対策としてAssetPostprocessUTF8Encode.csを利用させていただく事が多かったです。

デリミタ(区切り文字)

文字の区切り文字もwindows、mac環境で異なるため問題が起こる事がありました。
対処法としては、\\/に置換する対応を取っていました。 最近ではSystem.IOが提供しているPath、Directoryクラスをラップするクラスを用意してその中で、デリミタを置換する処理を使って回避してたりします。

こんな感じで

public static class Path
{
    public static string ReplaceBackSlashToSlash(this string self)
    {
        return self.Replace('\\', '/');
    }

    public static string Combine(string path1, string path2)
    {
        return System.IO.Path.Combine(path1, path2).ReplaceBackSlashToSlash();
    }

    public static string GetExtension(string path)
    {
        return System.IO.Path.GetExtension(path).ReplaceBackSlashToSlash();
    }

    // System.IO.Pathクラスが提供している関数を粛々と定義
}

prefab内にprefabを配置

prefabA内にprefabBを配置して、prefabBを編集してもprefabA内のprefabBは変更が反映されないという事がありました。 その時は、prefabAにprefabBの参照を持たせてinstantiateをする事で回避していた気がします(うる覚え)  現在はNested Prefabが提供されているため気にすることはなくなりました。

複数解像度を考慮したUI

UI配置をする際に解像度の違いを考慮せずに作っていたため、開発終盤やQAの時に発覚し粛々と修正する事もありました。
最初に考慮して作っていればよかったんですけどね・・・。

画面切り替え

Sceneを切り替えて作った方のがいいのか、1つのScene内でprefabを切り替えて作る方がいいのか?という事にも悩んでいました。 当時はScene切り替えは重いのでprefabを切り替えて作る事が多かったかな思いますが、最近ではあまり気にせずに作りやすい方法で作ってしまうのがいいのかなと個人的に思っています。

アセットバンドル

2重でロードするとエラーが発生したり、パスの大文字、小文字を識別するためその違いによるロードエラーに悩まされたりしていました。
あと、開発初期はResourcesを使用していたが、あとあと配信用アセットバンドルに変更する事で読み込み処理を書いていた箇所を粛々と修正するというような事も発生していました。
それらを解決するためクラスを用意している所も多かったのではないでしょうか。
今はAASがあるので、そのまま使ったり拡張して使えたりして便利ですね。

まとめ

振り返ってみると色々とでてきますね。
当時はUnityを使ってる人が周りにいなくて、情報も少なかった為、手探りでやっていました。
最近は使ってる人や情報も増え、検索するとすぐ解決できたり、参考になる情報がたくさん出てくるのでありがたいですね!
もし、困った事や悩んでいる事がでてきたらまずは検索してみるのがいいですね。

最近よく見るサイトで

は、とても参考になる内容が多いのでおすすめです!

最後に、

  • 楽しむ事
  • 完成させる事

がとても大切な事かなと思うので忘れずに、色々模索しながら引き出しを増やしていこうと思います!