くまくまの業務日誌

Markdown記法で徒然に書いてみましょう。

PowerShellでパフォーマンスモニターのデータを取得する。

PowerShellでパフォーマンスモニターのデータを取得してみました。

会社の作業で、パフォーマンスモニターの出力結果を色々と取る作業(実は私は見てるだけ)を行っていたのですが、オペレータの人が「急いで実行、急いで実行」と何やら念仏を唱えながらやっていたので、「それって一括で開始、終了できないんですかね?」と聞いてみました。その人曰く、「それができないのよぉ。」との事。確かにパフォーマンスモニターのGUIでは、データコレクターを複数設定した場合に、それぞれを一括でスタートさせる仕組みにはなっていません。それなら1つにまとめればいいのですが、CPU、MEM、DISK、NET、GPUと大項目別にデータコレクターを設定していたので、きっとジャンル別に分けたかったのでしょう。

自分でやると気が付かない「面倒くさい」

自分が作業を行うときは、例え100回のコピペ作業でも黙々とやってしまいますが、他人がそれを行っているのを見ると非常に「非効率だな」と感じてしまうものです。ということで、PowerShellでのスクリプトを作ってしまおうと思いましたので、サンプル含めご覧ください。

Get-Counter、Import-Counter、Export-CounterでOKです。

意外とあっさり、Get-Counterでパフォーマンスモニターの結果は取得できます。 ただ、問題が2つほど。

  1. Ctrl+Cで止める事になるが、それ以降はスクリプトが動かない。
  2. 取りたいカウンター情報を少しでも間違えると動かない。

Ctrl+Cで止める前提でどのように構成するか?

カウンターの取得スクリプトと、カウンターデータの抽出スクリプトを分けます。カウンターの取得スクリプトは途中でCtrl+Cで強制終了なのですが、ファイル出力までは、上手くいきます。そこまでうまくいけば、抽出スクリプトは楽です。

正しいカウンター情報を得るには?

パラメータ"ListSet"は、パフォーマンスモニターのカウンター情報を列挙してくれます。この列挙情報は普通にFormat-Listで出力させてもデータの多い部分は「...」ではしょられてしまいます。ま、PowerShellですから、まじめに出力するように手を加えて上げればきれいに出力できます。ただ、データは多いです。普通にテキストを眺めていてもなんだかなぁ、と思いましたので、今回は手動でHTML&CSSによる、きれいな出力をするようにしました。

サンプル:カウンター情報を列挙する

#
# カウンターリストを出力します。
#

$output = "<!DOCTYPE html>`n"
$output += "<html lang=`"ja`">`n"
$output += "<head><meta charset=`"UTF-8`">`n"
$output += "<title>Windows Performance Monitor Counter List</title>`n"
$output += "<link rel=`"stylesheet`" href=`"StyleSheet1.css`">`n"
$output += "</head>`n"
$output += "<body>`n"
$output += "<h1>Windows Performance Monitor Counter List</h1>`n"

$list = Get-Counter -ListSet *

$listCount = 1
foreach ($item in $list) {
    $output += ("<h2> No.{0} {1}</h2>`n" -F $listCount, $item.CounterSetName)
    $listCount += 1

    $output += "<table border=`"1`">"

    $output += "<tr>"
    $output += "<th>CounterSetType</th>"
    $output += ("<td>" + $item.CounterSetType + "</td>")
    $output += "</tr>`n"

    $output += "<tr>"
    $output += "<th>Description</th>"
    $output += ("<td>" + $item.Description + "</td>")
    $output += "</tr>`n"

    $row = 1
    foreach ($item3 in $item.Counter) {
        $output += "<tr>"
        $output += ("<th>Counter{0}</th>" -F $row)
        $output += ("<td>{0}</td>" -F $item3)
        $output += "</tr>`n"
        $row += 1
    }
    
    $output += "</table>`n"
}

$output += "</body></html>"

$output | Out-File -FilePath "PerformanceCounters.html" -Encoding utf8 -Force
/*
 thanks https://webliker.info/75964/
 */

h1 {
  color: #364e96;/*文字色*/
  border: solid 3px #364e96;/*線色*/
  padding: 0.5em;/*文字周りの余白*/
  border-radius: 0.5em;/*角丸*/
}

h2 {
  padding: 0.4em 0.5em;/*文字の上下 左右の余白*/
  color: #494949;/*文字色*/
  background: #f4f4f4;/*背景色*/
  border-left: solid 5px #7db4e6;/*左線*/
  border-bottom: solid 3px #d7d7d7;/*下線*/
}

table{
  width: 100%;
  border-collapse: collapse;
}

table tr{
  border-bottom: solid 2px white;
  font-size: 12px;
}

table tr:last-child{
  border-bottom: none;
}

table th{
  position: relative;
  text-align: left;
  width: 15%;
  background-color: #52c2d0;
  color: white;
  padding: 10px 0;
}

CSSは、もらい物です。

f:id:kumakuma0421:20201206004532p:plain
パフォーマンスモニターのカウンター情報

なかなかきれいに出力できてます。

サンプル:カウンター情報を取得する。

#
# パフォーマンスログを取得する
#

#Get-Counter -ListSet * | Format-List > ListSet.txt

# Windowsサーバリソースのデータ収集項目と判断基準の一例
# https://www.ashisuto.co.jp/product/category/quality/loadrunner/technical/list/1195227_3454.html
#
# CPU    \Processor(_Total)\% Processor Time     ※80%~90%以内
# CPU    \System\Processor Queue Length          ※CPUあたり2未満
# MEMORY \Memory\Available Mbytes                ※5MB以上
# MEMORY \Memory\Pages /sec                      ※20以内
# MEMORY \Process(_Total)\Working Set            ※参考値として取得
# Disk   \PhysicalDisk(*)\Avg. Disk Queue Length ※ディスク毎に2未満

# $counters = @(
#     "\Processor(_Total)\% Processor Time",
#     "\System\Processor Queue Length",
#     "\Memory\Available Mbytes",
#     "\Memory\Pages/sec",
#     "\Process(_Total)\Working Set",
#     "\PhysicalDisk(*)\Avg. Disk Queue Length"
# )

# 出力対象を決定します。
$counters = @(
    "\Processor(_Total)\% Processor Time",
    "\Processor(_Total)\% User Time",
    "\Processor(_Total)\% Privileged Time",
    "\System\Processor Queue Length",

    "\Memory\Available MBytes",
    "\Memory\Pages/sec",

    "\PhysicalDisk(*)\% Disk Read Time",
    "\PhysicalDisk(*)\Disk Read Bytes/sec",
    "\PhysicalDisk(*)\Avg. Disk Bytes/Read",
    "\PhysicalDisk(*)\Avg. Disk Read Queue Length",
    "\PhysicalDisk(*)\% Disk Write Time",
    "\PhysicalDisk(*)\Disk Write Bytes/sec",
    "\PhysicalDisk(*)\Avg. Disk Bytes/Write",
    "\PhysicalDisk(*)\Avg. Disk Write Queue Length",
    "\PhysicalDisk(*)\Current Disk Queue Length",

    "\Network Interface(*)\Bytes Received/sec",
    "\Network Interface(*)\Bytes Sent/sec",
    "\Network Interface(*)\Output Queue Length"
)

# ファイル名を作成します。
$now = Get-Date -Format "yyyyMMdd_hhmmss"
$output = ".\PerfLog_{0}.blg" -F $now

# パフォーマンスモニタの出力値を取得します。Ctrl+Cで終了します。
Get-Counter -Counter $counters -SampleInterval 1 -Continuous |
    export-counter -Force -Path $output

サンプル:カウンターログからデータを抽出する。

#
# パフォーマンスログをCSVに展開する
#

$files = Get-ChildItem -Path ".\" -Filter "*.blg"

foreach ($item in $files) {
    Write-Host $item.Name -ForegroundColor Yellow
    Import-Counter -Path $item.Name |
    Export-counter -FileFormat "CSV" -Path ($item.BaseName + ".csv") -Force
}

最大の問題:どのカウンター値を取得して、どの閾値で問題を切り分けるか?

大きなカテゴリとしては、以下の4つになると思います。

  • CPU
  • MEMORY
  • DISK
  • NETWORK

CPU

決して、CPU使用率:100%は問題ではないのです。むしろハードウェアをぎりぎりまで使い切ったら優秀です。しかし、コア数の少ないシステムにおいて1つのプログラムが100%近くCPUを消費し続けると、GUIの応答性が下がったり、発熱による暴走に至ったりと良いことはありません。効率よく使うか、安定を求めるか。悩むところではあります。

また、CPUがアップアップなのかを測るカウンター値として「\System\Processor Queue Length」があります。昔から「2以上」が閾値なのですが、今使っている化け物PC(XEON 44コア?)ですと、暇なコアが多くてQueueが上がることはまずないです。こんな化け物で仕事するとは思いもしませんでしたが、パフォーマンス測定も難しくさせます。

MEMORY

メモリが潤沢にあるなら、わざわざハードディスクの仮想メモリに送り込んだり、取り戻したりする必要はないはずです。仮想メモリとのやり取りが多いならメモリ不足が考えられます。とは言っても、128GBのメインメモリならまず、起きないことです。CPU/MEMORYは性能直結ファクターなので見極める必要があるのですが、新しいハードウェアにマッチした判断基準がまだないような気がしています。

DISK

今ではSSDの登場により、「くっそ遅い」事はなくなりましたが、それでも効率よくI/Oしているのかは測りたいところです。HDDの場合はセクタ、クラスタ単位のI/Oを意識していましたが、SSDの登場によりHDD的見方では行けない気がします。

NETWORK

9600bpsから始まった私のネットワーク人生も今や25Gbps。1Gbpsのハブでは足りなくて、ハブを求めて右往左往することもしばしば。

そもそもでありますが、1GbpsのLANで1Gbpsフルフル使えるとは思っていません。一体どこにTCP/IPの限界があるのでしょう。

ということで、すみません。全く持ってまとまった情報を持ち得ていないことが判明しました。次回までに情報収集と実測を行いたいと思います。

OpenCV sample を、Visual Studio community 2019でビルド

本日、もう一つの作業も行いました。

OpenCVは仕事で使っているのですが、使っているのは本当に、imshow()だけ、という「それは使っているうちに入らないのでは?」という状況でしたので、これから本気出して、まじめにサンプルを解析していこうと思い、まずは環境を整えることにしました。

まずはGitHubのここからサンプルを取得しました。samples/cppフォルダから始めようと思います。ただ、私の手になじんでいるのは、Visual Studioなので、まずはソリューションとプロジェクトを作らねばなりません。そして、このcppフォルダにあるサンプルソースは、1つのファイルで完結するように作られており、それぞれにmain()が存在します。つまり、作るプロジェクトは・・・軽く50以上。

50個以上のプロジェクトを作成し、環境を整えてファイルを設定していく作業を想像すると萎えます。なんとか自動でできないだろうかと考えましたが、そもそもプロジェクトファイルである、vcxprojファイルを2つ作って比較すると、違うのはソースファイル名とGUIDだけです。流石にGUIDを手で作るのは気が引ける作業ですので、ここはせっかく勉強したPowerShellを使って、プロジェクトファイルの自動生成を行うようにしました。

ファイルはここにあります。

ちなみにですが、cppフォルダにはOpenCVだけではコンパイルできないサンプルが、4つあります。これらはライブラリを追加しなければならないので、学習としては次の段階の時にやろうと思います。

それと、OpenCVWindows版DLLはGitHubの格納限界の100MBを優に超えてしまいます。GitのLFSを使用することで回避できると多くの方がWebで説明してくれていますが、私にはこの限界を突破する事ができませんでした。ここで、意気消沈。しかし、ふと思い出したのが、「NuGetで取ってくる仕組みにしてしまえば、ライブラリを格納する必要がない」という回避策。最新版のOpenCVではないですが、これで作業続行する事にします。

そして、今回妥協したのが、DLLなどの外部ライブラリは通常、「ビルド後の作業」でCOPYコマンドでターゲットにコピーする仕組みを入れるのですが、ソースが小さいのでコンパイル時間が短いため、ことごとく、作業が重複してエラーになってしまいます。今回はこういう点で時間を食うのもだんだん疲れてきたので、x64フォルダの配下にDLLとPDBを直接配置する事にしました。

と、文章を書いて矛盾に気が付きました。(^^;)
100MB超えてるPDBファイルがGitHubに格納されている・・・。 夕方には全然矛盾に気が付きませんでしたが、こうやって反省ノートを書いていると、気が付くこともあります。後でなぜうまくいっているのか?について検証します。

後は、ビルド時に出るエラーで「その関数は古い」とコンパイラに怒られるコードに対して、抑制する定義「_CRT_SECURE_NO_WARNINGS」を追加して、ターゲットすべてがコンパイルできることを確認しました。後は実行できるかでしょうか。

そして、本日の反省は、「また、masterブランチから作業してしまった」です。ブランチ切ってそっちで作業を行って、ある程度落ち着いたらmasterにマージするようにしないと、masterのログがぐちゃぐちゃになります。てか、もうなりました。近日中にmasterを再作成する予定です。

さて、今回の作業のGitHub保管リポジトリは以下となります。既に50個以上のプロジェクトが実装されている状態ですが、私同様、Visual Studioは準備できるけど、なんか手っ取り早く動作確認できるものない?をご要望でしたら、以下を検討してみて頂ければ幸いであります。

github.com

Doxygenについて

Doxygenについては、以下の検索をたどってみてください。

本当にこのような高度なレベルのドキュメント生成機能を"GNU General Public Licence"で使わせて頂いていいのかと平身低頭になる強力な解析支援ツールであります。

既に多くの方が使い方、Tipsなどをアップされているので、今さら私がなにかをお伝えするよりも、検索した情報の方が有用ではないでしょうか。

ちなみにですが、Doxygenにお世話になる場合というのが、以下のシチュエーションが多いのが私の実情であります。

  • 基本設計書、機能設計書までは、利用者と設計者の意思疎通、つまり「こうして欲しい」とか「こういう仕組みで動かすのです」という内容をお互いにレビューして鍛え上げていくのに対して、詳細設計書など、プログラムの構造を主に説明する資料に関しては「作っといて」とか「欲しいです」など、成果物の一つであるがために要求され、こちらも時間をかけずに体裁の整った資料を作成するために、Doxygenを利用する。
  • パラシュート部隊よろしく、炎上現場に放り込まれるも、資料も管理者もしっちゃかめっちゃかで、なにも情報がないままソースコードだけがあるので、Doxygenでまずは全体像をつかんで、内容を把握する。

このような「納品用」のドキュメント作成ツールは他にも・・・

などを使わせて頂きました。どれも本当に助けて頂きました。しかし、正直なところですが、関数レベルの設計書のニーズに関して、納品物としてではなく、問題発生時の解決の糸口として活用していきたいのが本音ではあります。設計書を見て、「ここがまずかったですよね。」と指摘してくださった方は皆技術と管理に長けたすごい人たちばかりでしたので。

さて、話はDoxygenに戻りますが、Doxygenの出力する内容は関数の構造だけでなく、例えばクラスに関しては、その継承関係図も出力してくれます。ちなみに、下の図は私の作成中のライブラリの継承関連図です。曲線の矢印が美しい図面であります。

f:id:kumakuma0421:20201115232631p:plain
alt::WindowsLibraryの継承関係図

あと、「呼出し関連図」と「被呼出し関連図」も出力する事ができます。

f:id:kumakuma0421:20201115233308p:plain
呼び出し関連図

f:id:kumakuma0421:20201115233334p:plain
被呼び出し関連図

これらの関連図が活躍するのは、「ここをいじった時にどこが影響する(=再試験の対象になる)のかを見積もる(または、別の方法を考える)場合に有効です。さすがに、「やるぞ」と決めた時は、関連するキーワードでGREPする結果の方が正しいとは思いますが。

で、本日は自分が作成中であるライブラリに対して久しぶりにDoxygenの出力結果を確認してみようと思って、色々設定をいじりながら「これが私のベストかな」と思う設定にたどり着きました。いつも、思い付きで設定ファイルをいじってたまに新しい発見をしたりしますので、あまり固着しない方がいいのかなとも思いますが、最初のスタートラインにするファイルでいつもそう設定している、というファイルがあるのはスタートダッシュも早いですので。

ちなみに今回の(既に皆さんは知っている)発見は・・・

  • ソースがSJISだったので、いつもツールでUTF-8に変換していたのですが、DoxygenはSHIFT-JISと伝えてもうまく変換できません。実は"CP932"だったのです。今日は本気で「面倒くさいなぁ」と思ったので、ここにたどり着きましたが、いつもお客様の「面倒くさいなぁ」を解決する側(私が面倒くさい作業を行うと、お客さまが楽になる)でしたので、面倒くさいに耐性ができてしまって、困ったものです。
  • GitHubにはGitHub Pagesなるものがあり、静的なHTMLならWebホスティングできるそうです。これって、Doxygenの出力結果格納にピッタリではありませんか?で、置きました。しかし、一部のファイルがうまく表示されません。「そのうち表示されるようになるだろう」と高を括っておりましたが、一向に表示される気配はなく、これまた本気で「なんで?」を探してみたところ、GitHub Pagesはアンダースコアで始まるファイルは対象外、というオチでした。対処方法も、「.nojekyll」ファイルをルートに置くだけで良いらしく、指示通りにファイルを配置したら、きれいに見れるようになりました。

本日は、Doxygenでいろいろ格闘した訳でありますが、Doxygenは、まだ奥が深い技術を持っていそうで、修行不足を痛感するこの頃であります。本日使った図表、Doxygen設定ファイルなどは、ここに格納しておりますので、もしよかったらご覧になってみてください。

オブジェクト指向プログラミングの再考

最近ふと、「オブジェクト指向プログラミング」を正しく人に説明できるだろうか、と疑問が湧いてきたのでここらで脳内整理してみようと思った訳であります。

検索結果からみる、「オブジェクト指向

オブジェクト指向」を検索してみる。

by Bing 「オブジェクト指向とは
by Googleオブジェクト指向とは

以下のキーワードが列挙されています。

オブジェクト指向の「オブジェクト」とは

世の中「オブジェ」の方が浸透性が高いこの「オブジェクト」という言葉は、本当に「物」に過ぎないと思います。そして、この「オブジェクト」と対になる考え方が「型」になると思います。

型を作れば、その型からオブジェクトをいくらでも作る事ができる。でも、そんなに型を作ってまでいっぱいオブジェクトを作る必要もないと思われるかもしれません。

例えばログファイルを解析するプログラムを作ろうとしたとき、解析ロジックさえきっちり作れば、ファイル操作部は関数だのグローバル変数だので構成して早々に作り上げてもよいとは思います。しかし、初期の段階で将来を見越した設計をしておくことは、この先思いもよらぬヒット商品を生み出すことになるかもしれません。

そのためにも、オブジェクトを自分だけではなく、賛同する誰かが使ってくれるかもしれないという思いで設計しておくことは、大切な事ではないかと思います。

「型」に求められるもの

プログラムがおかしなことになるのは、ロジックがおかしいために起きることに加え、以下のファクタも加わってきます。

  • 意図しない値を設定された。
  • 意図しない機能の使われ方をした。

1つ目の「意図しない値を設定された」に関しては、値の設定値を検証すればいい訳ですが、そもそも値が丸見えになっているのでは、どんだけ頑張っても裏技的に使われたりして「意図しない機能の使われ方」に繋がってしまいます。だから、設計者の意図するアクセス権限(直接見れる、見れない)を設定できなくてはなりません。これが、オブジェクト指向の1つ目のキーワード「カプセル化」になります。

カプセル化

直接操作して欲しくない変数や、関数は「カプセル化」で操作できないようにします。

class Sample
{
public:
    // 外部から操作可能です。
protected:
    // このクラスと継承先だけが操作可能です。
private:
    // このクラス内でのみ操作可能です。
};

外部からアクセス可能・不可で分けるなら、以下の通りです。

publicprotectedprivate
アクセス可能
アクセス不可

さて、protectedとprivateはどう使い分けましょうか。経験則からですと、privateに設定した変数は、継承が発生したり、深くなってきますと、どうしても不便となって、protectedに変えることが多かったです。わざわざprivate変数のためにprotectedな関数を作ってアクセスするのもなんですからね。

継承(派生)

機能を受け継ぎ、さらに発展させるという解釈で「継承」を考えるとちょっと違うかもしれません。ちなみにですが、私は最初にC++を勉強していた時、この「継承」というものは、Version1、Version2というような進化をさせるためにあるものと勘違いしていました。

実際は、機能のグルーピングという観点で見た方がよいと思います。以下はそのグルーピングの例となります。

  • ファイルの読み書きを行うクラスを作りたい。
  • ファイルが読み書きできるなら、CSVや固定長ファイルも扱いたい。
  • ファイルを操作するようにメモリを操作できると早いかも。
  • ファイルを操作するように外部との通信ができると便利かも。

実は、WindowsはCreateFileでファイルだけでなく外部との通信を可能にする「名前付きパイプ」を操作する事ができます。また、「共有メモリ」という機能を使えば、Read/Writeでメモリを操作することができます。流石にCSV、固定長ファイルに関しては自力で「機能」として考えなくてはなりませんが。

すべての機能をRead()/Write()で実現したいので、親クラスにはこの関数を装備します。Windowsは基本的にHANDLEという変数を使ってファイル、名前付きパイプ、共有メモリの操作が行えます。HANDLE変数も親クラスに実装しましょう。

CSVや固定長ファイルの機能に関しては、親のファイル操作機能を「継承」して実装すると、同じコードを書かなくて済みそうです。共有メモリに関しては追加の作業が必要になりますので、これも継承先のクラスで実装しましょう。

上記はあくまで一例ではあります。継承という考え方は確かに「機能を受け継いで」いる訳ですが、継承設計を行うために考えることは、機能全体の配置方法についてとなります。つまり、登場するファクタが多ければ多いほど、設計に柔軟性が必要となりますが、結果的にはバランスの良い構造が完成します。

どうせなら、小舟を作るより大型船を作る方が船の構造やバランスのとり方が理解しやすい訳であります。

多態性、多様性(ポリモーフィズム

昨今のカタカナ氾濫文化になっても、なじまない言葉ではあります。久しぶりに「オブジェクト指向」を振り返ってみようと思ったのもふと、この言葉を思い出したからであります。

取り敢えず、サンプルです。

class Car
{
public:
    virtual void Drive();
};

class TOYOTA_2000_GT : public Car
{
public:
    virtual void Drive();
};

class NISSANN_GTR : public Car
{
public:
    virtual void Drive();
};

Car* myCar = new TOYOTA_2000_GT();
Car* yourCar = new NISSAN_GTR();

myCar->Drive();
yourCar->Drive();

多様性の重要なポイントは、

  • 型から生成したオブジェクトは、なにもその型で受ける必要はない。
  • 親の型で子のオブジェクトを受けて、親の型から関数を呼び出しても、子のオブジェクトの関数が呼び出される。

というところにあります。上記のサンプルで言えば、TOYOTA_2000_GTクラスから生成したオブジェクトは、その親であるCarクラスのmyCarで受けている部分になります。またmyCar->Drive()は、Carクラスの変数からアクセスしていますが、実際はTOYOTA_2000_GTクラスのDrive()が呼び出されます。

つまり、Carクラスから派生したオブジェクトは、Carクラスの変数から呼び出すことで、「TOYOTA2000GTを運転する」のではなく、「(なんか知らんけど)車を運転する」という構文で、TOYOTAのかつてのスーパーカーを運転できるのです。GT-Rに関しても同じですね。「車を運転する」のですが、世界の最高峰の一つ、GT-Rを操作できるわけです。

さて、サンプルは「車」でしたので、どの車も運転して目的地に着くまでの操作は(MT,ATの違いはありますが)それほど変わりません。つまり、Carクラスから派生した2つのクラスはそれほど違いはないでしょう。

では、荷台の操作が可能なダンプトラックがCarクラスから継承された場合、後ろの荷台の操作はCarクラスからどうやって操作するのでしょうか。

class Dump : public Car
{
public:
    void Drive();
    void Dump(bool direction);
};

それは無理です。Carクラスは継承先のDumpクラスのDump()関数を知りません。よって呼び出すことができないのです。困りましたね。

  • TOYOTA 2000 GT で買い物に出かける。
  • NISSAN GT-R でドライブに出かける。
  • ダンプで土砂を捨てる。

全く違う事を行うのに、それをCarクラスでやるためにはどうすればよいでしょう。そのためには、親クラスとなるCarが知り得る事、つまり「なにかする」を用意することで実現できます。

もう少し先程のクラスを見直してみましょう。

class Car
{
public:
    virtual void Drive();
    virtual void DoAction();
};

class TOYOTA_2000_GT : public Car
{
public:
    virtual void Drive();
    virtual void DoAction();
};

class NISSANN_GTR : public Car
{
public:
    virtual void Drive();
    virtual void DoAction();
};

class Dump : public Car
{
public:
    virtual void Drive();
    virtual void DoAction();
private:
    void Dump(direction);
};

Car* myCar = new TOYOTA_2000_GT();
Car* yourCar = new NISSAN_GTR();
Car* workCar = new Dump();

myCar->Drive();
myCar->DoAction();

yourCar->Drive();
yourCar->DoAction();

workCar->Drive();
workCar->DoAction();

yourCar->DoAction()は、ドライブするだけなので、何もしないでしょうね。それでもいいんです。こう作れば、継承先がどんな特殊機能を持っていてもCarクラスでDoAction()すれば、実現できます。

今時点では、myCar, yourCar, workCarと3つの変数で動作を行っていますが、3つのオブジェクトを配列に入れて、for文でループさせれば、このコードはもっとコンパクトになります。ポリモーフィズムの最大効果です。「車を運転する」という抽象的な作業に対して、それぞれのオブジェクトがそれぞれの役目をキッチリ果たします。

もちろん、この方法以外にも「取り敢えず、現地まで私が運転するけど、荷台の操作はわからんので、誰かにやってもらう。」という考え方もありだと思います。その場合は、「もし、来たのがダンプなら」というif文が必要になるので、ロジックが複雑になります。そして、分岐点はテストの対象でもありますので、テスト工数がかかります。9台が車で、1台だけ特殊車両の構成なら、全体のバランスとしては、その1台のために分岐するのも悪いとは思えません。

いかがでしょうか。もう少しコードサンプルを提示できれば、もっとしっくりくるのかもしれませんが、時々このページは更新してわかりやすくしていきたいと思います。

Git-Flowの考察

会社でGit-Flowやります。

ということで、色々調べてみました。

今までSVNで管理していましたが、trunk一本でしたし、branchもよほどの事がない限り使っていません。そんなチームに天から「GitLabを使え」との指示が急に振ってきました。先鋒として調査と結果報告を行いましたので、これはその時に検討した資料を再構成(つまり外部用)したものです。その時はExcel方眼紙で作ってみましたが、このイメージはdiagrams.netを使用しました。

しかし、これはいい。今まで強力な図形ならVisioが必要と思っていましたが、これならVisioがなくても十分やっていけます。現在はGoogle Driveの追加アプリケーションとしてGoogle Driveから作っています。Google Driveには標準の「Google 図形描画」もありますが、そちらは残念な仕上がりです。

正直、Excelもなかなか詳しい図形を書けますが、曲線が美しく書けないですね。あと、アンカーポイントが固定的なので苦労します。見えないオブジェクトに線を連結してアンカーを増やして図形を整えるのは数が増えるとなかなか面倒になります。


さて、本題です。SVNと違って際限なくブランチを切って運用してしまいそうなGitではありますが、世の中にはリポジトリベースサイトの名を冠した、ブランチ運用フローが現時点で3つあるようです。それらの名称は以下の通りです。

  • Git-Flow
  • GitLab-Flow
  • GitHub-Flow

GitLab-Flow

イメージはググってください。諸先輩方が色々調べて公開してくれています。運用方法はとてもしっくりきます。「水は高い所から、低い所へ流れる」を具現化したモデルのようです。開発者は常にマスターに機能を追加して、日々これらの安定稼働と問題対応を行います。masterを更新するので、一時的にバグによる汚染も発生するでしょう。テストの自動化や、しっかりしたリグレッションテスト計画など、できる限りのmaster保全計画をキッチリ進めておけば、下流に発生する支流には、その支流に必要な機能を取り込んで、「取り込んだ機能の組み合わせで問題ない」ことを確認するだけのように感じます。この時点で問題が発生しても、対応者は「master」に更新を行って支流に「バグ対応」を流し込んでいく運用イメージになっているようです。

この支流のイメージは、顧客単位のカスタマイズ対応とか、「今回はこれらの機能を実装して出荷していく」という明確な出荷計画がある場合には良いと思われます。

GitHub-Flow

先程の「水は高い所から、低い所へ流れる」の見方を逆にした感じなのが、この「GitHub-Flow」のイメージだと思います。バグ対応も、機能追加も常に「master」に終着する事を前提として活動していきます。こちらもGitLab-Flowと同様、「master」に到着する頃には問題をクリアした「良いコード」であることが求められます。そのための方策は前述のGitLab-Flowと同じだと思いますが、最初に「master」に流し込む緊張感に比べたら、鍛え上げてから「master」に登録する形は、よりナチュラルな感じがします。

Git-Flow

Git-Flowのイメージは、以下の通りです。この図では、Git-Flowに登場するHotFix系のラインがありませんが、すみません、書きそびれました。しかし、コミットの流れをシンプル、かつ明確に理解するにはちょっと端っこに寄っておいてもらいましょう。

前述の3つの運用フローのうち、このGit-Flowが一番複雑かもしれません。見ての通り、ブランチとブランチを移動する機能やBug Fixが縦横無尽な感じがします。それに「master」は完全に暇しているようです。そして、事を複雑にしているのが結合テストの実施中に発生した問題対処の「release sp1」と、通常の開発を行うSprint2での「develop」での作業が重複しているところです。

つまり、バグを退治しながら開発を行う事を想定しているのです。この方法を採用する事にした理由の一つはこの、ブランチを切り替えながら両方の作業に対応できる(ということを、図面から明確に説明できる)からです。二人で担当分けすれば、「機能#4」の部分の間延びしたところは解消されますけどね(^^;)

そして、開発チームとテストチームが明確に分かれて作業しているところもこれを採用した理由になります。テストチームは「release」ブランチに着目して作業を行います。バグでテストが止まったら、開発チームからのバグ対応の連絡をこのブランチで待つのです。開発チームはテストチームからのバグ情報を「release」ブランチから対処を行い、事を収めるべく齷齪(あくせく)しながら、自身の開発作業も行うのです。

私たちの現場では、今までもこの状況が続いていますので、SVN→Gitに切り替える際はこの運用フローがいいのでは、ということで採用された次第です。

私としては、待望の「世の中Gitでしょ」に近づけるため、運用フローに関してはどれでも良かったのです。でも、リーダーさんが「どの運用フローにしたらいいのだろう」と悩まれて私に「提案」を依頼されてきたので、色々検討してみました。最初はまったくちんぷんかんぷんでしたし、ネットの情報のどれを見てもなかなかイメージがわかなかったので、「なぜだろう」と思いながら図面を”写経”してイメージを固めていきました。そして図面に足りなかったのは「なにがどこに流れて行っているのか」を明確にすることだな、と感じてこの図面を作ってみた次第です。

さて、世の中の情報が正しいとは限らないことは、この私の図面にも適用されます。この図面のレビュー時に「pull」でなくて「clone」ですよね、とか「stash」ではないですよ、とか指摘を頂きました。まだ、なにか問題が含まれているかもしれません。バグを見つけたらなんなりと御指摘ください。よろしくお願い致します。

f:id:kumakuma0421:20201011231017p:plain
Git-Flowイメージ図

非機能要求グレード の勉強会が会社でありました。

実は私、自分の会社にはほとんど顔を出していません。 ほとんどをお客さまのビルの、とあるフロア(外注専用)で過ごしております。 会社のメールもほとんど月末しか見ないので、こういった会社の有志が行う、セミナーには参加しそびれているのが現状でした。

しかし、コロナの影響でリモート環境が急に整い、自社セミナーにも気軽に参加できるようになったのは不幸中の幸いとでも申しましょうか。前回は会社が準備してくれた環境で参加したのですが、今回はBYODで参加です。Android5.0.2とかですがなんとかなるだろうと高を括っての参加です。

ちなみにですが、Androidは発熱すると、USB(ヘッドセット)を切断しに掛かります。また1.5時間のセミナーですと、電池も急速に減ります。「電池を取るか、ヘッドセットを取るか」な状況がセミナー最後のまとめの段階で訪れて往生しました。やはり、最新型が欲しい所です。

お題は「非機能要求グレード解説 勉強会」でした。開催を知ってから「こりゃ事前勉強しておかないとまずいな。」と思いましたので、時間が許す限り( ..)φメモメモ

Bingで検索「非機能要求グレード」

Googleで検索「非機能要求グレード」

なかには刺激的なタイトル「非機能要求グレードを使ってはいけない」なんてのも見つかり、混沌としてそうです。

で、事前情報はIPAから資料を入手、査読となるわけですが、どうしても上記の「使ってはいけない」の内容が気になります。そりゃそうですよね。IPAの資料に対して喧嘩売っているのも同然ですから、でも読んでみますと、確かにそう思えてきます。

そして、セミナー後に理解したことは以下のように自分としてまとめました。

  • 非機能要求グレードは備忘録的に使う。
    機能以外の部分に関して、検討を忘れてはいけない要件が列挙されている。すべてを当てはめる必要もないし、そこはお金とお客さまと相談しないといけない。
  • 非機能要求グレードは非機能要求に対する回答集ではない。
    なので、その解はお客さまと詰めていく必要がある。お客さまと合意ができたら設計書、仕様書に展開して計画的に作業を進める。

非機能要求グレードの資料には、「こういった要求に対して、どのレベルを考えていますか。」は体系的に記述されていますが、その要求の解は千差万別ですからね。お金を出すか、知恵を出すか、あきらめるか、代替案を模索するか。

セミナー講師も申しておりましたが、「マニュアル作成の件が抜けとった!」とか、「お客さまが急に○○○を言い出した!」とか、機能に関係ない所では往々にして暗黙の了解だったものが、後に認識のずれとして問題化することがあります。理論武装的な考えでなく、お客さまとWin-Winな関係を維持するためにも、この「非機能要求グレード」の資料は熟知の必要を感じる次第なのであります。

さて、どこまで私は「非機能要求グレード」の項目に対する回答を持っているでしょうか。

Notion 使ってみました。なかなかいいです。

Evernoteは、Webクリッパーがとても秀逸で、重宝していますが、ヘビーユーザーになると、容量の問題(60MB、ノートの上限は25MB)に割とぶつかるため、ここぞというときのWebクリップ機能に限定して使うようになってきました。

対抗するアプリとしては、OneNoteがありますが、こちらのWebクリップ機能はかなりプアです。これでクリップしても情報の再利用はできません。こちらは、会社では日報や業務メモなど、文字を一から書く場合に使用しています。テーブルをTABキーで作れたり、インデントや見出しがショートカットでぱっと作れるところは秀逸です。

この2大メモソフトがあれば、もう生産活動には十分なんですが、ここ最近の生産活動でふと思うところがありました。

最近、マークダウンで書くことが多いんでは?

GitLabが会社の新リポジトリとして使われるようになり、このブログでも記事を書く際はMarkdown一択で書いています。確かに書式と文字を同時に書けるこのスタイルは今後の文章作成に必須となる事は間違いないと思います。

さて、そんなMarkdown生活に新しいものを取り入れてみました。

Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

全て英語です。微塵も日本語ありません。Language設定に期待しましたが、なんとハングルはある...。どうしたものか。

しかし、なんとなくで使えます。UIから直感で使っていけます。"/"スラッシュで機能がポップアップするのは、とても便利です。取り敢えず、Evernoteから情報を引越させてみようと、手打ちとスラッシュで情報の引越(とリフレッシュ)をやっていましたが、Web bookmark は、最近のトレンドですね。Twitterのようにコンテンツイメージが小窓に表示されます。でも、何10回もスクロールをやっていると、下の方にあるこの「Web bookmark」は面倒、せやっと"/w"というようにスラッシュの後に'w'を打ち込んだら、やっぱり、絞って表示してくれました。素晴らしい。

Markdownのテーブルはシンプルにがモットーなんだろうなと思われるスタイルに対して、Notionのテーブルはデータベースそのもの。列のサマリー機能もあるようで、まだ試せていませんが、かなり高機能に思えます。

テンプレートを眺めてみると、Trelloのようなカンバンも作成できるようです。ここまでできるのであれば、「all-in-one」を標榜するだけの事はあります。

Wikipediaによれは、2016年に設立されたサンフランシスコの企業のようです。なので、ヘビーユーザも日本には少なくなさそうです。

とりあえずですが、Notion関連URLです。

www.google.com

gigazine.net

npedia.wiki

npedia.wiki

penchi.jp