Upgrade to Pro — share decks privately, control downloads, hide ads and more …

メタプログラミングでEXCEL仕様書よ、さらば!

 メタプログラミングでEXCEL仕様書よ、さらば!

EXCEL仕様書に悩まされた結果、どうやってEXCELを仕様書と言う地位から引退してもらうかと言う取り組みです。

C#のリフレクションや式木を使い、仕様書に機械的に転記すべき情報をソースコードから抽出する手法を紹介します。例示として:

* メッセージ表をEXCELで管理するのをやめる
* CSVファイルの構造をEXCELで管理するのをやめる

の、具体的な方法を解説します。

要点は、EXCELを原本にするのではなく、EXCELをビュワーとして割り切る方向に発想を転換する、という事です。

EXCELはデータを加工して視覚化する事には向いています。その能力を生かしつつ、どうやってコードとの整合性を担保するか、手を抜くか、作業性を向上させるか、という事を考えます。

EXCELを(それを欲する人のために)仕様書化しても良いのですが、原本がEXCELである必要はない、という事です。

古い発表なので、現在なら更に改善できる部分がありますが、発想は今でも通用すると思います。

------

第一回 Center CLR 勉強会
(募集エントリはDoorKeeper退会で失われているため、ブログ)
https://www.kekyo.net/2014/11/02/3501

Kouji Matsui

November 01, 2014
Tweet

More Decks by Kouji Matsui

Other Decks in Programming

Transcript

  1. 自己紹介  Center CLR 第一回参加ありがとうございます!! 私が張本人のいいだしっぺです! とうとうやっちまった… 頑張ります!  自転車乗りです。

     会社やってます。  Windows Phoneとか好きです。SIMフリーであぽーみたいにMSが直販してくれないかなぁ。  クラウディアたん
  2. EXCEL仕様書の全てを否定するわけじゃない  無駄をなくしたい(という所は共通認識だよね? ね?!)  一番うんざりするのは、データ構造の定義とか、マトリックス表とか  だって、この後、これを見ながらコード書くんでしょ? 機械的な作業なんて無駄だよね。 

    それに対して、アーキテクチャの説明とか、人間にしか読めないし書けない部分は、勿論仕様書として 書き起こすべき。  ところで、それって、EXCEL方眼紙で書く必要性あるの? W  ややこしい組み合わせの検証の為に、表にして可視化するのはOK。ただ、そもそもその構造本当に大丈夫?  でも、やっぱり定義系の記述は、表形式になっていたほうが、保守しやすいよね。 って言うけど、保守って何さ? EXCEL直してコード直して だんだん!!
  3. 逆方向に出来ないか  発想を逆転させるんだ。  こういう発想は、そもそも「ソースコードの情報を、再解析するのが難しい」から、ドキュメント→ ソースコード の順で考えるのが自然って事になってるだけでは?  それがウォーターフォール的な手法に組み込まれて、効率が良いように見えてしまっているのが問題。 

    コードを書いた後で、定型的にデータ構造表やらマトリックス表が抽出できれば? しかもそれを自動で。  「そんなの事実上無理じゃん。C#のコードを解析しないと出来ないわけで、コンパイラのパーサー書けって レベルじゃん」  さて、その為にこの勉強会があるわけですよ。 ご注意:ウォーターフォールはクソと思っているので、バイアス かかってます。補正する気は無いです。
  4. 勃発  このEXCELファイルを、チーム内で共有し、メッセージの追加や変 更が必要なら編集します。 → ソースコード管理と相性が悪い! → マージしたいんじゃ! → 編集面倒なんですけど!!

     対応するキーを、連番で含めます。 → 誰だよ、番号勝手に変えたやし!! → ねぇ、この定義いらないんだけど、連番付け直すの? → 同じ番号の定義がいくつもあるぞ!! → いつの間にか仕様書の番号が1個づつずれてる orz 改善策: 専任の管理者を決めて、その管理者が修正 を正しく行うようにしよう。 混乱するから、変更依頼伝票を作ろう。
  5. ソースコードから表を起こす  ソースコードに記述した情報を収集して、EXCELの表に出来たとしたら? → 成果物から生成されるから、転記によるミスがない。 → マージの問題は、ソース管理システムで担保出来る(だって、ソースコードなのだから)。  キーはどうする? →

    連番も諸悪の根源なので、連番付けしなくても良い方法を考える。  ソースコードにハードコーディングしたら、運用時に変更出来ないじゃないか → 本当にそうかね? アラアラ、それは一体イツの時代の知識なのカシラ、ネ
  6. メタデータを使おう  メッセージは文字列なので、string型で定義 する。これをstaticなフィールドに定義させ る。  キーに相当するものとして、名前空間名+ クラス名+フィールド名の組み合わせにす る。 

    これなら絶対に重複しない(同名のメンバー が異なるアセンブリで存在した場合はNGだ が、あまり起きないことに注力してもムダな ので考慮しない)  これを実行時に取得しよう。  取得用のメソッドを準備。 ええと、まだ何もしてない
  7. ラムダ式で式木 Lambda title2 = Body: Member Parameters: [0] Expression: null

    Member: FieldInfo Expression.Field スタティック フィールドなので null FieldInfo Expression.Lambda C#コンパイラはこのように展開する
  8. 式木(Expression Tree)を使う  フィールドの指定にラムダ式を書 かせる。  最低限の記述負担で行ける。  ラムダ式は式木に変換されていて、 FieldInfoを取り出せる。

     フィールドだけを指定可能なよう に、強く制約する事は出来ない。  妥協点としては良いところか。 ラムダ式でフィールドを指定 文字列で指定しないので、タイプセーフ ラムダ式を書かせて式木で受ける 式木からFieldInfoを取り出す
  9. これで文句ない? このファイルを元ネタにすれば良いよね? 「一覧が見たい」のなら、どうぞEXCELの 神機能を使って見まくって下さい。  エンハンスネタとして:  GetMessageに可変引数を追加すれば、FormatMessageとか作れるね。  上記のEXCELフォーマットを拡張して、カスタマイズしたいメッセージだけを書き入れるカラムを追加する。

    → ハードコーディングされたメッセージと比較しながら、メッセージを修正できる。  リフレクションで参照するアセンブリは、フォルダ内のDLLを一括読み取り出来るようにする・あるいは別の ツールとして分離する。  Stringではなく、何らかのモデルクラスを使わせることにより、もっと多くの情報をマッピング出来る。 例:メッセージボックスに出力する事を前提に、メッセージボックスのアイコンを指定させるとか、メッセージボックス の戻り値をタイプセーフにする(モデルクラスをジェネリックにして、T型に列挙型を指定させるなど)
  10. 開発手順がどう変わるか?  キー名の事は忘れて良い。定義は「そこ」にハードコーディングされているし、非人間的な、連番管理とかいら ない。  メッセージをオーバーライドしたい運用管理者だけが、識別しやすいシンボル名ベースのキーで区別すればよい。  インテリセンス・リファクタリングツール・静的解析ツールに親和性がある。  キー名の変更も楽々。相応しくないと思えばすぐに修正出来る。変更に失敗してもビルドエラーで検出できる。

     誰がこのメッセージを参照しているのか、なんて、EXCELなんて見なくてもすぐに把握可能。  メッセージ定義は全てソースコード上に存在するので、マージが楽。  メッセージの差し替えは、完全に運用の現場に移譲できる。  差し替え用の元ネタファイルを提供できるので、後は勝手にやってよ。って言える。 最終的に、開発・保守の効率を上げるという「価値」を生み出すというこ とが重要。 これを出発点にしないと、合意形成は難しい。なぜなら、太古の手法を変 えたくないという心理が働くから。
  11. CSVファイルを読み取る  ちょっと別の方向から攻めてみます。  CSVファイル(カンマ区切りレコード)の読み取りをどうやってる?  StreamReaderを使って自前でパース? まさかね。  いやいや、ここは、少なくともTextFieldParserクラスを使ってよ。

     え、なにそれ?  何と「Microsoft.VisualBasic.FileIO.TextFieldParser」というクラスで、「Microsoft.VisualBasic.dll」に あるわけです(参照設定してね)。  ええー? VBぃぃぃ? 応用性あるの、そのクラス…  意外としっかり作ってあります。  Encodingクラスは勿論対応、セパレータ文字列を指定可能、ダブルクォートの自動認識あり、と、普通 に使うには全く問題ないレベルです。
  12. モデルクラスを作る  フィールドの型をどうにかしないと。  形式のカラムを読み取り:  「32ビット整数」→ int  「文字列」→

    string  「真偽値」→ bool  「8ビット整数」→ byte  「8ビット整数」は本当にこれでいいのか?  値には「変更なし」とか「指令都市施行」などという、具体的な意味が割り当てられている。  Enumっぽいよね。Enumにしよう。
  13. リフレクションで入れればいいんでね?  手で変換コードを書きたくないよね。  リフレクションを使えば、自動化できそうだ。  問題がいくつか:  フィールド位置の対応付けをどうするか。 

    CSVはすべて文字列なので、型変換をどうするか。 ソースコード上、たまたま 順序通り並んでいるが、リ フレクションで順序が維持 される保証はない
  14. 属性クラス is 何  CLRのメタデータを拡張可能な概念として「属性クラス」がある。  カスタム属性クラスを定義すれば、メタデータに情報を付加できる。  例:XmlSerializerクラスは、「XmlElement」や「XmlAttribute」属性を使って、XMLの表現方法をカスタマイ ズできる。

     CSVのフィールド(モデルクラスのプロパティ)に、カラム位置を付加すれば判別可能になるよね。 カラム位置を保持するカスタム属性 プロパティ情報 (PropertyInfo) CsvColumnIndexAttribute Index = 1 Name = “旧郵便番号” GetCustomAttributes()
  15. カスタム属性クラス is 何  属性クラスは「Attribute」クラスを継承する必要がある。  属性クラスは「AttributeUsage」属性を適用する必要がある。  → 属性クラスに属性を適用するとか、モヤモヤするかもしれないけど、こういうものだと割り切って下さい。

    Attributeクラスを継承 AttributeUsage属性を適用 (この属性はプロパティにしか適用できない事を宣言) コンストラクタで値を受け取る 事が出来る プロパティで見えるように しておく
  16. モデルのインスタンス生成が… ジェネリック制約「where T : new()」が使えない。 制約にはコンストラクタ引数を定義出来ないため すると、「var model = new

    T();」と書けなくなる。 仕方が無いので、動的にインスタンスを生成。 コンストラクタ引数がある (フィールド文字列群)
  17. まとめ  わざわざ難易度の高い技術まで含めてお見せしたのには訳があります。今や、CLR内のメタデータを 使って、色々な事が出来る、という事を示したかったからです。  実際には自分でコードを書かなくても済む場合も多いです。本稿で示した内部の実装は、既にライブ ラリとして提供されています。例として:  EntityFrameworkは、データベースへのアクセスを抽象化します。テーブルやカラムといったデータベースの 要素を、メタデータの属性でマッピングさせることで、データベースプログラミングを大幅に簡略化します。

     本稿のCSVファイルへのアクセスは、「LINQ to CSV」というオープンソースのライブラリで同様の機能を実 現しています。モデルクラスへの自動マッピングによって、CSVファイルへのアクセスもタイプセーフ性を前 提に出来ます。また、「LINQ to twitter」を使うと、ツイッターのタイムラインデータを、タイプセーフなモ デルクラスを用いてアクセス出来ます。  もっともBasicな、XmlSerializerも、メタデータを活用した例です。  SandCastleや類似ツールこそ、ドキュメンテーションの為にメタデータを活用する良い例です。(リファレ ンスとしての有用性はまた別の話題) 総じて、昔では(事実上)出来ない事だったことは、今では当たり 前に出来る事です。
  18. まとめ  これらのサードパーティライブラリ群に加えて、Visual Studioを取り巻く開発環境が非常に強力です。  本稿で取り上げた「インテリセンス」や「リファクタリング」機能が標準で備わっています。従来のテ キストベースの一括置換で、誤って変更してしまうような事故がありません。  「一度決めた仕様を変えるな!」あるいは「一度決めた仕様を変えるためには開発運用手順に従って….」とい う足かせは、改善に対する前向きな取り組みを徐々に破壊していきます。

    「どうせ言ってもムダだし」「言われたところだけを言われたようにやっておけばいい」という文化につながっ てしまいます。  そもそも、ルールを定めなければならなかった理由の一つが、そうしないと直ぐにコードが破綻してしまうから です。しかし、リファクタリングツールはそれを機械的に自動的に安全に処理出来ます。このエコシステムに 乗って開発しないと、高価なツールを使っている意味がありません。  リファクタリングや静的解析ツールは、サードパーティ製のツールを導入すると、更に強力になります。 「Resharper」や「NDepend」の価格と、自分の時給換算の報酬額を比較してみて下さい。無駄な残 業何日分で導入できるでしょうか? そして、全自動・半自動で行われるこれらの作業が、自分の時間を どれだけ解放できるでしょうか? その時間は是非「人間にしか出来ない作業」に使って下さい。