ラベル 品質 の投稿を表示しています。 すべての投稿を表示
ラベル 品質 の投稿を表示しています。 すべての投稿を表示

2011年12月21日水曜日

小事の思案と割れ窓理論

葉隠と言えば、「武士道といふは死ぬ事と見付けたり…別に仔細なし。胸すわって進むなり。」で有名だけど、正直、自分みたいな「すくたれもの」には難しい。

だけど実は葉隠には、そんなムリなやつばかりじゃなくて、普通に実践的なアドバイスも結構ある。

『大事の思案は軽くすべし。/小事の思案は重くすべし。』

これについて自分は、やっぱり開発者で飯を食っているせいか、前半をリスク管理の問題、後半を品質管理の問題と捉えてしまう。

前半の『大事の思案』がなぜ軽いかについては、非常にクリティカルな事態に関しては、いざというときに判断に迷って対応が遅れたりしないように、普段から方針を定めておいて、即断即決できるように備えておくべきだという解釈になる。

後半の『小事の思案』がなぜ重いかについては、三島由紀夫が葉隠入門の中で、アリの穴から堤防が崩れるように、瑣末なことを軽んじる事によって生活の体系や重大な思想までもが台無しになると解説している。

で、もちろん前半も後半もどちらも大事なんだけど、どちらかというと自分なんかには後半の方が、より切実にピンと来る。(管理の比重が大きい人は前者かもしれない。)

例えば、コーディング規約なんかみたいなものでも、「ぎりぎり読めりゃいいじゃん」みたいに適当にしないで、きっちり律儀に守ってかないといけない。と自分は思う。

そこを疎かにするから、規約違反の放置->->内部品質の低下->->外部品質の低下->->製品品質の低下 ってな感じで、結局、また地獄になってくんじゃないかと。


で、この小さい事こそ大事ってのを、別角度から現代風に理論化したのが、割れ窓理論だと思う。

一般には、ジュリアーニ市長の時代にニューヨーク市が治安を回復したときにベースになった理論として有名なアレだけど、Wikipedia によるとこうなる

「建物の窓が壊れているのを放置すると、誰も注意を払っていないという象徴になり、やがて他の窓もまもなく全て壊される」

ささいに見える Duplicate code の放置が、コピペだらけの巨大な糞コードの山に繋がっていくという、まあ、ありがちなあれと同じじゃないだろうか。

で、この割れ窓理論をベースにした政策が「ゼロトレランス」だけど、開発現場に当てはめてみると、さしずめ Refactoring Mercilessly といったところか。

なんて事を考えていると、例えば、「途中return は是か非か」みたいな、一見不毛でアホらしい事についてムキになって議論するのも、けっこう大事というか、度を越さない範囲ならむしろ健全だとも思えてくる。もちろん自分もわりとムキになる方だ。

2011年11月3日木曜日

仲間外れはどれか?

下の図は、仲間外れを見つける問題例だけど、小学校受験のためのものだから幼稚園児向けということになる。

仲間外れといっても、一応、少なくとも野菜ではあるのだから、問題の趣旨を一旦置いておけば、あながち間違った括りとは言えなくもない。

でも、じゃあ、「カボチャ」の代わりに、「八百屋さん」だったり「プログラマ(好きな食べ物:肉、嫌いな食べ物:野菜)」とかだったとしても、同じカテゴリって言い張る奴っているのだろうか。まあ、こんなアホな質問はした事はないけど、身の回りには多分いないと思う。つうか、いたら嫌だ。

ところが、それに相当するようなソースコードなら、プロの開発現場でもしょっちゅう見かける。今日はそんな事を書いてみる。

====

こんなコードがあったとする。

このコードには、ダメなところがいくつかあるけど、特にまずい問題点を、ちゃんと技術者っぽい言葉で説明できるだろうか。

/** 色を指定できるカーペット。 */
public class Carpet {
   private final int color;
   public Carpet(int color) {
      this.color = color;
   } 
   //…
}

/** システムで使える色の集合  */
public class Colors {
   private static final Map COLORS = new HashMap();
   static {
      COLORS.put("赤", 0xFF0000);
      COLORS.put("緑", 0x00FF00);
      COLORS.put("青", 0x0000FF);
   };
   private Colors() {} 
   public static int colorNameToRgbValue(String colorName) {
      return COLORS.get(colorName); 
   }
   public static List createCarpets(String[] colorNames) {
      List result = new ArrayList();
      for (String colorName: colorNames) {
         result.add(new Carpet(COLORS.get(colorName)));
      }
      return result;
   }
}

Colors は本当は enum を使うべきだけど、サンプルの都合上普通のクラスにした。また、そもそもユーティリティクラスがまずいってのは、取り敢えずこの際、放っておく事にする。

Colors という色のセットを表すクラスに、色に関係ない事はないけど明らかに異質でレベルの違う Carpet という概念を扱うメソッド、createCarpets() が定義されている。

こういうとき、ちょっと堅苦しい言い方だけど、「凝集性が低い」という(もちろん低いほどダメ)。

もっと言うと、暗合的凝集度論理的凝集度の間くらいになると思われ、レベルとしてはサイテーに近い。(技術者っぽくない言葉でいうと、暗合的凝集度は「なんで同じクラスに入れてんのかイミフ」なやつで、論理的凝集度は「言い訳できない事ないけど必然性に乏しい」やつ。)

この凝集性と表裏一体の概念として、結合度というのもある。

上のコードは結合度が高い(こっちは高いほどダメ)のだけど、実質的にグローバル関数といえるメソッド群がクラス変数という実質グローバルな情報を介して結びついている点で「共通結合」であり、6段階あるうちの悪い方から2番目で、やはりかなり酷いコードと言える。

さらに、凝集性や結合度はオブジェクト指向隆盛以前の、構造化手法全盛期からある設計評価基準だけど、オブジェクト指向に関連の強い言葉「責務」を用いて表現すれば、「createCarpets によって、Colors が一つ以上の異なる責務を負っている事が問題」と言う事もできる(責務:言うまでもなく CRC の R(Responsibility))。

つうわけで、上のコードは単純過ぎる例ではあるものの、技術的には「低凝集・高結合度で、複数の責務を負った下手糞なコード」だと言える。まあ、そういうコードや設計を放置しておくと、その先どうなるかについて、技術者じゃない人になら説明する必要があるけど、技術者同士なら説明不要だと思う(思いたい)。

ただし、実はクソヘタプログラマだけがこんなコードを書いているのではなくて、そこそこの技術者/チームでも、開発期間の中で生じるいろんな行きがかり上、たまたまこんな感じになってしまって、そのまま直す機会を逸してしまってる場合もある。

まあ、でも。そんな時のためのリファクタリング技術なわけで、ちゃんとテストコードを実行するという前提(当たり前だけど、無ければ必ず書き足す)さえ守れば、なんぼでも体質改善すれば良い。

だけど、そもそもダメだって事が認識できないとなると、いろんな意味でかなりやばい。説明するこっちも、クラスの責務から説明すればいいのか、結合度・凝集度から説明すればいいのか、それとも小学校受験の仲間外れ問題まで遡って説明しなければならないのかと考えてしまって、なんかもうキッツイわ…

2011年8月27日土曜日

Advanced Level テストマネージャ試験受けてみた

今日、JSTQB という団体がやってる、ソフトウェア・テスト技術者試験の Advanced Level 試験(Foundation Levelの上級試験)を受けてきた。

全65問のうち、きっと問題のミスだろうと思われる不可解なところを除けば、全問できたような気がする。まあ9割5分とか9割でも普通は合格だと思う。

というかあまり難しくなかった。去年、実施したらしいトライアル版試験の統計をみると合格率10%というから、さぞかし難関だろうと思ってたけど、試験時間を半分過ぎた辺りから余裕な感じで退出する人も多かったりして、今回は合格率50%を越えるような気がしないでもない。

ところで、試験勉強はISTQB(JSTQBの親の国際団体)が出している試験のシラバス(学習事項)をひたすら読むだけだけど、これがよくできていて勉強が苦にならない。

以前のポストで、Foundation Level のシラバスを紹介したけど、さすがにそれよりはテスター向けの専門性が高い。それでも自分のようなテスト専門じゃない開発者にとっても、読み応えがある。

実プロジェクトのテスト技術者の教科書としてもそのまま使えそうな内容で、暗記事項の羅列などはほとんど無いかわりに、なんというか現場感覚があるので、過去に携わったプロジェクトや今現在進行中のプロジェクトについて、いろいろ考えさせられる。

ちなみに Advanced Level 資格には テストマネージャ、テストアナリスト、テストテクニカルアナリストという種別があり(今回のはテストマネージャだった)、3つそろったら、なんか格上の称号が与えられるらしい。まあ、欲しくないと言えば嘘になる。

2011年6月18日土曜日

保守性とイマドキの開発

「ソースを綺麗にしてコードの保守性を高めよう」なんて事は誰もが言うし、「規約を作って静的チェックツールにかけよう」とか、「UnitTest を書いてリファクタリングも奨励しよう」なんて感じで話が進む事もあるけど、いざとなるとグズりだす怪しからんヤツらが実に多い。

スケジュールがきついからとか、コスト面の制約で人が足りないからとか言うのが、お約束のエクスキューズなんだけど、うーん、だからこそなんだがなあ・・・

で、ちょっとコードの保守性について、特に、それが大事なのは何故なのかという点を中心に考えてみる。

====
実はまず、「保守性」ってネーミングが、そもそも良くなかったりする。語の使用の歴史的経緯から見ても、どうしても納品後の保守フェーズに係る品質要素という印象が拭えない。最も適切と思われる内部品質は意外と知られていないし、可読性だと読むだけみたいだし、「綺麗なソース」とか「健康なソース」では情緒的過ぎて説得力に欠ける。

ここで「保守性」を、開発者の素朴な観点から言い換えると、「保守作業の生産性」って事になる。ISO 9126の分類は、論点が違うのでここでは割愛

この生産性が低ければ、当該の保守作業にもその分だけ時間とお金が掛かったりするわけだけど、じゃあ、その保守作業とは何だっただろうか。

再び開発者観点で素朴に考えると、「既存ソースを読んで意図と構造を理解し、追加・書き換え・削除等の編集を施す」、さらに短くは「ソースを読んで編集する」という、それだけの事だとわかる。

で、これを踏まえて言い直すと、「保守作業の生産性」とは「ソースを読んで編集する作業の生産性」という事になる。…が、はて?こんなのは今時、保守フェーズに限定された作業なんかでは全然ない。

極論すれば、6ヶ月の開発期間における最初の10分くらいから、「ソースを読んで編集する作業」は早くも発生し始めるし、反復型の開発なら第二イテレーション以降は大部分がその意味で「保守作業」になる。

「動いてるコードはイジらない」的な昔の開発風景ならともかく、既存コードを編集しながら成長させる現代の開発では、「保守性」はプロジェクト全期間に渡る重大ファクターであり、開発初期から「実装生産性」そのものに漸近していく。

なわけだから、正しくは「スケジュールがキツいし人も足りない」-> 「ならば生産性を上げよう」-> 「つまりソースを改善して保守性を上げよう」と考えなければならない。これの逆をやってるから、各反復で負のスパイラルを誘発し、ドツボにハマっていく。

====
というのが、コード保守性に関する不見識への、差し当たりの抗議。

「そもそも保守性の高いコードとは何か」と、「保守性向上作業(リファクタ等)の工数はどうしてくれるんだ」という2つの事項についても説明が必要だが、別の機会にする。

まあ現場では、こうして理詰めで説明しても、心理的・組織的圧力で生産性を考慮しないままなし崩しに開発が進んでいってしまう事は往々にしてあるんだよなあ。

2011年1月27日木曜日

ソフトウェア品質の対概念

プロがで自分の職能分野の事柄を wikipedia で調べる事となると、何となく気恥ずかしさを感じないでもないが、たまに良い事が書いてあってちょっと嬉しい時がある。

ソフトウェア品質Software_quality)」で調べると、ちゃんと「ソフトウェア製品品質Software_product_quality)」と「ソースコード品質(Source_code_quality)」に分けて書いてあった。

ソフトウェアに関しては、一般的な意味での品質ーーーつまり「日本の精密機械の品質は・・・」なんて言うときの「品質」とは別の、もう一つの品質があるという事が、実はわりと普通の考え方なのだという証言が一つ得られた事になり、少しほっとした。更に少し調べると、ISO/IEC 9126-1:2001でも「内部品質」という形で定義されているらしい。不勉強だった。

とは言っても、この二つの品質が互いに異なる別物だという考え方は、まだソフトウェア開発業界で常識となるには至っていないように見える。

開発中の製品の品質について会議なんかで議論すると、こっちが後者の意味で話しているのに、しかも、どういう意味での「品質」か、ちゃんと前置きしてから語っているはずなのに、いつの間にか前者の話に流れて行ったりする。終いには「”品質”の話をしてるんだから、コードとか関係なくね?」みたいに返してくるから、こっちも「だ~か~ら~」みたいになってくる。

大雑把に言うと、製品品質は売上に関わり、ソースコード品質は費用に関わる。つまり、製品品質は使う側の生産性を左右し、ソースコード品質は作る側の生産性を左右する。あるいは、製品品質の問題は消費者側で顕在化し、ソースコード品質の問題は生産者側で顕在化するとも言える。

ある意味正反対の概念が、「品質向上」などと言ったスローガンの下で一緒くたに扱われるから、品質管理会議が何だか噛み合わない。いっそ別の言葉でもあれば良いんだけど、日本語でも英語でも適切な言葉が見当たらない。

「今話している「品質」はソースコード品質の意味での「品質」なわけで、つまり(略)」みたいな面倒くさい断りを入れずに済む状況は、当分なくなりそうにない。

2011年1月18日火曜日

JSTQB認定テスト技術者資格試験のシラバス

去年の夏の終わり頃、JSTQB という団体が認定するテスト技術者資格の試験を受けた。

Foundation Levelという事で、上級者向けの Advanced Level (まだ始まっていない)とはおそらく違ってそれほどハードルは高くなく、プロならほとんどが受かる難易度だと思う。勉強の材料は、JSTQB のサイトで配布されているシラバスを使った。これをよく読めば大体受かるはず。

実は、このシラバスがすごく良く出来ていて、受験者だけが読むのでは少しもったいない気がした。

短い分量に、用語、基礎知識、各種テクニックから教訓まで、非常に上手くまとめられている。

テスターはもちろんの事、開発者から PM、仕様担当者まで、広めの範囲の関係者一同で読み合わせて、認識を共有したりすると良いと思った。

2010年7月11日日曜日

三項演算子を使うべき理由

三項演算子を使うべきでないとする規約や現場って、結構多い。

それに対する「使う」派の主張もたまに見かけるが、
  • 「控えめに使うなら許されるべき」なんて消極派だったり、
  • 「三項演算子すら理解できない奴はクズ」なんて議論拒絶派だったり、或いは
  • 「三項演算子の方が格好良くて好き」的な頭脳労働苦手派であったり
する。

自分は使用肯定派だけど、なるべく合理的に三項演算子について考えてみたい。日曜なのに暇だしな。

最初にまず、「if 文ではなく三項演算子を使うべき」状況を考えて、その後で、良くある三項演算子否定論への異議を述べてみる。(言語は C# とか Javaを想定)

■■ if 文を避けて三項演算子を使うべき理由

★ 変数の宣言と定義を同時にできる
一時変数への値の設定について、宣言と同時なのと宣言から離れているのとで、どちらが良いコードかという問題だが、後者の「離れて」が正解なんて言う人は聞いたことが無いので、説明は割愛。(一応手持ちの資料を調べると、『Code Complete 上巻』の変数の部に詳述されているので、理屈を確認したければこの辺りを読めばいい)
public int Foo(bool f)// if 文版
{
  int i;
  if (f)
  {
    i = 100;//← 宣言した行から離れている
  }
  else
  {
    i = 200;//← 宣言した行から離れている
  }
  // i を 使う
}

public int Foo(bool f)// 三項演算子版
{
  int i = f ? 100: 200;//← 宣言した行で値を設定している
  // i を 使う
}
Javaならば更に final を付けて、より低リスクな安心コードにできる。(残念ながら、C# の const では、同様の安全策ができそうでできない。)
public int foo(boolean f) {
  final int i = f ? 100: 200;← 誤変更のリスクが解消
  //ここで i を変更しようとするとコンパイルエラー
  // i を 使う
}
また、上のサンプルコードでも明らかなように、「一時変数の宣言箇所は、使用する箇所のギリギリにまで近づけるべき」と言うプラクティスについても、三項演算子の方がより準拠している。

★ 一時変数が少なくて済む
三項演算子はもちろん演算子だから、式を書ける所ならば普通に使えるので、わざわざ作業用の一時変数を使わないで済む場合がある。
※一時変数の使用と不使用とでどちらが望ましいかなんて解説は省略。
※『リファクタリング』に「説明用変数の導入」という一時変数を増やす事になる小技が載っているが、それとは別の話
public void Foo(bool f)// if 文版
{
  string arg;
  if (f)
  {
    arg = "one"; 
  }
  else
  {
    arg = "two"; 
  }
  Bar(arg);//作業用の一時変数にわざわざ入れる羽目になる。
}
public void Foo(bool f)// 三項演算子版
{
    Bar(f ? "a" : "b");//式なので普通に使える。一時変数不要。
}

★ 重複コードを解消できる
上の どちらのFoo()も、条件分岐/条件演算を 別のメソッド Baz() に移して値をすぐに return させるようにすると、共にBar(Baz(f))という形に置き換えることができるが、それでも、まだ微妙な重複が残る。
public void Foo(bool f)
{
    Bar(Baz(f));
}
public string Baz(bool f)// if 文版
{
  if (f)
  {
    return "a";
  }
  else
  {
    return "b";
  }
}
public string Baz(bool f)// 三項演算子版
{
  return f ? "a" : "b";
}
実務上は、このreturn の重複についてまでも、Code Smell と捉えて、厳しく除去するなんて事はあまり無いが、例えば Baz()から値を返す前に何かの書式化を施すような変更を想定すると、これだって立派な重複コードだと言う事が分かる。目くじらを立てる事もないほどではないが、無ければ無いに越した事は無い。

★ 不要なブロックを減らせる
ブロックが多い(深い)のと少ない(浅い)のでは、少ない方に決まっているという普通の話。(自明のように見えるが、実はプログラマの中にはブロックをどんどん深くして悦に入る人もたまにいる。これ以上くどい説明もアレなので省略するが・・・)
コードブロックに関して突き詰めていくと、ブロックそのものが、長過ぎるメソッド/一時変数の濫用/重複コード/スパゲティコード/オブジェクト指向を無視した手続き型ロジックやらの温床でもあり元凶でもあるように見えてくる。他のトレードオフも考慮した上で、できるだけ式かメソッド呼び出しに変えてしまった方が、将来的にも安全なコードになる。

三項演算子を「使うべき」理由は、こんなところか・・・
続いて、よくある三項演算子反対の意見に反論してみる。

== == == == == ==
■ 三項演算子否定論への異議

★三項演算子は難しいから禁止すべき
そもそも「難しいか否か」なんて主観的判断が、合理的評価基準として妥当なのか疑問だが、差し当たりこれを認めるとして、それならば他の言語要素に関しても三項演算子より難しいものは否定してしまうのかという話になる。LINQ はどうか?ラムダ式はどうか?ジェネリクスは簡単か?

何かの言語要素を難しいと感じた誰かさんが(難しさを認識する事自体は望ましい事だが)、それを一律に禁じてしまうような事で、言語という道具と、それを操るプロフェッショナルから、投下したコストに対する効用を最大限に引き出す事が本当に可能なのか疑わしい。ちゃんと分かって、禁止しているのだろうか?むしろ、その禁則さえなければ得られたはずの利益を捨ててしまっていないか?

また「平均的プログラマの技術水準」なんて怪しい設定を持ち出して、三項演算子は無理なんて主張する人も多いが、どこに根拠あるんだろう?というか、
(isNegative ? -1 : 1) * absoluteValue
の意味が分からない人が、更に高度な他の文法要素を使いこなしたり、あるいはテスト駆動開発でモックテストを書いたりできる訳がない。

「三項演算子ができないレベルで妥協した方が、人材調達が容易」なんて言い分もあるようだが、それって「我々のスタイルは、基礎的な文法要素も使えない、最底辺PGによる人海戦術です」なんて言うのと同義なわけだけど、マジでそんなので良いのかな。三項演算子どころではない大問題だと思うんだが・・・

★ 三項演算子は読みにくいから禁止
三項演算子の方が読みやすいと言う人もいるし、どっちでも変わらないという人もいて、結局、単なる主観なわけで、フォーマルな規約の根拠としては元々ふさわしくない。

あと、読みにくさの話になると、ことさら読みにくくした三項演算子コードのサンプルだけを引き合いに出して「ほら、こんなに読みづらい」なんて言う人が必ず出て来るけど、そういうのはスルー。

★ 三項演算子はミスを生じやすいから禁止
自然な対策としては、作業ミスを誘発しやすい箇所を識別した上で、括弧付けの規約などで可読性を確保すればいいのであって、三項演算子そのものの禁止にはならないはず。これについても、数ある言語要素の中でなぜ三項演算子だけが槍玉に挙げられるのか分からんが。
Sun のJava規約みたいに 2項演算子を含む条件部を括弧でくくるなど

★ 三項演算子が嫌いだから禁止
三項演算子を使う理由を「好きだから」という情緒によってしか説明できない人と同じくらい、知的作業に向いていない。よって、この手の輩はコーディング規約策定には関与すべきでない。


なーんて、なぜか書いているうちにエキサイトしてきて、文章にトゲが入ってくる・・・
やはり三項演算子談義には、何か人の攻撃性を刺激するような魔物が住んでいるのか・・・

2009年11月4日水曜日

Java 1.4↑の assert /Eclipse/JUnit/Webアプリ

Java には 1.4からassert があって、これがなかなか良いものだけど、活用している現場をあまり見かけない。

MFC プログラマ出身者なら ASSERT マクロからの類推で、すぐに有り難味が分かるだろうけど、生粋の Java 現場では意外と知られていなかったりする。

普及しない理由として、javac コマンドに -source 1.4 を付けて、java コマンドに -ea を付ければ assert が効くという事を知っているだけでは、Eclipse 等の IDE 開発での場合にやり方が自明でなく導入しにくいという事もある気がする。

というわけで、以下、Eclipse 上で JUnit と Webアプリとして実行するときの、ちょっとしたTips。

====

Foo というクラスの execute() メソッドを不用意に呼んでしまったというシナリオで、コード的には、以下のように常に assert 失敗するようにした。
public class Foo {
   public String execute() {
       assert false: "assertion test";
       ・・・

◆ JUnit の場合

[Run Configurations...]から、[VM arguments] に-eaを指定する。設定は一度だけでOK。 実行すると、AssertionError の発生がちゃんと JUnit ビューに表示される。

◆ Web アプリの場合

下図のように[Run Configurations...]から、[VM arguments] に -ea を追加で指定する。 実行すると、ちゃんと AssertionError が上がってきて、Console ビューにスタックトレースされたのが見える。(ただし Servlet で AssertionError をもみ消してしまうコードがあると、当然あまり効果が無いので、そこは要注意。)

こんな感じで、開発中は常時 -ea を効かせておくようにすると、デグレ止めのセーフティネットとして役に立つ。特に人の出入りがあるプロジェクトで有効。もちろん、JUnit との併用が望ましい。

普及しない理由の残りは、どういう基準で assertion を書けばいいのか分からないという事もあるかもしれない。これは分かる人だけが assertion を書けばいいという方針で、おそらく十分。無理にガイドラインを作ってチームに強制するのは、費用対効果が余り良くない。

他の開発メンバに守ってもらうのは、ユニットテストやアプリの実行時に必ず -ea オプションを効かせてもらうという一点だけで良い。各自のコードが 既存の assertion に抵触した場合に、即座に分かるようなればそれだけで効果的だし、有用性が分かれば他のメンバも assertion を書くように、だんだんなってくる。