[境界要素法プログラムを設計する(境界積分サブルーテイン:策定編)] [境界要素法]
[境界要素法プログラムを設計する(境界積分サブルーテイン:策定編)]
1.サブルーティンは必要か?
世の中には、何でもかんでもサブルーティンにすれば良いと思ってる人がけっこういますが、自分の意見は違います。メインルーティンの作業をサブルーティン化すれば、確かにメインは綺麗に整理されてプログラムのフローがわかりやすくなります。しかし代償もあります。それは具体的な作業コードが隠蔽化(カプセル化)されて、可読性(読み解きやすさ)が悪くなるケースもあり得るからです。
特に大規模プログラムでは何10~何100というサブルーティンが現れ(大規模だからしゃーないんだけど)、こっちのファイルを読みあっちのファイル読んで、そっちのページを・・・とやってると、最弱マシンである人間は、それだけでバグ化します(^^;)。こういう場合は、メインの作業フローを組み直すべきなんですが、では次のような例はどうでしょう?。
よくサブルーティンは引数付きが推奨されます。ローカル変数が使えるので、変数競合を避けられるからです。最強マシンであるPCが、最弱マシンである人間のミスから、その最弱マシンを自動で守ってくれます。
メイン冒頭でxの値を評価し、その評価によって計算の行く末を決める、計算初期値yの値が変わるとします。
If x < 0 Then
y = 0
ElseIf (0 <= x) And (x < 1) Then
y = 1
Else
y = 2
End If
REM yを使った計算
これはサブルーティン化すべきでしょうか?。するとしたら、こんな感じになりそうです。
External Function y_Setter(x)
If x < 0 Then
y = 0
ElseIf (0 <= x) And (x < 1) Then
y = 1
Else
y = 2
End If
y_Setter = y
End Function
If x < 0 Then
y = 0
ElseIf (0 <= x) And (x < 1) Then
y = 1
Else
y = 2
End If
REM yを使った計算
・・・と非常にすっきり(^^)。ところが入力仕様が変わり、yのケース分けが1個追加され、しかもケース境界も可変になる事がわかりました。それにともなって「yを使った計算」も変更されます。こうなると、
External Function y_Setter(x)
If x < 0 Then
y = 0
ElseIf (0 <= x) And (x < 1) Then
y = 1
Else
y = 2
End If
y_Setter = y
End Function
メインの側は、
Declare External Function y_Setter
y = y_Setter(x)
REM yを使った計算
だいたいこの辺りからPMは、PG(プログラマー)の恨みを買い出します(^^;)。
y = y_Setter(x, z1, z2, z3) REM z1~z3はケース分けの境界値
REM yを使った計算_変更1
External Function y_Setter(x, z1, z2, z3)
If x < z1 Then
y = 0
ElseIf (0 <= z1) And (x < z2) Then
y = 1
ElseIf (0 <= z2) And (x < z3) Then
y = 2
Else
y = 3
End If
y_Setter = y
End Function
事態はさらに最悪の方向へ向かいます。「開発が終わるまで入力仕様の変更は続き、ケース分けは何ケースになるかわからない。それに対処できるようにしといてくれ」。・・・頭に血が上ったPGは、こう叫びます。
「わかった。配列で渡すようにする。後で汚いとかコードが重いとか、文句言うなよ!」
引数付きサブルーティンは確かに推奨されるべきものです。でも、入力仕様の変更に非常に弱いという欠点も持ちます。だからやめなさいって、そんなもん。自分ならメインで単にこうします。
If x < z1 Then
y = y0
ElseIf (0 <= z1) And (x < z2) Then
y = y1
ElseIf (0 <= z2) And (x < z3) Then
y = y2
Else
y = y3
End If
REM yを使った計算_変更2
REM ElseIfブロックは、何個でもコピーして増やせる!
もう一つは、引数並びが重く複雑なサブルーティンは内容も複雑な訳です。しかもサブルーティン化したためにコードが隠蔽され、メインと並べて一目で見渡せなくなります。最弱マシンはそこで、必ず何かを見落とします。バグ特定がしずらいため、それはバグの連鎖反応も招きかねません。
でもテスト技術者(TE)って、こういうコードが嫌いなような印象を受けます(規格物好き?)。確かに綺麗なコードの方が、テストしやすいですもんね。「何でサブ化しない?」ってけっこう言われました(^^;)。
PG「だって仕方ねぇ~だろう。PMの野郎が仕様をどんどん変えるんだから」
TE「それとコードの可読性は別だ。サブ化しないから可読性が悪い」
PG「悪いだと?。上から順番に読めば、必ずわかるコードのどこが悪い」
TE「メインに1万行も書きやがって、この馬鹿ものがぁ~!」
PG「うるせぇ~!。順番に1万行も読めない奴は、PGでもTEでもねぇ~!」
PM「開発の最終段階でサブ化したら?」
PGとTE「・・・・・・」
2.境界要素法プログラムは?
で、境界要素法プログラムではどうでしょう?。とりあえず問題の部分は、
REM (x0,y0),(x1,y1),(x2,y2)から、要素kの境界積分値を計算
でした。ここで(x0,y0)は特異点座標、(x1,y1)と(x2,y2)は一つの境界要素kの端点座標です。これらは入力部で既に確定しています。という事は、仕様変更はほとんどなさそうです。
・・・ではサブ化しますか。でも自分の考えでは、これだけでは弱いと思います。境界要素法プログラムの[計算部]をサブ化せずに全部ベタ書きしても、1000行くらいだと思います。さっきのお馬鹿PGだったら「ベタ書きしろぉ~!」というでしょう。1000行くらいなら全体を一気に見渡せると思えるからです。なぜコードを隠蔽して、見にくくするのか?。もっと強力な理由が必要です。設計における方針決定には、明白な根拠があるべきです。
「境界要素番号kで境界積分を行うLoop」が動的過程だからです。前回の該当部分を見て下さい。自分は十分に長いLoopだと思います。その最大の理由は、要素-節点対応表を使って積分値の重ね合わせをやってるからです。つまりこのLoopは一種の漸化式なんですよ。漸化式って短くても、すぐ訳わかんなくなりますよね?(^^;)。そういう部分は出来るだけ綺麗に見やすくしとくべきだ、と思うからです。境界積分値を計算する、サブルーティンを作ると方針決定します。
これは、
1) 動的過程を制御するメタな静的構造(今はLoop)の可読性を上げて確保する.
事でもあります。ほとんど意識されませんが、サブルーティンを用いる最も大きな理由の一つが上記だと自分は思います(コード自体は短くても)。y_Setterはそういうものではありませんでした。
あとサブルーティンを用いる一般的理由としては、当然ながら、
2) メインが長すぎて一気に読めない(1万行は多すぎる(^^;)).
3) 再利用性を考えた.
などです。y_Setterは、2),3)いずれにも該当しません。
3)は(オブジェクト指向も含めて)サブルーティン化の大きな理由とされますが、じつはバグの発生頻度とトレードオフの関係にあります。
一般にコードは書けば書くほどバグ確率は比例して増加します。再利用すれば一回しか書かないので、良さそうに思えます。しかしコードは隠蔽されるので、潜在バグの発生確率が上がります。それに気づかぬまま潜在バグが発覚すると、今度はシステム全体で大被害です。大抵そこら中で使い回すからですよ。大被害が出るとバグの場所はわかりやすいですけれど、運用段階に入ってた銀行のシステムなんかだと、わかりやすいでは済みません(^^;)。一番困るのが、運用段階に入ったサブルーティン間の競合です。
以上は全て人間の都合です。機械にとってはどうでも良い事です。なので2)などは、人間の限界を認めた話です。人間原理最優先で行きましょう(^^)。人間原理最優先なので、以後サブルーティンと関数にはローカル変数を持てる外部手続きのみ用います。タフな機械に守ってもらいます。
コメント 0