No more Death March

あるSEのチラシの裏 C# WPF

プロジェクトの分離について

色んな書籍をみても、c#のプロジェクトやjavaのパッケージの分け方について深く言及しているものがあまり無い。

 

 

最近思うのは、プロジェクトやパッケージの分離方法の勘所を抑えていれば、自ずとメンテナンスが容易なシステムになるのではないかということ。

 

モデリングアーキテクチャに対する理解も必要だと思うのですが、個人の解釈次第なところが多いし、もっと具体的に、こういうクラスはこういう名前空間で、こうやってライブラリ分離します。そうするとこういうメリットやデメリットがありますよ。

 

こういう話題がもっと目についても良いと思っています。

 

今はまだ自習のなかでうっすら手応えを感じているレベルですが、この辺の考え方が上手くまとまれば設計の際に迷うことが無くなりそう。

 

 

 

C# 自作ライブラリの検討メモ

デザインパターンオブジェクト指向エクササイズの教材として自作ライブラリを作ろうと検討中。

名前空間についてメモ


Nmdm
 ⇒最上位の名前空間、ブログ名から

Nmdm.Pair
 ⇒ジェネリックインターフェースで二つのインスタンスのペアを表現

Nmdm.Collection
 ⇒IEnumerableを持つ拡張用インターフェース

Nmdm.Range
 ⇒ジェネリックインターフェースで型の範囲を表現

Nmdm.Comparer
 ⇒.NetのIComparer関連の拡張 インターフェースは不要

基本型を拡張する場合の名前空間(例:string)

Nmdm.String
 ⇒stringインスタンスを持つインターフェースIStringの宣言場所

Nmdm.String.Wrapper
 ⇒基本型のラッパー実装場所

Nmdm.String.Decorator
 ⇒単一のstring型インスタンスで成立する処理をデコレーターパターンで記述、IStringを返す。
  ToWide、ToNarrow、ToUpper 等

Nmdm.String.Comparer
 ⇒IComparerの実装場所

Nmdm.String.Adapter.Length
 ⇒(変換元の型).Adapter.(変換先の型)のルールで変換ロジックをアダプターパターンで記述


Pair、Collection、Rangeなど汎用的なデータ構造は型名の後に名前空間を入れる。
Nmdm.Int.Pair.Adapter.〇〇
 ⇒IPairに関する実装

Nmdm.Int.Range.Decorator.〇〇
 ⇒IRangeに関する実装



基本ルール
・完全コンストラクタパターン
・メソッドをアダプタパターンまたはデコレーターパターンで分離、ミックスインにする。
・処理を実装する箇所では全てのメンバーを使う。
・LengthやCount、Year、Monthといった用途が定まりそうなものは別途インターフェースを設け、IIntなどより抽象的な型に依存させる。

c# リフレクションの使いどころを考える

ソフト全体で使いたいインターフェースがある時、
インターフェースとその実装を同じプロジェクトに入れると実装部分をメンテナンスする度に大規模なビルドが必要になる。

そもそも抽象(インターフェース)に依存して処理を標準化するのに実装を直す度にビルドが走るのはおかしな話。

それを回避する方法として、インターフェースと実装を分離し、UnityなどのDIを使うのも良いのだけど、
粒度の小さく凝集度の高いものを毎回DIで実現しようとするとDIのためのコーディングだけで手間がかかってしまう。

そこでリフレクションを使ってインターフェースが宣言されているプロジェクト内でリフレクションを使って実装クラスのアセンブリを読み込んでしまう。

プロジェクトの依存関係は実装⇒インターフェースの向きなので依存関係に逆転した読み込みが行われることになる。

一見するとおかしな考え方に思えるが、こうすることによって実装以外のインターフェースに依存するプロジェクトから
インターフェースの実装プロジェクトに対する依存を完全に排除することが出来るし、実装をチューニングしたりリファクタリングしても、
クライアントプロジェクトのビルドが実行されることはなくなる。

ステートソーシングな設計をイベントソーシングな設計に

ステートソーシングな設計の「商品テーブル」をイベントソーシングな設計に置き換える時のイメージをメモ

「商品テーブル」
・ID
・コード
・名称
・登録担当者ID
・登録日時
・更新担当者ID
・更新日時
・削除担当者ID
・削除日時

手順1)ドメインに関する出来事を箇条書きにする

・新しい商品を登録した。
・商品の名前を変えた。
・商品のコードを変えた。
・商品を削除した。

手順2)出来事をテーブルに置き換える

・「商品が登録されましたテーブル」
・「商品の名前が変わりましたテーブル」
・「商品のコードが変わりましたテーブル」
・「商品を削除しましたテーブル」

手順3)各テーブルの列構成を考える。

「商品」
・ID

「商品登録されましたテーブル」
・ID
・商品ID
・担当者ID
・発生日時

「商品の名前が変わりましたテーブル」
・ID
・商品ID
・新しい商品名
・担当者ID
・発生日時

「商品のコードが変わりましたテーブル」
・ID
・商品ID
・新しいコード
・担当者ID
・発生日時

「商品を削除しましたテーブル」
・ID
・商品ID
・担当者ID
・発生日時

C# プロパティとメソッドの違い

プロパティとメソッドとの違いについておさらいします。

MSDNに掲載されている説明は以下の通り。

プロパティとメソッドの選択

一般的に、メソッドは操作を表し、プロパティはデータを表します。

例えば「人」オブジェクトがあれば、
「名前」や「性別」はデータで、
「歩け」や「走れ」といった操作(動作)はメソッドですよ。
ということだと。

お仕事プログラミングはVB6から入った身なので、
当時は疑うこともなくプロパティを使っていたけど、
オブジェクト指向設計の面で考えるとこのメソッドなのかプロパティなのかっていうのが、
返って話をややこしくしていると思う。

そもそもJavaだとかRubyだとか、C#で言うプロパティというのは無いわけで、
Microsoft系言語のガラパゴスな仕組みだと認識しています。

少しでも脳みその負担を減らすために、いっそプロパティを使わずにプログラミングした方がいいんじゃないかとすら思う。

Javaからプログラミングに入った人だとJavaC#と移った時に
プロパティ?なにそれ?プロパティファイルじゃなくて?ってなるんでしょうかね。

書籍「現場で役立つシステム設計の原則」を読んでみて。

7月5日に発売されたのでさっそく購入しました。

この本の著者の増田さんという方、
DDDやOOPに関する資料をSlideShareに公開していて何度も目にしていました。

流し読みしてみての感想ですが、
SlideShareの内容を書籍にまとめ、より詳しく解説を加えたものという具合です。

↓↓↓増田さんが公開している資料↓↓↓
www.slideshare.net

個人的にはとても良い本だと思う。
これから何度も読み返して頭に馴染ませて行きます。

オブジェクト指向設計を勉強しよう!」ってなって、実践DDD本やリファクタリング本を読み漁りましたが、
この本を最初に読んだ方が分かりやすかっただろうなぁ・・・

文字列からプリンタを取得

using System;
using System.Printing;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var queueByFullName = new PrintQueue(new LocalPrintServer(), LocalPrintServer.GetDefaultPrintQueue().FullName);
            Console.WriteLine(queueByFullName.FullName);
            Console.ReadKey();
        }
    }
}

PrintQueueクラスのコンストラクタにPrintServerクラスのインスタンスとプリンタの完全名(文字列)を渡すと取得出来る。


以下のようにインストールされていないプリンタ名を指定するとSystem.Printing.PrintQueueExceptionが発生する。

using System;
using System.Printing;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //var queueByFullName = new PrintQueue(new LocalPrintServer(), LocalPrintServer.GetDefaultPrintQueue().FullName);
            var queueByFullName = new PrintQueue(new LocalPrintServer(), "Hoge");
            Console.WriteLine(queueByFullName.FullName);
            Console.ReadKey();
        }
    }
}