はじめに
業務システムエンジニアさんがご提示した要件に対して実現ロジックを共有できる方法があるかもしれない。あるならば事前に共有して手戻りをなくしましょう的なお話。
対象読者
業務システムエンジニアのたまごさんで現在主な担当実務が実装の方
筆者について
システムエンジニアSEになって、うん十年、その前にハードウェアエンジニアを12年くらいやっていました。
ハードウェアエンジニアのときやってたこと
ハードウェアの設計手法に数値計算のシミュレーションや測定データからの補正みたいなことに積極的に取り組むタイプでしたので、プログラミングは本業ではありませんでしたが、数値計算プログラムを実装するうちにUIの部分、条件の入力や結果のグラフ化とかの実装に魅了されて、なんかそっちのが好きかもということでSEになりました。SEに転職する数年前からパソコンを買って自宅でもプログラミングするようになっていました。そのとき出会ったのが日本語プログラミング言語Mind(マインド)1 で、それはアセンブラのインラインコーディングもできて、直接マシン語を生成する2 強力なコンパイラ言語でした。
システムエンジニアになってから
SEに職種変更してからは、会計業務の知識を取得して仕訳システムを設計したりC++で実装開発したりしていました、そのうち世の中はWebシステムが主流となる時代に突入していきます。SEになったころでもうけっこういい歳ではあったのですが、若いコたちといっしょにお客様を訪問して打ち合わせしたり、その結果をドキュメント化したりで、けっこう楽しくやっていました。
そのとき、本題とはちょっと逆パターンにはなるのですが、若いコ向けに実装のロジックを伝えるのに使ったのが、日本語プログラミング言語Mind(マインド)を疑似言語化した日本語ロジック仕様記述言語(まさに究極でカンペキじゃない私のオレオレ言語です。@killyさんごめんなさい。)でした。
私がQiitaに参加したのは
話は跳躍しますが、私がQiitaに参加したのは、現状劣勢な日本語プログラミング言語勢[^3] に対して、なんとかできないだろうかという思いのためなのです。独自のランタイム、共通言語ランタイム上にのっかっていたとしても、けっこう細かいAPIの仕様差異で、現在の開発現場で多用されている実装言語との共存が難しいため、疑似言語化した日本語ロジック仕様言語と静的型付け言語へのトランスコンパイル可能な日本語言語仕様をまず突破口としようというのが、私が立案した戦略です。
そんな中でQiitaでいろいろな方と交流していきますと
現役のデベロッパさんからは実装言語としての日本語プログラミング言語に関しては、私が考案しているトランスコンパイラ言語も含めて、非常にネガティブな所感を持たれている方が多いということを改めて確認できました。一方でACII文字の実装言語の下書きとしては、各者各様ではありますが、私もその一人ではありますが、日本語でロジックをある程度記述してソースコードに併記するということは、私の知りえない現場の範囲でも行われているようだ3 ということが確認できた気がしています。
概要
スタート地点
これから述べることは、あなたがまだ設計はしないけど、SEさんが提示したなんらかの要件情報を、あなたがこれがおそらくSEさんが期待している結果要件を実現するロジックだろうという内容で実装をしました、というところがスタートです。
SEさんの提示してくる設計情報の粒度はいろいろで、会議とかも忙しいSEさん的にはついPGさんにロジックまる投げで、とりあえずこういう状態になるように実装してねとか、箇条書きで、あるいは、口頭のみで、情報が伝えられるかもしれない。
2つの選択肢
そこであなたには2つの選択肢が目前に提示されます。
選択肢A とりあえずコーディングし、デバッグして動くところまで爆走する。
選択肢B とりあえずコーディングした後、日本語ロジック仕様で抽象化してあげて、SEさんにこれでよさそうですかね?とコミュニケーションする。
後者の場合、SEさんも昔はジャヴァとか、あるいはヴイビーとか、さらに遡るとコボルとか、若いあなたがうそかほんとうか知りえない古(いにしえ)の言語でしか実装経験がない場合であっても、あなたが実装しようとしている最新または新しめの実装言語での実装ロジックの妥当性を検証し共有できる可能性が高くあります。
日本語で考えるとロジックがあいまいになる?
日本語で考えるとロジックがあいまいになるという言説は、あくまで自然言語の日本語で散文的に表現した場合に妥当と言えるでしょう。以下は、日本語ロジック仕様記述言語 Re:Mind(リマインド)によってC#実装コードを記述した例4 です。
記述例
Step:1 ざっくりソースコードを書く
例がいまいちですが、たぶんこうだろうというロジックを実装言語で記述します。
/// <summary>コード出力する</summary>
/// <param name="importList">インポートリスト</param>
/// <param name="soruce">ソース</param>
/// <param name="targetSourcesLineList)">ターゲットソースライン型リスト</param>
private static void codeOutput(List<string> importList,List<TargetSourceLines> targetSourcesLineList,List<SourceLines> sourcesLineList){
for(int i=0;i<importList.Count;i++){
var targetSource =importList.ElementAt(i);
Console.WriteLine(targetSource);
}
for(int i=0;i<targetSourcesLineList.Count;i++){
var targetSource =targetSourcesLineList.ElementAt(i);
Console.Write(getOriginalIndent(sourcesLineList,targetSource.sourceLineNumber));
Console.WriteLine(targetSource.targetLineStrings);
}
}
Step:2 関数名や引数名を整理する
関数名や引数名を整理します。JavaDocみたいなコメントでソースコードに物理名に対応した論理的な日本語の解説名が書いてある場合は、それを使うとよいです。
▽static コード出力する(リスト型<string> インポートリスト,リスト型<ターゲットソース行型> ターゲットソース行リスト,リスト型<ソース行型> ソース行リスト)
△
Step:3 ソースコードに対応したロジックを書く
/// <summary>コード出力する</summary>
/// <param name="importList">インポートリスト</param>
/// <param name="soruce">ソース</param>
/// <param name="targetSourcesLineList)">ターゲットソースライン型リスト</param>
private static void codeOutput(List<string> importList,List<TargetSourceLines> targetSourcesLineList,List<SourceLines> sourcesLineList){
//〇i=0,i<インポートリスト.Count,i++ 繰り返す
for(int i=0;i<importList.Count;i++){
//・ターゲットソース =インポートリスト.ElementAt(i)
var targetSource =importList.ElementAt(i);
//□コンソール.一行表示する(ターゲットソース)
Console.WriteLine(targetSource);
}
//〇i=0,i<ターゲットソース行リスト.Count,i++ 繰り返す
for(int i=0;i<targetSourcesLineList.Count;i++){
var targetSource =targetSourcesLineList.ElementAt(i);
Console.Write(getOriginalIndent(sourcesLineList,targetSource.sourceLineNumber));
Console.WriteLine(targetSource.targetLineStrings);
}
}
Step:4 ほぼ完成
ロジックを書き写したらほぼ完成です。JavaDocみたいなコメントで、日本語の論理名と実装言語の物理名を付記してさしあげるとなおよいです。
▽static コード出力する(リスト型<string> インポートリスト,リスト型<ターゲットソース行型> ターゲットソース行リスト,リスト型<ソース行型> ソース行リスト)
〇i=0,i<インポートリスト.Count,i++ 繰り返す
・ターゲットソース =インポートリスト.ElementAt(i)
□コンソール.一行表示する(ターゲットソース)
〇ここまで
〇i=0,i<ターゲットソース行リスト.Count,i++ 繰り返す
・ターゲットソース =ターゲットソース行リスト.ElementAt(i)
□コンソール.表示する(オリジナルのインデントを取得する(ソース行リスト,ターゲットソース.ソー0ス行番号))
□コンソール.一行表示する(ターゲットソース.ターゲット行文字列)
〇ここまで
△
とりあえず日本語表記の疑似言語なので、あまりかっちり考えず適当にゆるーく散文表現もまじえつつ、あなたの国語力で乗り切ることもできます。
ただ、あくまで日本語は形式化すればプログラミング言語になりうる自然言語なので、(語形に性別がないとかけっこう助かる気はします。もちろん英語にもありませんが。)ある程度プログラミング言語的な形式的な記述をお勧めいたします。
また、あくまでエンジニア同士の情報共有なので、一般的な実装言語の表記も混在させるのはありです。
言語仕様(抜粋)
日本語ロジック仕様記述言語 Re:Mind(リマインド)はオープンな設計言語仕様で、どなたでもこの記法を使いロジックを記述することができます。
制御構文の開始シンボルとして、◇、〇、□、・などの全角記号を用い、箇条書きされた日本文としての体裁を日本語トランスコンパイラ言語 Re:Mindの構文と共有しています。◇は分岐構文、〇はループ構文の開始と終了を表し、冗長な日本語表記がなくてもフロー図の表現に慣れている方が直感的に認識できることを考慮しています。
制御構文
分岐
◇i > 0 の場合
//todo
◇ここまで
□全角記号のひし形◇が条件分岐の開始となります。
・続いて論理式を書きます。半角かっこは不要。
・続いて「の場合」と書きます。半角で書かれた論理式とはくっついていても可。
・全角記号のひし形◇が条件分岐の終了となります。
・つづいて「ここまで」と書くことができます。省略も可。
◇i > 0 の場合
//todo
◇他に i < 0 の場合
//todo
◇他に
//todo
◇ここまで
◇途中で最初の論理式とは排他的な条件をつづける場合は、全角ひし形◇に続いて「他に」と書いて、論理式を書いて、「の場合」と書きます。
・論理式の前後の空白は、論理式を半角で書いている場合は省略できます。
◇最後に例外条件を明示する場合は、全角ひし形◇に続いて「他に」と書きます。
繰り返し
〇i=0,i<10,i++ 繰り返す
//todo
〇ここまで
□全角記号の丸印〇が繰り返しの開始となります。
・続いてカウンタ論理式をカンマ区切りで書きます。カウンタ変数の型名と半角かっこは不要。
・続いて「繰り返す」と書きます。半角で書かれた論理式とはくっついていても可。
・全角記号の丸印〇が繰り返しの終了となります。
・つづいて「ここまで」と書くことができます。省略も可。
〇繰り返す
//todo
〇ここまで
□全角記号の丸印〇に続いて「繰り返す」と書いた場合は無限ループになります。
〇繰り返す
//todo
◇j==0 の場合 やめる
//todo
〇ここまで
・繰り返し構文内で条件分岐文を書いて「やめる」と書くと、直接のループを脱出します。
/** index */
〇int インデックス=0,インデックス<10,インデックス++ 繰り返す
//todo
〇ここまで
・繰り返し構文のカウンタ変数をインラインで日本字で宣言することもできます。
変数
・整数 年齢 = 34
・文字列 名前 = "花子"
・ブール値 特待区分 = true
□全角文字の中点に続いて、型名を記述し、空白に続いて変数名を記述します。
・型名は一般的なプログラミング言語の半角型名でも可。
・半角等号で初期値を宣言できます。
おわりに
意外とシステム開発の現場では、複雑なロジックのモジュールの場合、SEさんとデベロッパさんとの間で意思疎通がうまくいかず、あくまでSE目線的な表現としてはデベロッパさんの爆走を看過してしまい(丸投げする方が基本ワルイ)、できあがったモジュールの出来をみたら、こんなんじゃなかった的なことは、(暗によくあるのではといいたいところですが)まったくご経験されたことのないあなたは超優秀デベロッパさんです!
-
Qiita 日本語プログラミング言語「Mind」最新版をリリースしました 参照 ↩
-
PureMind Pro5.2以前の場合 現在は独自中間コード生成。 ↩
-
Qiita 下書きしてからコードを書く 参照 ↩
-
Qiita 日本語トランスコンパイラ言語 Re:Mind(リマインド)の試作バージョンを日本語ロジック仕様記述言語 Re:Mindで内部設計する(ターゲット言語C#) 参照 ↩