Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

「定量的な数値」とは何か

  • (A) 第三者が何らかの方法で計測できる数値を指して「定量的な数値」と言う。
  • (B) 第三者が何らかの方法で計測できる数値の中でも、ものごとの量を表す数値を指して「定量的な数値」と言う。

たとえば、生産効率や不良率は(A)、生産量や作業時間は(B)にあたります。定「量」的な数値、というわけですね。 (言葉の意味として適切かどうかは別として)作業量やスケジュールを報告する際には(B)だけを指して「定量的」と言ったりする人がいるようです。

ソフトウェア考古学論考 (2)

どっちかもいうとこっちが本題。

さて、ソフトウェア考古学の目的としては、

の他にも、poorly-documentedなレガシーシステムソースコードから、その仕様(あるいは意図)を読み解き復元し、システム再構築のインプットにするというケースが考えられます。

システムの技術的負債の解消や開発者の技術継承などを目的としてシステムを再構築する考え方としては、Fowler(2014)による犠牲的アーキテクチャ*1、および高橋 (2017)による式年遷宮アーキテクチャ*2が提案されています。 システム再構築にあたっては、セカンドシステム症候群を避けるためにも、まずは欲張らない(つまり、現行システムと同程度の)機能をカバーするよう開発を行うわけですが、その際これまで現行システムが本番環境で踏みつけてきた様々なコーナーケースの地雷を避けるには、現行システムの処理がなぜ現在のようになっているのかの理解が欠かせません。

ここで「システム再構築のインプットとなる設計思想の復元」を目的としたソフトウェア考古学的活動が必要になると思うのですが、そのような論文は見当たりません。とすると、

  1. アジャイルソフトウェア開発における知識の保存は成功を収めた。犠牲的アーキテクチャに基づくシステム再構築に耐え得るだけの知識を保存することができた(≒問題にならなかった)
  2. 犠牲的アーキテクチャに基づくシステム再構築は、ソフトウェア考古学的活動を伴っていない。十分な業務知識に基づくトップダウンの再設計だけで、刷新前のシステムと同程度の機能を実装できている(≒やっぱり問題にならなかった)
  3. ソフトウェア考古学的活動による設計思想の復元に成功した例はない。システム再構築は単純なストレートコンバージョンで行われている(≒成功していないので何も書けない)

のどれかなのかなぁと思うのですが、どうなんでしょうね?(3に一票入れたいのですが、悲観的に過ぎるかな?)

*1:Martin Fowler, "Sacrificial Architecture", 2014. URL: http://bliki-ja.github.io/SacrificialArchitecture/

*2:高橋征義, "青空文庫式年遷宮アーキテクチャ: 青空文庫200周年に向けて", 青空文庫20周年記念シンポジウム「青空文庫の今とこれから」, 2017. URL: https://www.slideshare.net/takahashim/aozora20th-2017

ソフトウェア考古学論考 (1)

ソフトウェア考古学(Software Archaeology)という考え方は、OOPSLA 2001で提唱されたのが始まりのようです *1Wikipediaにある通り *2 、poorly-documentedなレガシーシステムソースコードやドキュメントをどう読み解くか?というところから始まったようなのですが、現時点では、Google Scholarで調べる限り、ソフトウェア考古学の研究分野は大きく以下の2つに分かれているように見えます。

  • レガシーシステムの保守開発の効率化。poorly-documentedなレガシーシステムソースコードから、その仕様(あるいは意図)を読み解き、保守開発を確実に実施する(またはリスクを低減する)。たとえばBryon (2009)*3など。
  • システムの仕様理解の補助。昔から開発の続いているソフトウェアのソースコードの変遷やバグの出かたを変更履歴から読み解くことで、現時点のソフトウェア(これ自体はいわゆるレガシーでない場合もある)の仕様理解を助けたり、品質向上の助けにしたりする。たとえば Carrington et al. (2003)*4など。

分析に用いる手法や、その目的から見ると、後者はどちらかといえば「ソフトウェア考古学」というより「ソフトウェア発生学 (Software Embryology)」と呼ぶべきかもしれません。

前者の例を挙げると、たとえばCOBOLソースコード中に

IF 件数 = 9999 THEN

みたいな文があったら、

  • なにかのレコード件数が本当にぴったり9999件だったときの処理なのか?
  • 異常を表す値としてHIGH-VALUEである「9999」を使うのはCOBOLでは常套手段だから、異常系処理なのか?
  • あるいはレコード件数が9999件より多かったときの処理(レコード取得時に上限を9999件として取得しているために、イコールで比較するだけで済んでいる)なのか?
  • あるいは変数名に騙されているだけで、「件数」という変数は実は配列のインデックスなのでは?レコード取得時には件数を制限しておらず、ループ回数に上限を設けて処理を打ち切っているのでは?

といった具合で、対処となる行やその周辺を元に処理の意図を読み解き、最終的には

*検索結果を表示できない場合(レコード取得時にDBエラー発生、
*または検索結果が画面表示件数の上限を超えていた場合)
 IF 件数 = 9999 THEN

のように仕様を復元することを指します。

もちろん、アプリケーションの業務的仕様を把握している人がいるなら、わざわざこんな面倒くさいことをせずとも「知ってる人に聞く」だけで解決できるわけですが、そうもいかないケースもあるわけで、たとえば以下のようなケースが思いつきます。

  • 仕様決定の経緯を把握してる人が定年で辞めちゃった
  • 仕様決定の経緯を把握してる人が他社へ転職しちゃった
  • 仕様決定の経緯を把握してる人がいるにはいるけど、元請じゃなくて開発会社の人(詳細仕様を質問するためだけに契約を結ぶのか?という話になる)
  • 仕様決定の経緯を把握してる人が所属してる会社と仲が悪くなっちゃって、ちょっと聞きに行ける雰囲気じゃない
  • 仕様決定の経緯を把握してる人が社内にいるけど、別のプロジェクトにアサインされてて、おいそれと聞きに行けない*5
  • 仕様決定の経緯を把握してる人が社内にいるし、話も聞いてきたけど、聞いた話の内容を理解できるレベルのメンバーがチーム内に残ってない

そもそもソフトウェア考古学が必要になる前には、開発は上手く回っていたわけで*6、その影にはこういう「知ってる人」や「仕様決定の背景を理解できる人」の存在があったわけですね。

翻って現代のアジャイルソフトウェア開発においては、知識を個人でなく組織に溜め込むことで、必要なドキュメントを減らそう、それで代替できるドキュメントは作らないようにしよう、という考え方があるわけです(SCRUMの研修で聞いただけの話ですが……)。 ただ、ソフトウェア考古学が生まれた経緯を見るに「知識を組織に溜め込むことで、保守に必要な知識が失われないようにする」のは、果たして可能なのだろうか?ドキュメントを作らないことで、逆にソフトウェア考古学の出番が増えやしないか?という点は疑問に思っています。開発チームは存続していても、メンバーの退職・異動・昇進などのイベントを経ることで、どうしても開発開始当初に考えられていた設計上の思想はチーム内でも薄まっていきます。大量のバックグラウンドや経緯や意図を伝えるには、それに見あった量のドキュメントが必要なのでは

アジャイルソフトウェア開発宣言がまとめられたのは2001年、今年で18年です。アジャイルソフトウェア開発の黎明期に作られたソフトウェアの開発思想や背景は、今でもチーム内に知識として保存されているのでしょうか?また、ソフトウェア考古学なしでもそのソフトウェアの保守開発に立ち向かえるのでしょうか?

*1:Ward Cunningham, Andrew Hunt, Brian Marick, Dave Thomas, "Software Archeology: Understanding Large Systems", OOPSLA 2001 Workshop, URL: https://web.archive.org/web/20100612232147/http://www.visibleworkings.com/archeology/position-papers.html

*2:https://en.wikipedia.org/wiki/Software_archaeology#cite_note-RGBH-1

*3:Bryon Moyer, "Software Archeology: Modernizing Old Systems," Embedded Technology Journal, March 4, 2009. URL: https://www.omg.org/adm/docs/Software_Archeology_4-Mar-2009.pdf

*4:Carrington, David, and S-K. Kim. "Teaching software design with open source software." 33rd Annual Frontiers in Education, 2003. FIE 2003.. Vol. 3. IEEE, 2003. URL: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.103.2003&rep=rep1&type=pdf

*5:こういう時に限ってアサイン先のプロジェクトが炎上してたりするんですよね……

*6:儀式的に回っていただけかもしれませんが。 cf. カーゴ・カルトソフトウェア工学

How to separate a string into codepoint-wise characters with PowerShell

Context:

You have a Unicode string that contain non-ASCII characters as well as ASCII characters. You want to separate that string into characters.

Problem:

If you split the string with the code below:

$TemporaryArray = $InputString -split "";
$ResultArray = $TemporaryArray[1..($TemporaryArray.length-2)];

You will have a problem: characters that represented as surrogate pair (U+10000 ~ U+10FFFF) will separated high surrogate and low surrogate (they are not character).

Reason:

PowerShell -split operator is not surrogate pair aware, and it seems by design.

Solution:

Once convert the string into UTF32 byte-array, and separate it into codepoints (4-byte length), and convert them to String object.

$ResultArray = @();
$InputStringBytes = [Text.Encoding]::UTF32.GetBytes($InputString);
for ($i=0; $i -lt $InputStringBytes.length; $i+=4) {
     $ResultArray += [Text.Encoding]::UTF32.GetString($InputStringBytes, $i, 4);
}

Limitation:

This method separate a string into each codepoint, so the Unicode ligatures (it consists of two or more codepoints) are illegally separated into codepoints. You can use icu.net for this purpose.

Difference of behavior of String#split() in Java and -split operator in PowerShell

Difference of behavior of String#split() in Java and -split operator in PowerShell

Both of String#split() in Java and -split operator in PowerShell take regex as argument, and split string into a list or an array, but there is some difference in behavior when you pass an empty string as argument.

In Java:

System.out.println("abc".split("").length); // -> 3

Whereas in PowerShell:

PS > ("abc" -split "").Length  # -> 5

Because ("abc" -split "") makes @("","a","b","c","").

Also in PowerShell:

PS > ("abc".split("")).Length  # -> 1

Because split("") will not split the target string at all.