C# のコーディング規則

C# のコーディング規則
Microsoft公式ドキュメントに「C# のコーディング規則」が追加されました。
2021/5/14 の新しい内容です。

この記事のガイドラインは、サンプルおよびドキュメントを開発するために Microsoft によって使用されます。これらは、.NET ランタイムの C# コーディング スタイル ガイドラインから採用されました。それらを使用することも、ニーズに合わせて調整することもできます。 主な目的は、プロジェクト、チーム、組織、または会社のソース コード内での一貫性と読みやすさです。

とあるように、Microsoftでも使用される内容なので、
コーディング規則はこれをベースにするのが良さそうです。
フィールドはキャメルケースに_プレフィクスを付ける事が明文化されています。

  • private または internal のフィールドに名前を付ける場合は、キャメルケースを使用し、_を使用してプレフィックスを付けます。
  • ステートメント補完をサポートする IDE でこれらの名前付け規則に従う C# コードを編集するときは、「_」と入力すると、オブジェクト スコープのすべてのメンバーが表示されます。
  • なので自動実装ではないプロパティを使用する場合、
    バッキングフィールド名はプロパティ名の先頭を小文字にして_プレフィックスを付けたものになります。

    あと気になった点は、次のような点でしょうか。
    コメントは文章で書くようにという事ですね。

  • private または internal である static フィールドを使用する場合は、s_プレフィックスを使用し、スレッド静的には t_を使用します。
  • コメントのテキストはピリオドで終了します。
  • もちろん最初に書いてあるように、この規則はニーズに合わせて調整することもできますが、
    基本の規則として知っておくと良いと思います。

    PlantUML を試してみました。

    5月の連休を利用して、UML図の作成にPlantUMLを試してみました。
    VSCode + 拡張機能の流行りの組み合わせです。
    普段は別の専用ソフトを使っているので、
    テキストベースで図を作成するのは、個人的には初めてです。

    練習に社内の研修用ソフトのシーケンス図を作成してみると、
    予想以上に簡単に作成することができました。
    テキストベースなので要素の配置などレイアウトを考える必要もなく、
    シンプルに書きたい事を書くことができる印象です。

    ほんの些細な事でも考える事が少なくなると、
    やりたい事がよりはっきり見えてくるのを実感しました。
    プログラムのソースコードを書くときでも、
    スコープは狭くする、ネストを深くしない、メソッドは小さく分ける…など、
    余計な事を考える余地が少なくなるよう工夫したいと思います。

    読みやすいコード

    コードは理解しやすくなければならない。
    「リーダブルコード」にもそう書かれています。

    他の人が読みやすいかどうかというのはとても重要な事だと思います。
    適切な変数名やメソッド名は理解を助けますし、
    説明変数なども積極的に利用するようにしています。
    書き方ひとつとっても、
    例えば変数を宣言して anotherClass のみ遅延した初期化が必要な場合、

    var myClass = new MyClass();
    var yourClass = new YourClass();
    AnotherClass anotherClass;

    と書くよりは、

    var myClass = new MyClass();
    var yourClass = new YourClass();
    var anotherClass = default(AnotherClass);

    と書く方が、それぞれの変数の位置が揃っていて、
    読みやすいのではないでしょうか。
    気取らず、気の利いた美しいコードを目指したいと思います。

    C#9.0 record

    C#9.0でrecord型が追加されました。
    まだ実務では使用していませんが、
    今後C#でとても重要な機能になると思っています。

    最も活躍できるのが、DDDのValueObjectでしょうか。
    今まではそれらしい事をするには等値性を表現する為に、
    Equals()やGetHashCode()をoverrideする必要がありましたが、
    record型はコンパイラが自動で行ってくれます。

    そして定義がとても簡単に行えます。
    Microsoftの説明を引用すると、

    public record Person {
     public string LastName { get; }
     public string FirstName { get; }
     public Person(string first, string last) => (FirstName, LastName) = (first, last);
    }

    と同じことが、

    public record Person(string FirstName, string LastName) { }

    と書けます。とても簡潔ですね。

    リファクタリング

    既存のソースコードに新しい機能や変更を加えようとするとき、
    まず既存のコードをリファクタリングします。
    そして切り出したり共通化したクラスやインターフェースなどを、
    ソリューションやプロジェクト内のどこに記入するべきか考える必要があります。

    全体の設計思想や、選択したフレームワークによって、
    適切な場所があるはずですが、なかなか上手く収まらない事もあります。

    そのような場合は、自分が全体の設計思想に対する理解が足りていないか、
    ソリューションやプロジェクトが上手く構成できていない事がうかがえます。

    リファクタリングは基本的には必要な時に行いますが、
    例えばテストファースト開発のように、
    開発サイクルの中で常時行う方法もあります。

    年末の大掃除と同じように、まとめて後でやろうとすると大変です。
    普段から少しずつ行っていればリスクも少なく、
    ソリューションやプロジェクトの構成もより明確になってゆくものだと思います。

    リファクタリングであまり悩むことが無いよう、
    安心して開発できる環境を目指したいと思います。

    デザインパターン

    GoFの23のデザインパターンを学習しています。
    デザインパターンの多くは、
    抽象的な概念を抽象クラスやインタフェースで定義して、
    継承や実装により、実クラスで表現する手法を取ります。

    デザインパターンを知ると設計の幅が広がるとともに、
    ソースコードを読むときの理解の助けにもなると思いました。

    例えばiPhoneで使われるviewには、
    Observerパターンが使われているものがあります。
    Observerパターンを知っていればすぐに理解できますが、
    知らないと概念の理解に少し苦しみます。

    チームで開発を行う場合でも、
    「ここはSingletonパターンを使おう」など、
    言語を問わずに共通の概念を共有することができるので、
    連携がスムーズにできそうですね。

    Microsoft Code Analysis

    自宅で使用している Visual studio に、
    「Microsoft Code Analysis」を導入してみました。
    VSの拡張機能から簡単にインストールすることができます。
    コードの問題を検出して、改善・修正の提案を行ってくれるので、
    初学者の方にもおすすめです。

    例えば次のような冗長なコードを書いてしまった場合でも、
    if(isDebug == true){ ...
    コードを簡単にできる旨をヒントや警告で表示してくれて、
    クリックで修正する事ができます。
    if(isDebug){ ...
    他にも private にできるメンバーを教えてくれたりなど機能が豊富で、
    自然と Microsoft が推奨する、一般的なコードを書くことができるようになります。

    会社では ReSharper を使用しているので必要無いのですが、
    自宅でも同様の分析機能があると少し安心します。

    Xamarin の開発環境

    弊社では Xamarin を用いてモバイルアプリも開発をしております。
    Xamarin はC#で iOS/Android などのモバイルアプリが開発できる、
    モバイルアプリ向けのクロスプラットフォーム開発環境です。

    ただし例えばiOSアプリをWindowsで開発する場合でも必ずMacが必要で、
    Mono、Xcode、Visual Studio(Mac)、Visual Studio(Win)、Xamarin などの、
    使用するソフト間のバージョン関係がとてもシビアです。

    先日 Visual Studio(Win) Ver16.6 にアップデートした際に、
    ビルドができない状態となり、原因の特定に時間が掛かってしまいました。
    結局は Visual Studio の問題で Ver16.6.1 で修正されたのですが、
    これを機に Visual Studio(Mac) による専用の開発環境を整えて、
    開発時のソフトウェアバージョンをある程度固定する事にしました。

    Windows と Mac 間の通信が不要となり、
    ビルド速度が向上し、デバッグも安定するようになりました。
    普段は Visual Studio(Win) で開発を行っておりましたので、
    Visual Studio(Mac) やショートカットに慣れていこうと思います。

    DDD

    DDD(Domain-Driven Design) を勉強しています。
    解決すべき問題をドメインとして捉え、
    それをドメイン固有のルールなどと共にプログラムに表現していく手法です。

    DDDではEntityやValue Objectなどの概念が出てきます。
    C#でValue Objectを表現しようとした場合、classかstructか悩みました。
    結局classで表現することに決めたのですが、
    structはデフォルトコンストラクタを定義できない事が最大の理由です。
    例えば正の整数を保証する為に、以下のような事ができれば、
    structの利用の幅が広がるのですが実際にはできません。

    struct MyStruct {
    private readonly int _value;
    MyStruct() { //このコンストラクタは定義できない。
    throw new Exception();
    }
    MyStruct(int value) {
    if (value <= 0) throw new ArgumentException("0以下の値は設定できません。");
    _value = value;
    }
    …(略)…
    }

    Value Objectをclassで表現した場合、
    中身の値は保証できても、使う側はオブジェクト自体のnullチェックが必要となります。
    structの使いどころって、なかなかな無いものです。

    柔軟な発想

    ある機能をプログラムで実現する為に、
    少し視点を変えて、別の方法を思いつくと、
    意外と簡単に実装ができてしまう事があります。

    例えばバックグラウンドで読み込みを行っている時に、
    「Loading…」と表示される画面はよくあります。
    ユーザーから見れば「Loading…」の画面が、
    新たに作られて、表示されたように見えますね。
    そのままコードにするとこんな感じでしょうか。
    (クラスやメソッドなどは仮のものです。)

    LoadingView loadingView = new LoadingView();
    loadingView.Show();
    // バックグラウンドで行う処理
    loadingView.Close();

    これでも問題ありませんが、
    複数のバックグラウンド処理が重なった場合などは、
    さらに処理を考える必要があったり、
    表示の部分がシーケンス的であったり、少し複雑です。

    視点を変えて、
    「Loading…」画面の可視性が切り変わると考えた場合はこうなります。

    loadingView.Visible = true;
    // バックグラウンドで行う処理
    loadingView.Visible = false;

    「Loading…」の画面が表示されていない場合でも、
    見えていないだけでずっと画面内に存在しているイメージですね。

    実際には loadingView.Visible の部分は、
    LoadingView の可視性を表すプロパティなどにしておきます。
    こうすると、シーケンス的だった表示がステート(状態)となり、
    制御しやすくなります。

    難しい問題には頭を柔らかくして、
    様々な視点から柔軟な発想ができると、
    もっと単純に解決できるかもしれませんね。