OSSな.NET向けライブラリを作って公開してみた


この記事は [個人開発 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/private-development) の21日目です


# 軽く自己紹介

会社では、パッケージ製品のサーバー・クライアントのWindowsアプリケーションを
作っているC#エンジニアです。
最近は、趣味でReactも使っていますが、こちらはまだまだです。

# 作ったものの紹介

.NET向けライブラリで、コマンドライン引数やレジストリや設定ファイルなんかを簡単に統一的に扱えます。
ApplicationRegistries と名付けました。

* GitHub: https://github.com/banban525/ApplicationRegistries
* Nuget: https://www.nuget.org/packages/ApplicationRegistries

個人開発というと、Web系のサービスだったりするようなので、
ネイティブアプリ向けのライブラリで申し訳ないですが、軽く紹介します。

普通のアプリケーションって、待ち受けするポート番号やタイムアウト時間なんかは、
環境によっては変える必要があり、設定を外出ししますよね？
ただ、単に外出ししたいだけなのに、いろいろ考えないといけないのが苦痛で、
さらっと書くだけでいい感じに設定値を外出しできる方法が欲しかったんです。

こんな感じで書くだけで、レジストリやコマンドライン引数、環境変数を自動的に探して、
値があればそれが返されます。
もちろん、デフォルトのレジストリキーやコマンドライン引数は変更可能です。

``` csharp
[ApplicationRegistry]
public interface ISettings
{
  /// <Summary>
  /// 待ち受けするポートNo
  /// </Summary>
  [DefaultValue(80)]
  int PortNo { get; }

  /// <Summary>
  /// タイムアウト時間
  /// </Summary>
  [DefaultValue(60000)]
  int Timeout { get; }
}

class Program
{
  static void Main()
  {
    int portNo = ApplicationRegistry.Get<ISettings>().PortNo;
  }
}

```


詳しい仕様書は [GitHubのReadme](https://github.com/banban525/ApplicationRegistries/blob/master/README.ja.md)、[Qiitaの記事](https://qiita.com/banban525/items/c7f052bde3d13c9264bd) を見てください。


単に設定を外出ししたいだけなのに、レジストリだとキーの存在チェックとかnullチェック、
コマンドライン引数だとパーサーを書かないといけない、とか面倒ごとがいろいろあります。
それが億劫になって、ハードコーディングしちゃうと、いざという時に困ります(というか困りました)。
特にコンパイル型言語はその場でちょこっと修正するとかできません。

できるだけ無駄なことを考えなくても、後からイザというときに設定値を変更できる仕組みにしたつもりです。

あと、使っているレジストリ一覧を文書にしろ、とか会社では言われるので、
その辺も自動化できるようにしてあります。

どちらかというと自分が必要だから作ったのと、せっかくだからOSSにして
今風のモダンな開発をやってみたかった、というのが開発の動機です。


# 個人開発っぽく作ってみての所感的なものを 

宣伝(？)はこれくらいで、一応[個人開発 Advent Calendar](https://qiita.com/advent-calendar/2018/private-development)なので、
.NETアプリの個人開発についての所感的なものを書いていきます。

## OSSの.NETアプリ

定量的では無いですが、OSSの.NETアプリは少ない気がします。
元々.NET Frameworkが非OSSなのでそのためかもしれませんが、
最近は、.NET Coreでオープンソース化が進んでいるので、活性化するのを期待しています。
今回、ライブラリをOSSで公開しているのも、少しでもそこに貢献できればと思っています。

## CI

最近のソフトウェア開発では、単体テストおよびCIは必須です。
しかも、OSSのCIといえば、サービスを利用するのが当たり前。
ただ、.NET FrameworkベースのCIサービスは、少し調べてみましたが
[AppVeyor](https://www.appveyor.com/) 一択のようですね。
.NET Coreならもう少し幅がありそうでしたが。

逆に、このAppVeyor、WindowsServerのコンテナで動いているようで、
バッチもPowerShellも使えるし、msbuildやnugetも使えて、
Windowsガッツリなエンジニアにとってはとても使いやすいです。
これが無料に使えるなんて・・・。
クローズドな社内にJenkinsを抱えておくのが嫌になってきます。

他にも、AppVeyorでのビルドから、Nugetへの自動的にデプロイできるようです。
これは、頻繁にNugetにデプロイするほどでもないかと思い、手動にしています。

## Nuget

.NET Frameworkにおけるパッケージマネージャですね。
Javascriptでいうところのnpm。

ここに置いておけば、インターネット経由でどこでもダウンロードできますし、
公開する場所を考えなくてもよいのは楽です。

さすがに、何も宣伝しないと、バージョンアップの公開後1か月経っても43ダウンロードですね。
たぶん、3が自分の実験で、40がクローラーだと思います。
nugetもローカルにキャッシュするようになったので、ダウンロード数は昔ほど増えないのかもしれませんね。

Nugetのページはこちらです。
https://www.nuget.org/packages/ApplicationRegistries

## .NET Standard？

最近の.NETのOSSに関連して、.NET Frameworkと.NET Coreの両方から使える
.NET Standardなるものがあるようです。
.NET Standardで作っておけば、どちらからでも使えると。

ただ、実際使ってみると、なぜかSystem.IO.dllやSystem.Linq.dllといったアセンブリが大量にダウンロードされて
よくわからん状況になりました。
同僚からは「そんなはずはない」と言われたので勘違いかもしれませんが、
.NET Coreはともかく、.NET Frameworkでライブラリ参照するだけどアセンブリが大量に増えるのはどうかと。

ということで、Nuget的には、.NETFramework 4.5以上、.NET Standard 2.0以上の両対応にしてあります。
ソースコードは同じなのに、わざわざ.NETFramework 4.5用のプロジェクトと
.NET Standard 2.0用のプロジェクトを2つに分けています。
ちょっといまいちな感じ。

もしかしたら、新形式csprojの「複数ターゲット」が使えるのかもしれませんが、詳しくは調べていません。
参考: https://ufcpp.net/blog/2017/5/newcsproj/

## メタプログラミング

このライブラリ、内部は高速化のためにReflection.Emitというメタプログラミングを使って、
実行時に動的にクラスを生成しています。
このメタプログラミングって、黒魔法みたいで好きなんですよね。
ただ、会社のプロダクトで、こういう特殊な技術を使うと、ホシュガー、とか言い出す人がいますし、
そもそも力技で実装可能なら、外注使って作ったらいい、ということになります。
自由な個人開発では、普段できない特殊な技術が生きてくるところな気がします。

Reflection.Emit は、強力で今後も使うことがあると思いますが、
ILを理解しないといけないとか、結局逆アセンブルして移植しないと、とかあって
ちょっと面倒ので、できるだけ避けたいですね。
式木によるメタプログラミングでクラスまで作れたらいいんですが。

## 時間感覚

わかっていたことですが、アイデアを実現して使えるようになってから
GitHubとNugetで公開できるまでは感覚的に5倍くらい時間がかかりました。

具体的にはこんな手間があります。
* 入力のバリデーションや異常系の実装が必要
* リファクタリングしておきたい
* Readmeは欲しい
* 当然Readmeは英語にしたい
* コメントやテストコードにも日本語が・・・(あきらめました)
* 単体テストを整備したい
* CIで常時テストしたい
* GitHubのReadmeにバッジを付けたい

あまり時間がかかると飽きてくるんですよね。
特に私は下に書いた事情で個人開発の時間は短いですし。
難しいですが効率化する良い手はないでしょうか・・・。


## 個人開発のモチベーション

「自宅に帰ってまでコーディングする気にならない」
よく聞きます。私も同じです。
会社出るときとか帰宅中はあれこれやろうと考えるのですが、
自宅に帰るとやる気が消滅する、ありがちですね。

私は、子供もいるので自宅でコーディングするのはあきらめました。
その代わり、ノートPCを持ち歩いて電車の中でコーディングしています。
もちろん、座れることが前提ですが。

習慣付けるとなかなかいいものです。

* 重たいもの運んでいるんだから使わないともったいないという気になる
* 通信料が気になるのでできるだけローカルでできることに集中する
* ~~怪しげなサイトや動画を見られない~~

どこの路線かまでは言いませんが、電車の中で座ってコーディングしているおっさんを
見かけたら私かもしれません。

# 最後に

個人開発のネタとしてはいまいちだった気がします。
やはり、こういった場で目に付くのは、
Webフロントエンドだとか、機械学習、でしょうか。
しかし、ただ流行りに乗るのではなく、
ネイティブアプリだったり、Windowsだったり、どちらかというと裏方だけど
一定数の開発者がいる分野にも目を向けて、
少しでも楽になるように、OSSで盛り上げていきたいですね。