write ahead log

ロールフォワード用

VB.NET(Windows Forms)で見積管理システムを作った

昨今の技術動向をガン無視ですが, ここ2,3ヶ月ほど深夜にぼちぼちやっていたのが形になったので.

github.com

Releaseにインストーラを入れてみました.

TravisCIが使えるかと思いましたが, 流石にWinformは無理でした.(VBはサポートしてるんですね)

目的

一応ある程度は作った目的があって

  • ある程度モジュール化された設計ができるかやってみる
  • テスト可能な設計ができるかやってみる
  • データバインディングスタイルで実装してみる
  • 使ったことの無いコントロールを知る
  • インストーラで入れて動くとこまで1人で作ってみる

お仕事もほとんどがVB.NET + Winformsなんですけどね.

やっぱシステムインテグレーションの業界にいると人売りか業務知識偏重になっちゃって技術面は仕事で伸ばすのは難しいかなと思います.

(面白いとこもありますけどね) 仕事でできないなら, 一度自分でやってみるかと.

作るもの

業務システムっぽいものを作らないと, あんまりリアリティがないです.

ということで, 単純な見積書を作成するシステムを作ってみる事にしました.

見積書はGoogleで適当に検索して出てきたテンプレートミックスしてフォーマットにしました.

こんな感じです.

f:id:twinbird_htn:20180217064620p:plain

UIは参考にするためにVectorでいくつか類似ソフトを落として見てみましたが, 参考になったのかよくわかってないです.

案外, 世の中にあるものは変わらないなという印象でした.

最終的に下記の様なUIにしました.

f:id:twinbird_htn:20180217064640p:plain

f:id:twinbird_htn:20180217064649p:plain

そんなわけで, 機能的には雑です.

利用ツール

仕事でやるわけじゃないので, 全部タダでないとなりません.(必死)

今のMSにはVisual Studio Communityがあります.

これのおかげで普通に開発ができました.

帳票が問題でしたが, MS Reportがあったので何とかなりました.

主だったライブラリは以下の通りです.

ライブラリ/ミドルウェア 用途
.NET Framework 4.5 これがないとはじまらない
MS Test テストフレームワーク
MS Report 帳票作成
ADO.NET RDBMSアクセス用
SQLite3 RDBMS
MS VS Installer Projects インストーラ作成

Entity Framework使わないの? という感じですが, あえて使っていません.(便利なのはわかります)

O/Rマッパーが嫌いなわけじゃないんですが

  • システム全体の規模が大きくなると最終的に複雑なSQLを発行する事になる
  • みんな横着してO/Rマッパーを使ってパフォーマンスが酷いことになる
  • みんな横着してO/Rマッパー使ったつもりが逆に辛くなる

というケースも見てきているのであえて使わずにおきました.

ただ, 今回の例だとCRUDばかりなので, 明らかに使った方が良いです.
(実戦ではもっと要件が複雑化するでしょうが)

設計

このアプリケーションは8つのプロジェクトで構成されています.

├ADOWrapper
│  ├Interface
│  └SQLite3
├Application
│  ├Component
│  ├Form
│  ├Report
├Domain
│  ├DomainObject
│  └Repository
├Infrastructure
│  ├DDL
│  └RepositoryImpl
├Setup
├TestADOWrapper
├TestDomain
├TestInfrastructure

Testから始まるプロジェクトは各プロジェクトのテストプロジェクトです.

Setupはインストーラ作成のためのプロジェクトです.

各プロジェクトの依存関係は以下の通りです.(Test, Setupプロジェクトを除く)

---------------        --------------- 
| Domain      |        | ADOWrapper  |
---------------        ---------------
   ^        ^            ^
   |        |            |
   |     ------------------
   |     | Infrastructure |
   |     ------------------
   |        ^
   |        |
---------------
| Application |
---------------

ADOWrapperはADO.NETの簡易なラッパーです.

このソフトウェア全体を通して, DBへのアクセスにはこのADOWrapperを用いています.


Infrastructureは永続化のための機能を提供します. これは, DomainプロジェクトのRepositoryインターフェースに対する実装です. RDBMSを差し替える場合にはおそらくInfrastructure全体を差し替える事になります.

(ADOWrapperもInterfaceと実装が分かれているため, 基本的にはRDBMSの差異を吸収することができます. しかし, たいていの業務アプリケーションはRDBMS実装依存SQLを使わざるおえないでしょう. そうなるとSQLを記述するInfrastractureプロジェクトの差し替えが必要です.)


Domainは業務的に意味のある塊をクラスにしたものの集まりです.

入力の妥当性確認や計算(見積なら合計金額や税率計算)などもこのプロジェクトのクラスで行っています.


Applicationは普通のWindows Form Application(いわゆるWinformsアプリ)です.

画面とのデータのやり取りは極力データバインディングを利用しています.

Domainプロジェクトのデータ構造をそのままバインディングしている箇所もあれば, 間にPresentation(Data Transfer Object)というクラスを中継してバインディングしている所もあります.

単純なマスタの場合など, 直接Domainプロジェクトのクラスをバインディングしている箇所が多いですが, 検索して表示する一覧などは後からドメインオブジェクトを跨いだ項目表示を要求されることが多いという経験上, Presenterを挟むようにしています.

      -----------------
      | Event Handler |
      -----------------
        | Control  |
        |          |
-------------   ------------------
| Presenter |---| Domain Object  |
-------------   ------------------
        |          |
        | Data     |
        | Binding  |
        |          |
      ------------------
      | User Interface |
      ------------------

と, ここまでの話はほとんど本やWebサイトの見よう見まねです.

できる人がやればもっときれいになりそうですが, 今の私にはこれが限界です.

とはいえ, 値オブジェクト化できるところもたくさんあるし, Helperみたいなのを作ってコントロールの初期化なんかはまだまだ共通化できそうです.

帳票や集計関連の処理なんかも追加/複雑化したらServiceを用意すれば対応できそうです.

実装

Winform + データバインディングでのプログラミングをほぼ経験していないので, 良い機会になりました.

データバインディングめっちゃ便利じゃん.


他にはコントロールを勉強しなおす機会になりました.

というのも, 恥ずかしながら今まで下記のコントロールを使ったことがなかったからです.

  • BindingSource
  • ErrorProvider
  • ReportViewer(MS Report)
  • HelpProvider
  • MDI Window

あとは, DataGridViewのカスタムはほぼやった事がなかったので勉強になりました.

自作コンポーネントで知って良かったのは以下です.

VB化してありがたく使いました.

  • 背景色を変えるコンポーネント(何故か絶対に要件になる)
  • DataGridViewにソート機能を付けるためのBindingList
  • DataGridViewCellのカスタムコントロール

ソースはComponent以下です.

参考URL

参考URLが多すぎるのですが, 多少整理して貼っておきます.

設計

TERASOLUNA Server Framework for Java (5.x) Development Guideline - アプリケーションのレイヤ化

いきなり.NETじゃない.

NTTデータフレームワークの設計規約みたいです.

なんだかんだ参考になりました.

GUIアーキテクチャパターンの基礎からMVVMパターンへ

ふむー.って感じ.

Microsoft - .NET におけるアプリケーション アーキテクチャ ガイド

このリストの中で唯一読んでない.

というか昨日知った.

もっと早く知りたかった.

実装

とあるコンサルタントのつぶやき - Part 1. 双方向データバインドの基本的な使い方

間違えなく実装面で一番参考になった. Part2も素晴らしい.

とあるコンサルタントのつぶやき - .NETとJavaの例外処理の違い

趣旨とは違うけど, Javaの勉強になった.

コントロール

Microsoft Developer Network - Windows フォーム コントロールの機能別一覧

あまりに無知なので読んだ.

Bug Catharsis - 常識的に考えてErrorProviderを使いたいよね

ごめんなさい.ごめんなさい.

be free - フォーカスがあるテキストボックスの背景色を変えるコンポーネント

ありがとうございました.

DataGridView

.net snippets - C# - SortableBindingList

これをVB移植して利用.

こいつがないとDataGridViewにバインディングしてもソートできない.

+++ 上野メモ帳 +++ 0 DataGridViewのDataSourceに独自クラスのListを指定する場合

DataGridViewに具体的にバインディングする.

方法上記と合わせて.

方法 : Windows フォーム DataGridView Cells でコントロールをホストする

これさえ読めばカスタムセルが作れる.

(コピペできる)

MS Report

インストール

Microsoft Developer Network - VS2015でレポート(ReportViewer)を使用したい

変更から入れるってマジでわからないっす.

Microsoft Rdlc Report Designer for Visual Studio

これ入れる必要あったのかよくわかってない.

SSDT for Visual Studio 2017

これも入れる必要あったのかよくわかってない.

Stack overflow - Reportviewer tool missing in visual studio 2017 RC

最終的にここの2番目の回答のモジュールに参照を全て通したら動いた.

あーリビルドはしたかも.

使い方

Microsoft レポートによる帳票の作成

素晴らしい教材.

導入以外は基本これで済んだ.

あとはサブレポートぐらいだけど, サブレポートはフィーリングでいける.

ReportViewerにおけるサブレポートの使い方について

そもそもサブレポートというものをこれで知った.

SQLite3

職人気質を目指すプログラマの日記 - System.Data.SQLite の GetDateTime でエラー

恐ろしくハマったので.

インストーラ

ドラブロ - Visual Studio 2017 でインストーラを作成する

すごい親切.

Web備忘録 - Visual Studio 2017 Installer Projects でインストーラーを作成する

こちらも中々親切.

疑似個人情報データ生成サービス

デモデータ作るのに使わせてもらった.

プロ生 - マイクロソフトが提供しているアイコンセットまとめ

大抵のアイコンはこれでいい気がする.

参考書籍

どれも敷居が高くて半分もわかっていない気がする.

あと, DDDとアーキテクチャの話は分けられないんだろうけど, こんな抽象的になるものなんですかね...

言いたいことはわからんでもない(だがわからん), っていうのがずっと続く感じで....


設計関連

.NETのエンタープライズアプリケーションアーキテクチャ第2版 .NETを例にしたアプリケーション設計原則

たぶん一番参考にした.

この中では読みやすい方だと思う.

実践ドメイン駆動設計

これもまだ読みやすい方だと思う.

エンタープライズアプリケーションアーキテクチャパターン

よ, 読みましたよ?

エリック・エヴァンスのドメイン駆動設計

流し読みです, ええ.

抽象的すぎて辛い.

業務知識系

本筋とは関係ないですが.

(この本ってDB設計の本じゃなくて業務知識の本ですよね....)