<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7701765455905567301</id><updated>2012-01-08T02:30:05.271+09:00</updated><category term='WebService'/><category term='workflow'/><category term='news'/><category term='ESB'/><category term='OCEB'/><category term='legacy language'/><category term='SOA'/><category term='Ajax'/><category term='本'/><category term='PM'/><category term='WF'/><category term='Scala'/><category term='Drools'/><category term='agile'/><category term='DSL'/><category term='RDB'/><category term='haskell'/><category term='ORM'/><category term='営業'/><category term='java webapp'/><category term='開発インフラ'/><category term='performance'/><category term='WS-*'/><category term='anti patterns'/><category term='品質'/><category term='OSGi'/><category term='Java EE'/><category term='english'/><category term='usecase'/><category term='patterns'/><category term='ソフトウェア工学'/><category term='smalltalk'/><category term='UnitTest'/><category term='XML'/><category term='BPM'/><category term='algorithm'/><category term='Java'/><category term='BPEL'/><category term='非RDB'/><category term='idiom'/><category term='DI'/><category term='other languages'/><category term='C#'/><category term='logic programming'/><category term='AspectJ'/><category term='DomainModel'/><category term='資格'/><category term='groovy'/><category term='雑学'/><category term='Eclipse'/><category term='業界'/><category term='BPMN'/><category term='article'/><category term='MIDI'/><category term='Erlang'/><title type='text'>yasuabe blog</title><subtitle type='html'>調布在住の技術者がシステム開発を面白がるブログ</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default?start-index=101&amp;max-results=100'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>311</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-1814466048380866396</id><published>2012-01-07T20:40:00.001+09:00</published><updated>2012-01-07T20:40:54.841+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Haskell で平面ルービックキューブ</title><content type='html'>&lt;p&gt;急に、ルービックキューブをプログラムで解いてみたい衝動にかられたが、手元にブツが無い。近所のコンビニにも無かったので、作ってみることにした。&lt;/p&gt;&lt;p&gt;以下のような方針&lt;ul&gt;&lt;li&gt;極力シンプルに。本物に近い操作感とか立体性とか別にいらないので、二次元の図形で表現する。&lt;/li&gt;&lt;li&gt;中央の小正方形は動かさない事にする。&lt;/li&gt;&lt;li&gt;操作はテキストボックスへの入力とする。色を表す文字一文字により、その色が中央となる面の回転を表し、小文字なら時計回り、大文字ならその逆とする。&lt;/li&gt;&lt;li&gt;現在、テキストボックスに入力されている文字列全体が反映された結果を描画する。&lt;/li&gt;&lt;li&gt;図形は中央に描画する。&lt;/li&gt;&lt;li&gt;Haskell でやってみる&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;結果から示すと、以下が実際の様子。まず初期表示&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-2JUjJgpkthk/Twgpuowu4NI/AAAAAAAAATo/Edu5VBoEIWg/s1600/rcube-state0.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="208" width="320" src="http://3.bp.blogspot.com/-2JUjJgpkthk/Twgpuowu4NI/AAAAAAAAATo/Edu5VBoEIWg/s320/rcube-state0.png" /&gt;&lt;/a&gt;&lt;br/&gt;初期表示&lt;/div&gt;&lt;/p&gt;&lt;p&gt;赤い面を時計回りに2回、青い面を時計回りに1回、赤い面を反時計まわりに1回、青い面を反時計まわりに1回、それぞれ90度回転させた結果。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-MsW7RJ-g7ok/Twgpuv1NIZI/AAAAAAAAAT4/7TCObS6wwdo/s1600/rcube-rrbRB.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="208" width="320" src="http://2.bp.blogspot.com/-MsW7RJ-g7ok/Twgpuv1NIZI/AAAAAAAAAT4/7TCObS6wwdo/s320/rcube-rrbRB.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;コードは以下のような感じになる。&lt;pre class="prettyprint"&gt;module Main where&lt;br /&gt;&lt;br /&gt;import Graphics.UI.Gtk&lt;br /&gt;import Graphics.UI.Gtk.Glade&lt;br /&gt;import Graphics.UI.Gtk.Gdk.GC&lt;br /&gt;import Graphics.UI.Gtk.Gdk.Drawable&lt;br /&gt;import Graphics.UI.Gtk.Gdk.Events as Evt&lt;br /&gt;import Data.IORef&lt;br /&gt;&lt;br /&gt;--図形&lt;br /&gt;data SquareColor = G|R|W|Y|O|B&lt;br /&gt;color G = Color 0x0000 0xE000 0x0000&lt;br /&gt;color R = Color 0xE000 0x0000 0x0000&lt;br /&gt;color W = Color 0xFFFF 0xFFFF 0xFFFF&lt;br /&gt;color Y = Color 0xFFFF 0xFFFF 0x0000&lt;br /&gt;color O = Color 0xF000 0x5000 0x0000&lt;br /&gt;color B = Color 0x0000 0x0000 0xD000&lt;br /&gt;&lt;br /&gt;initialState = map (replicate 9) [G,R,W,Y,O,B]&lt;br /&gt;&lt;br /&gt;v60    = (18, -10)&lt;br /&gt;v120   = (18,  10)&lt;br /&gt;v180   = (0,   21)&lt;br /&gt;angles = [[(-108,-30), v120,v180],&lt;br /&gt;          [(-108,-30), v60, v120],&lt;br /&gt;          [(-54,   0), v60, v180],&lt;br /&gt;          [(0,   -30), v60, v180],&lt;br /&gt;          [(0,    33), v60, v120],&lt;br /&gt;          [(54,  -60), v120,v180]]&lt;br /&gt;allParas = concatMap createParas angles &lt;br /&gt;createParas v = map toPara $&lt;br /&gt;    map (\n -&amp;gt; dupV v n) [0..2] &amp;gt;&amp;gt;= (\x -&amp;gt; map (\n -&amp;gt;dupH x n) [0..2])&lt;br /&gt;toPara = (\[(ox,oy), (x1,y1), (x2,y2)] -&amp;gt;&lt;br /&gt;  [(ox,oy), (ox+x1-1, oy+y1-1),&lt;br /&gt;  (ox+x1+x2-2, oy+y1+y2-2),(ox+x2-1, oy+y2-1)])&lt;br /&gt;dupH = (\[(ox,oy), v1@(x1,y1), v2] n -&amp;gt; [(ox+x1*n, oy+y1*n), v1, v2])&lt;br /&gt;dupV = (\[(ox,oy), v1, v2@(x2,y2)] n -&amp;gt; [(ox+x2*n, oy+y2*n), v1, v2])&lt;br /&gt;&lt;br /&gt;centering _ [] = []&lt;br /&gt;centering size (angle: angles) =&lt;br /&gt;  (map (centeringPoint size) angle): (centering size angles)&lt;br /&gt;&lt;br /&gt;centeringPoint (w, h) (x, y) = (x + (div w 2), y + (div h 2))&lt;br /&gt;&lt;br /&gt;--ウィンドウ操作&lt;br /&gt;main = do&lt;br /&gt;    initGUI&lt;br /&gt;    surfaceIORef &amp;lt;- newIORef initialState&lt;br /&gt;    Just xml     &amp;lt;- xmlNew "rcube.glade"&lt;br /&gt;&lt;br /&gt;    window       &amp;lt;- xmlGetWidget xml castToWindow "window1"&lt;br /&gt;    onDestroy window mainQuit&lt;br /&gt;&lt;br /&gt;    drawingArea  &amp;lt;- xmlGetWidget xml castToDrawingArea "drawingarea1"&lt;br /&gt;    onExposeRect drawingArea (const $ do&lt;br /&gt;        dw       &amp;lt;- widgetGetDrawWindow drawingArea&lt;br /&gt;        gc       &amp;lt;- gcNew dw&lt;br /&gt;        surface  &amp;lt;- readIORef surfaceIORef&lt;br /&gt;        size     &amp;lt;- widgetGetSize drawingArea&lt;br /&gt;        drawCube dw gc size surface)&lt;br /&gt;&lt;br /&gt;    entry        &amp;lt;- xmlGetWidget xml castToEntry "entry1"&lt;br /&gt;    onEditableChanged entry $ do &lt;br /&gt;        n &amp;lt;- get entry entryText&lt;br /&gt;        writeIORef surfaceIORef $ rotateAll initialState n&lt;br /&gt;        widgetQueueDraw drawingArea&lt;br /&gt;&lt;br /&gt;    widgetShowAll window&lt;br /&gt;    mainGUI&lt;br /&gt;  where&lt;br /&gt;    rotateAll p [] = p&lt;br /&gt;    rotateAll p (x:xs) = rotateAll (rotate p x) xs&lt;br /&gt; &lt;br /&gt;    drawCube d g size x = do&lt;br /&gt;      drawParas d g (foldl (++) [] x) $ centering size allParas&lt;br /&gt;    drawParas d g _ [] = return ()&lt;br /&gt;    drawParas d g (x:xs) (p: ps) = do&lt;br /&gt;      gcSetValues g $ newGCValues { foreground = color x }&lt;br /&gt;      drawPolygon d g True p&lt;br /&gt;      drawParas d g xs ps&lt;br /&gt;&lt;br /&gt;-- 回転操作&lt;br /&gt;g2r [g,r,w,y,o,b] = [r6 o,r3 g,r3 w,r3 r,y,   r9 b]&lt;br /&gt;r2g [o,g,w,r,y,b] = [r9 g,r9 r,r9 w,y,   r6 o,r3 b]&lt;br /&gt;w2r [g,r,w,y,o,b] = [r9 g,w,   r3 o,r3 y,r3 b,r6 r] &lt;br /&gt;r2w [g,w,o,y,b,r] = [r3 g,r6 r,w,   r9 y,r9 o,r9 b] &lt;br /&gt;y2r [g,r,w,y,o,b] = [r9 w,y,   o,   r3 b,r3 g,r9 r]&lt;br /&gt;r2y [w,y,o,b,g,r] = [r9 g,r3 r,r3 w,y,   o,   r9 b]&lt;br /&gt;o2r [g,r,w,y,o,b] = [r6 b,r6 o,r6 y,r6 w,r6 r,r6 g]&lt;br /&gt;r2o [b,o,y,w,r,g] = [r6 g,r6 r,r6 w,r6 y,r6 o,r6 b]&lt;br /&gt;b2r [g,r,w,y,o,b] = [r9 y,b,   r9 o,r3 g,r3 w,r]&lt;br /&gt;r2b [y,b,o,g,w,r] = [r9 g,r,   r9 w,r3 y,r3 o,b]&lt;br /&gt;rotate [(g1:g2:g3:gs), [r1,r2,r3,r4,r5,r6,r7,r8,r9],&lt;br /&gt;        (w1:w2:w3:ws), (y1:y2:y3:ys),&lt;br /&gt;        o,              (b1:b2:b3:bs)] 'r' =&lt;br /&gt;       [(w1:w2:w3:gs), [r7,r4,r1,r8,r5,r2,r9,r6,r3],&lt;br /&gt;        (y1:y2:y3:ws), (b1:b2:b3:ys),&lt;br /&gt;        o,              (g1:g2:g3:bs)]&lt;br /&gt;rotate [(g1:g2:g3:gs), [r1,r2,r3,r4,r5,r6,r7,r8,r9],&lt;br /&gt;        (w1:w2:w3:ws), (y1:y2:y3:ys),&lt;br /&gt;        o,             (b1:b2:b3:bs)] 'R' =&lt;br /&gt;       [(b1:b2:b3:gs), [r3,r6,r9,r2,r5,r8,r1,r4,r7],&lt;br /&gt;        (g1:g2:g3:ws), (w1:w2:w3:ys),&lt;br /&gt;        o,             (y1:y2:y3:bs)]&lt;br /&gt;rotate p 'g' =r2g (rotate (g2r p) 'r')&lt;br /&gt;rotate p 'G' =r2g (rotate (g2r p) 'R')&lt;br /&gt;rotate p 'w' =r2w (rotate (w2r p) 'r')&lt;br /&gt;rotate p 'W' =r2w (rotate (w2r p) 'R')&lt;br /&gt;rotate p 'y' =r2y (rotate (y2r p) 'r')&lt;br /&gt;rotate p 'Y' =r2y (rotate (y2r p) 'R')&lt;br /&gt;rotate p 'o' =r2o (rotate (o2r p) 'r')&lt;br /&gt;rotate p 'O' =r2o (rotate (o2r p) 'R')&lt;br /&gt;rotate p 'b' =r2b (rotate (b2r p) 'r')&lt;br /&gt;rotate p 'B' =r2b (rotate (b2r p) 'R')&lt;br /&gt;rotate p _ = p&lt;br /&gt;r3 [s1,s2,s3,s4,s5,s6,s7,s8,s9] = [s7,s4,s1,s8,s5,s2,s9,s6,s3]&lt;br /&gt;r6 x = r3 $ r3 x&lt;br /&gt;r9 x = r6 $ r3 x&lt;/pre&gt;&lt;p&gt;画面定義は、GtkWindow に GtkVBox を置いて、その上側に GtkDrawingArea、下側に GtkEntryを置いたものを、Glade 3.8.1 で適当に作っておく。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;一応、ルービックキューブにはなったが、遊ぶにはシャッフルする機能を追加する必要がある。あと、そもそもの目的だった、解く方のコードも書こうと思うのだけど、なんかここまでの作業で変にコーディング欲が充足されてしまって、当初のモチベーションが既に半減してしまった。なんだかなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-1814466048380866396?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/1814466048380866396/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2012/01/haskell_07.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1814466048380866396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1814466048380866396'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2012/01/haskell_07.html' title='Haskell で平面ルービックキューブ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-2JUjJgpkthk/Twgpuowu4NI/AAAAAAAAATo/Edu5VBoEIWg/s72-c/rcube-state0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8607670901971390764</id><published>2012-01-05T00:27:00.000+09:00</published><updated>2012-01-05T20:59:15.097+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>s/UT/UnitTest/</title><content type='html'>&lt;p&gt;このブログで今まで UnitTest について書いた投稿には、「UT」というラベルを付けていたが、これを今日、「UnitTest」に付け替えた。&lt;/p&gt;&lt;p&gt;最初は何の気なしに「UT」としてしまっていたけど、最近は、なんだか見れば見るほどウォーターフォール文化における単体テストを表す略号に見えてきて、本来語りたい事とのズレが大きく感じられるようになってきた。&lt;/p&gt;&lt;p&gt;ちなみに本文では、だいたい UnitTest とパスカルケースで書いてきたつもり。これは、ウォータフォールの単体テストと区別するためであると同時に、&lt;a href="http://c2.com/cgi/wiki?UnitTest"&gt;本家 wiki&lt;/a&gt; の仕様に合わせてリスペクトを表明しているからでもあったりする。&lt;/p&gt;&lt;p&gt;ところで、ウォーターフォール色が強い組織・現場では、未だに「実装フェーズ」の直後に「単体テストフェーズ」を設けて、そこで初めて JUnitコード を書き始めるような残念な開発が、特に反省されることもなく日々実践されている。&lt;/p&gt;&lt;p&gt;そういう現場でも、理論的には後付けテストはダメなんだと言う事が、何かの拍子に認知され始めて、一応名目上は「実装・UTフェーズ」みたいに、前後関係をボヤかした感じになったりするのだけど、いかんせんプログラマの意識が「テストの事なんか後で考える」のままだから、実質的には何も変わらないし進歩もない。&lt;/p&gt;&lt;p&gt;泳ぎの真似を陸上でどれだけやったところで泳げるようになんかならないように、後付けテストなんか何年やってもテスト・ファーストで書けるようには全然ならない。&lt;/p&gt;&lt;p&gt;だからそろそろ、現場の開発チームで指導的な立場にある人は、「できればなるべく差し支えない範囲でTDD推奨」みたいな感じではなく、そろそろ「TDD必須」って宣言すべきだと思う。&lt;/p&gt;&lt;p&gt;本当に、一度できるようになったら、というか、できるようになってみないと「テストを先に書く」方がその逆よりも、工数、品質、仕事の面白さなど、どれをとっても格段に優れているという認識は成立しないのだろうと、つくづく思う。&lt;/p&gt;&lt;p&gt;とはいっても、「やってみればテストファーストの方が速い事が分かるよ」なんてやんわりと言って聞かせたところで、どうせ一向に浸透しないのはもう分かった。つう事は、山本五十六も「やってみせ、いって聞かせて、させてみて、 褒めてやらねば人は動かじ」なんて言っているとおり、まずは横に座って実演するところから始めなければならない事になるらしい（やっぱ結局XPに戻ってくる事になるのか…）。&lt;/p&gt;&lt;p&gt;高跳びでも、背中を下に向けた方がその逆より高く跳べるという事に、フォスベリーが記録を出すまでは、だれも気づかなかった。だから、まず「やってみせ」から始めないとダメなのだろう。やってみせる事なしに「言って聞かせて」も結局効果がないし、「させてみせ」も、結局ちょっと目を離したスキにうやむやになってしまう。&lt;/p&gt;&lt;p&gt;・・・つう事を考えているのだけど、本当に残念で仕方が無いが、今の現場では直接コードを書いて実演できるような立ち位置ではなかったりする。次の現場こそは、まずは絶対に、自分で「やってみせ」るところから始められる、実装メインのロールでプロジェクトに参画したい。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8607670901971390764?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8607670901971390764/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2012/01/sutunittest.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8607670901971390764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8607670901971390764'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2012/01/sutunittest.html' title='s/UT/UnitTest/'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2435878351314763435</id><published>2012-01-01T07:09:00.001+09:00</published><updated>2012-01-01T07:16:50.864+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Haskell でソケット通信をやってみる</title><content type='html'>&lt;p&gt;Haskell で ソケットを使ったクライアント-サーバ通信をやってみる。&lt;/p&gt;&lt;p&gt;Haskell を使ったネットワーク・プログラミングの入り口が分かればいいので、クライアントから受け取った文字列をひっくり返して返すだけの、簡単なお題とする。&lt;/p&gt;まず、サーバはこんな感じ。&lt;pre class="prettyprint"&gt;import Network&lt;br /&gt;import System.IO &lt;br /&gt;&lt;br /&gt;main :: IO ()&lt;br /&gt;main = withSocketsDo $ do &lt;br /&gt;    hSetBuffering stdout NoBuffering&lt;br /&gt;    server `catch` (const $ putStrLn "Exception caught.")&lt;br /&gt;    putStrLn "Connection closed."&lt;br /&gt;&lt;br /&gt;server :: IO ()&lt;br /&gt;server = do&lt;br /&gt;    sock &amp;lt;- listenOn (PortNumber 8001)&lt;br /&gt;    repeats (receive sock)&lt;br /&gt;    sClose sock&lt;br /&gt;&lt;br /&gt;repeats :: Monad m =&amp;gt; m Bool -&amp;gt; m () &lt;br /&gt;repeats x =&lt;br /&gt;    x &amp;gt;&amp;gt;= (\x' -&amp;gt; if x' then (return ()) else repeats x)&lt;br /&gt;&lt;br /&gt;receive :: Socket -&amp;gt; IO Bool&lt;br /&gt;receive sock = do&lt;br /&gt;    (h,host,port) &amp;lt;- accept sock&lt;br /&gt;    hSetBuffering h LineBuffering&lt;br /&gt;    msg &amp;lt;- hGetLine h           &lt;br /&gt;    putStrLn msg &lt;br /&gt;    hPutStrLn h $ reverse msg &lt;br /&gt;    return $ null msg&lt;/pre&gt;クライアントはこんな感じ。&lt;pre class="prettyprint"&gt;import Network&lt;br /&gt;import System.IO &lt;br /&gt;&lt;br /&gt;sendMessage msg = withSocketsDo $ do &lt;br /&gt;        hSetBuffering stdout NoBuffering &lt;br /&gt;        h &lt;- connectTo "127.0.0.1" (PortNumber 8001)&lt;br /&gt;        hSetBuffering h LineBuffering&lt;br /&gt;        hPutStrLn h msg&lt;br /&gt;        hGetLine h &gt;&gt;= putStrLn&lt;br /&gt;        hClose h&lt;/pre&gt;実行は GHCi でやってみる。&lt;br/&gt;以下、サーバ側&lt;pre style="background-color:white;color:black;line-height:132%;"&gt;ghci&gt; :load server.hs&lt;br /&gt;[1 of 1] Compiling Main             ( server.hs, interpreted )&lt;br /&gt;Ok, modules loaded: Main.&lt;br /&gt;ghci&gt; main&lt;br /&gt;Loading package bytestring-0.9.1.10 ... linking ... done.&lt;br /&gt; ・・・略・・・&lt;br /&gt;Loading package network-2.3.0.7 ... linking ... done.&lt;br /&gt;hello&lt;br /&gt;1234&lt;br /&gt;&lt;br /&gt;Connection closed.&lt;br /&gt;ghci&gt; &lt;/pre&gt;以下、クライアント側&lt;pre style="background-color:white;color:black;line-height:132%;"&gt;ghci&gt; :load client.hs&lt;br /&gt;[1 of 1] Compiling Main             ( client.hs, interpreted )&lt;br /&gt;Ok, modules loaded: Main.&lt;br /&gt;ghci&gt; sendMessage "hello"&lt;br /&gt;Loading package bytestring-0.9.1.10 ... linking ... done.&lt;br /&gt; ・・・略・・・&lt;br /&gt;Loading package network-2.3.0.7 ... linking ... done.&lt;br /&gt;olleh&lt;br /&gt;ghci&gt; sendMessage "1234"&lt;br /&gt;4321&lt;br /&gt;ghci&gt; sendMessage ""&lt;br /&gt;ghci&gt; &lt;/pre&gt;&lt;p&gt;思ったより難しくない。次は、マルチスレッド化かなあ。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2435878351314763435?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2435878351314763435/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2012/01/haskell.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2435878351314763435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2435878351314763435'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2012/01/haskell.html' title='Haskell でソケット通信をやってみる'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6769758527984503833</id><published>2011-12-22T00:12:00.000+09:00</published><updated>2011-12-22T00:37:43.099+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PM'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>WYDKYDK が読めたよ！ ﾜｰｲヾ(´ρ`)ﾉ゛ﾜｰｲ</title><content type='html'>&lt;p&gt;Alistair Cockburn の本に出てくる変な綴りの言葉。意味は分かるけどなんて発音するのか、ずっと分からなかったけど、何の気に無しにググってたら見付けた。&lt;/p&gt;&lt;p&gt;なんかソフトウェア開発とは全然関係ない、&lt;a href="http://www.designcommunity.com/pipermail/nlc/2011-January/000717.html"&gt;オレゴン州の自治会か何かの議事録らしき文書&lt;/a&gt;だけど、WYDKYDK ("&lt;span style="color:white;"&gt;wid-kee-dik&lt;/span&gt;")とある。カタカナにすると&lt;span style="color:white;"&gt;ウィドキーディク&lt;/span&gt;みたいな感じだろうか。&lt;/p&gt;綴りが珍しいのは略語だからで、もとはこんな文。&lt;div style="border:1px dashed grey;padding:5px 5px 2px 15px;margin:0px 0px 10px 0px;"&gt;What you don't know you don't know&lt;/div&gt;&lt;p&gt;簡単な英語だけど、構文が分からない人が意外と多い。順を追って見てみると、&lt;br/&gt;&lt;div style="border:1px dashed grey;padding:2px 5px 1px 15px;margin:0px 0px 10px 0px;"&gt;You don't know it.&lt;br/&gt;あなたはそれを知らない&lt;/div&gt; ↓&lt;div style="border:1px dashed grey;padding:2px 5px 1px 15px;margin:0px 0px 10px 0px;"&gt;What you don't know.&lt;br/&gt;あなたが知らないもの&lt;/div&gt; ↓&lt;div style="border:1px dashed grey;padding:2px 5px 1px 15px;margin:0px 0px 10px 0px;"&gt;You don't know you don't know it.&lt;br/&gt;あなたはそれを知らないという事を知らない&lt;/div&gt; ↓&lt;div style="border:1px dashed grey;padding:2px 5px 1px 15px;margin:0px 0px 10px 0px;"&gt;What you don't know you don't know.&lt;br/&gt;あなたが知らないという事を知らないもの&lt;/div&gt;といった感じで、入れ子になってたりして、プログラマには親和性が高い気がするんだが。&lt;/p&gt;&lt;p&gt;ところで、現場ではこの WYDKYDK への認識が足りない人が、例えば WBS を作ったり作らせたりすると、困った事になる。&lt;/p&gt;&lt;p&gt;「これだけ詳細化したんだから、見積りは正確なはずだ」なんて思考様式なんだけど、そもそも認識されていない事を詳細化しようもないし、予測に組み込みようもない。&lt;/p&gt;&lt;p&gt;正解は、何らかの形で現実に実行してみて「知らない事」を「知らなかった事」に変えていく事なんだけど、下手な人はこの当たり前の事ができず、日程にバッファを組み込むといった程度の、稚拙な手に走ってしまう。まあ現場ごとの文化とか、プロジェクトごとの事情とかもあるけどね。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6769758527984503833?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6769758527984503833/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/wydkydk.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6769758527984503833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6769758527984503833'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/wydkydk.html' title='WYDKYDK が読めたよ！ ﾜｰｲヾ(´ρ`)ﾉ゛ﾜｰｲ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3609883903625165202</id><published>2011-12-21T00:20:00.000+09:00</published><updated>2011-12-22T00:34:04.555+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><category scheme='http://www.blogger.com/atom/ns#' term='雑学'/><title type='text'>小事の思案と割れ窓理論</title><content type='html'>&lt;p&gt;&lt;span style="color:white;"&gt;葉隠&lt;/span&gt;と言えば、「武士道といふは死ぬ事と見付けたり…別に仔細なし。胸すわって進むなり。」で有名だけど、正直、自分みたいな「すくたれもの」には難しい。&lt;/p&gt;&lt;p&gt;だけど実は葉隠には、そんなムリなやつばかりじゃなくて、普通に実践的なアドバイスも結構ある。&lt;/p&gt;&lt;p style="font-size:larger;color:white;"&gt;『大事の思案は軽くすべし。／小事の思案は重くすべし。』&lt;/p&gt;&lt;p&gt;これについて自分は、やっぱり開発者で飯を食っているせいか、前半を&lt;span style="color:white;"&gt;リスク管理&lt;/span&gt;の問題、後半を&lt;span style="color:white;"&gt;品質管理&lt;/span&gt;の問題と捉えてしまう。&lt;/p&gt;&lt;p&gt;前半の『大事の思案』がなぜ軽いかについては、非常にクリティカルな事態に関しては、いざというときに判断に迷って対応が遅れたりしないように、普段から方針を定めておいて、即断即決できるように備えておくべきだという解釈になる。&lt;/p&gt;&lt;p&gt;後半の『小事の思案』がなぜ重いかについては、三島由紀夫が葉隠入門の中で、アリの穴から堤防が崩れるように、瑣末なことを軽んじる事によって生活の体系や重大な思想までもが台無しになると解説している。&lt;/p&gt;&lt;p&gt;で、もちろん前半も後半もどちらも大事なんだけど、どちらかというと自分なんかには後半の方が、より切実にピンと来る。（管理の比重が大きい人は前者かもしれない。）&lt;/p&gt;&lt;p&gt;例えば、コーディング規約なんかみたいなものでも、「ぎりぎり読めりゃいいじゃん」みたいに適当にしないで、きっちり律儀に守ってかないといけない。と自分は思う。&lt;/p&gt;&lt;p&gt;そこを疎かにするから、規約違反の放置-&gt;-&gt;内部品質の低下-&gt;-&gt;外部品質の低下-&gt;-&gt;製品品質の低下 ってな感じで、結局、また地獄になってくんじゃないかと。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;で、この小さい事こそ大事ってのを、別角度から現代風に理論化したのが、&lt;span style="color:white;"&gt;割れ窓理論&lt;/span&gt;だと思う。&lt;p&gt;&lt;p&gt;一般には、ジュリアーニ市長の時代にニューヨーク市が治安を回復したときにベースになった理論として有名なアレだけど、&lt;a href="http://ja.wikipedia.org/wiki/%E5%89%B2%E3%82%8C%E7%AA%93%E7%90%86%E8%AB%96"&gt;Wikipedia&lt;/a&gt; によるとこうなる&lt;div style="color:white;"&gt;「建物の窓が壊れているのを放置すると、誰も注意を払っていないという象徴になり、やがて他の窓もまもなく全て壊される」&lt;/div&gt;&lt;br/&gt;ささいに見える Duplicate code の放置が、コピペだらけの巨大な糞コードの山に繋がっていくという、まあ、ありがちなあれと同じじゃないだろうか。&lt;/p&gt;&lt;p&gt;で、この割れ窓理論をベースにした政策が「&lt;span style="color:white;"&gt;ゼロトレランス&lt;/span&gt;」だけど、開発現場に当てはめてみると、さしずめ&lt;a href="http://c2.com/cgi/wiki?RefactorMercilessly"&gt; Refactoring Mercilessly&lt;/a&gt; といったところか。&lt;/p&gt;&lt;p&gt;なんて事を考えていると、例えば、「途中return は是か非か」みたいな、一見不毛でアホらしい事についてムキになって議論するのも、けっこう大事というか、度を越さない範囲ならむしろ健全だとも思えてくる。もちろん自分もわりとムキになる方だ。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3609883903625165202?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3609883903625165202/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3609883903625165202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3609883903625165202'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/blog-post.html' title='小事の思案と割れ窓理論'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2042262392508486968</id><published>2011-12-20T01:45:00.001+09:00</published><updated>2011-12-21T00:45:26.086+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DI'/><title type='text'>Spring 3.1 の Cache Abstraction</title><content type='html'>&lt;p&gt;Spring 3.1 が GA になった。最後に Spring を触ったのは&lt;a href="http://yasutech.blogspot.com/2010/01/spring-30-rest.html"&gt;これを書いたとき&lt;/a&gt;だから、もう2年近く前になるけど、こんときは 3.0 が出た頃だった。あんまり進んでなかったのかも。&lt;/p&gt;&lt;p&gt;いろいろググってみると、キャッシュがどうかしたとか書いてあるので、寝る前にちょっと試してみる。&lt;/p&gt;&lt;pre class="prettyprint"&gt;package spring.trial1.ex1;&lt;br /&gt;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import org.springframework.cache.annotation.Cacheable;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;import org.springframework.context.support.ClassPathXmlApplicationContext;&lt;br /&gt;&lt;br /&gt;class Bar {&lt;br /&gt;   Map&amp;lt;Integer, String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;   {&lt;br /&gt;      map.put(1, "one");&lt;br /&gt;      map.put(2, "two");&lt;br /&gt;   }&lt;br /&gt;   @Cacheable("bar")&lt;br /&gt;   public String findString(int key) {&lt;br /&gt;      System.out.printf("findString(%d) called%n", key);&lt;br /&gt;      return map.get(key);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Foo {&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;   ApplicationContext ctx = new ClassPathXmlApplicationContext(&lt;br /&gt;         "applicationContext.xml");&lt;br /&gt;   Bar bean = ctx.getBean(Bar.class);&lt;br /&gt;&lt;br /&gt;   System.out.println(bean.findString(1));&lt;br /&gt;   System.out.println(bean.findString(2));&lt;br /&gt;   System.out.println(bean.findString(3));&lt;br /&gt;   System.out.println(bean.findString(1));&lt;br /&gt;   System.out.println(bean.findString(2));&lt;br /&gt;   System.out.println(bean.findString(3));&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"&lt;br /&gt;  xmlns:p="http://www.springframework.org/schema/p"&lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&lt;br /&gt;                http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;cache:annotation-driven /&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"&amp;gt;&lt;br /&gt;    &amp;lt;property name="caches"&amp;gt;&lt;br /&gt;      &amp;lt;set&amp;gt;&lt;br /&gt;        &amp;lt;bean&lt;br /&gt;          class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"&lt;br /&gt;          p:name="bar" /&amp;gt;&lt;br /&gt;      &amp;lt;/set&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;  &amp;lt;/bean&amp;gt;&lt;br /&gt;  &amp;lt;bean id="bar" class="spring.trial1.ex1.Bar"/&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;/pre&gt;pom.xml の dependency に spring-context 3.1.0.RELEASE と、cglib 2.2.2 を指定して、ビルド→実行したら、以下のような結果が得られる。（既に Maven Central に入ってるらしく、特に repository を指定したり、ローカルリポジトリに入れたりとかしなくても、普通に 3.1 がダウンロードされる。）&lt;pre style="background-color:white;color:black;"&gt;&lt;br /&gt;findString(1) called&lt;br /&gt;one&lt;br /&gt;findString(2) called&lt;br /&gt;two&lt;br /&gt;findString(3) called&lt;br /&gt;null&lt;br /&gt;one&lt;br /&gt;two&lt;br /&gt;null&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;findString の 中身が呼ばれるのは最初だけで、2回め以降はキャッシュが使われているらしいのが分かる。&lt;/p&gt;&lt;p style="font-weight:bold;"&gt;■ 雑感&lt;/p&gt;&lt;p&gt;&lt;a href="http://yasutech.blogspot.com/2010/01/spring-30jsr-330javaconfig.html"&gt;JavaConfig/JSR-330&lt;/a&gt; で xml を書かずに済むようになったと思ってたけど、この &amp;lt;cache:annotation-driven&amp;gt; に関しては、やり方が分からない。&lt;br/&gt;&lt;br/&gt;仕方なく、昔ながらのapplicationContext.xml を書いてしまった。もしかすると、ちゃんとしたやり方があるのかもしれないけど、部分的にアノテーションで部分的にXMLみたいにマジでなるとしたら、結構イヤかも。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2042262392508486968?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2042262392508486968/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/spring-31-cache-abstraction.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2042262392508486968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2042262392508486968'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/spring-31-cache-abstraction.html' title='Spring 3.1 の Cache Abstraction'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6603842450466693628</id><published>2011-12-18T16:13:00.000+09:00</published><updated>2011-12-21T00:47:02.434+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>gtk2hs で落書きしてみる</title><content type='html'>&lt;p&gt;&lt;a href="http://yasutech.blogspot.com/2011/12/gtk2hs-glade.html"&gt;前回の書き込み&lt;/a&gt;で、gtk2hs の準備ができたので、もう一歩進めてみる。&lt;/p&gt;&lt;p&gt;10年以上前、Visual C++を使ってた頃、MFC のチュートリアルで Scribble というのがあった。これを、Haskell で試してみた。&lt;/p&gt;&lt;p&gt;ただし、MDI とか ドキュメントの保存とかは割愛して、とりあえず描画の API とマウスイベントのハンドリングだけを気にすることにした。&lt;/p&gt;&lt;p&gt;仕組みは簡単で、マウスボタンが押下されたときから放されるまでのマウスポインタの軌跡を記録し、ウィンドウ描画時に各点を線でつないでいくというもの。コードは以下のようになる。&lt;/p&gt;&lt;pre class="prettyprint"&gt;import qualified Graphics.UI.Gtk as G&lt;br /&gt;import Graphics.UI.Gtk.Gdk.GC&lt;br /&gt;import Graphics.UI.Gtk.Gdk.Events&lt;br /&gt;import Data.IORef&lt;br /&gt;import Graphics.UI.Gtk.Gdk.Drawable&lt;br /&gt;&lt;br /&gt;main = do&lt;br /&gt;    G.initGUI&lt;br /&gt;    w &amp;lt;- G.windowNew&lt;br /&gt;    G.onDestroy w G.mainQuit&lt;br /&gt;&lt;br /&gt;    da &amp;lt;- G.drawingAreaNew&lt;br /&gt;&lt;br /&gt;    isDrawingIORef &amp;lt;- newIORef False&lt;br /&gt;    figuresIORef   &amp;lt;- newIORef [[]]&lt;br /&gt;&lt;br /&gt;    G.onExposeRect da (const $ do dw &amp;lt;- G.widgetGetDrawWindow da&lt;br /&gt;                                  gc &amp;lt;- gcNew dw&lt;br /&gt;                                  f &amp;lt;- readIORef figuresIORef&lt;br /&gt;                                  drawFigure dw gc f)&lt;br /&gt;&lt;br /&gt;    G.onMotionNotify da True $ \Motion {eventX = x, eventY = y}-&amp;gt; do&lt;br /&gt;      isDrawing &amp;lt;- readIORef isDrawingIORef&lt;br /&gt;      case isDrawing of&lt;br /&gt;        True  -&amp;gt; do  modifyIORef figuresIORef (\f-&amp;gt;addPoint f x y)&lt;br /&gt;                     G.widgetQueueDraw da&lt;br /&gt;        _     -&amp;gt; return ()&lt;br /&gt;      return True&lt;br /&gt;  &lt;br /&gt;    G.onButtonPress da $ \Button {eventX = x, eventY = y}-&amp;gt; do&lt;br /&gt;      writeIORef isDrawingIORef True&lt;br /&gt;      modifyIORef figuresIORef (\f-&amp;gt;[point x y]: f)  &lt;br /&gt;      return True&lt;br /&gt;&lt;br /&gt;    G.onButtonRelease da $ \Button {eventX = x, eventY = y}-&amp;gt; do&lt;br /&gt;      writeIORef isDrawingIORef False&lt;br /&gt;      modifyIORef figuresIORef (\f-&amp;gt;addPoint f x y)&lt;br /&gt;      return True&lt;br /&gt;  &lt;br /&gt;    G.containerAdd w da&lt;br /&gt;    G.widgetShowAll w&lt;br /&gt;    G.mainGUI&lt;br /&gt;&lt;br /&gt;  where&lt;br /&gt;    point x y = (round x, round y)&lt;br /&gt;    addPoint figures x y = (point x y: head figures): tail figures&lt;br /&gt;    drawFigure _ _ [] = return ()&lt;br /&gt;    drawFigure d g (f:fs) = do {&lt;br /&gt;      G.drawLines d g f; drawFigure d g fs }&lt;/pre&gt;&lt;p&gt;Haskell 自体にまだ慣れていないので、いかにも未熟な感じだけど、イベント処理と描画の作法がなんとなく分かってきた。ネット上で API を調べる事にも、だんだん慣れてきた。&lt;/p&gt;&lt;p&gt;ただ、IORef というのが、なんだかしっくり来ない。結局、状態を持ってしまってる事になり、どうも気持ち悪い。初心者なりに勝手に純粋関数型言語に期待していたのは、もっと、引数と戻り値だけでつながっていく感じなんだけど、まだまだ勉強が足りないのかもしれない。&lt;/p&gt;&lt;p&gt;結果としては、マウスボタンの判別をしていないので、右でも左でも書けてしまうけど、一応思ったとおりに動作するものができた。&lt;a href="http://www.google.co.jp/search?q=%E3%82%B9%E3%83%97%E3%83%BC&amp;hl=en&amp;prmd=imvns&amp;source=lnms&amp;tbm=isch&amp;ei=e63wTsOfOI-giQeoysmrAQ&amp;sa=X&amp;oi=mode_link&amp;ct=mode&amp;cd=2&amp;ved=0CAwQ_AUoAQ&amp;biw=1280&amp;bih=863"&gt;スプー&lt;/a&gt;の絵もこんな風に書く事ができる（頭頂部の突起がやや足りない事を除けば、我ながらよく描けたと思う）。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-N-J_IW7wt4Q/Tu2ZEFaZv5I/AAAAAAAAATc/hHuXuoqx2yU/s1600/spoo.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="239" width="320" src="http://1.bp.blogspot.com/-N-J_IW7wt4Q/Tu2ZEFaZv5I/AAAAAAAAATc/hHuXuoqx2yU/s320/spoo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6603842450466693628?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6603842450466693628/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/gtk2hs-wo.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6603842450466693628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6603842450466693628'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/gtk2hs-wo.html' title='gtk2hs で落書きしてみる'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-N-J_IW7wt4Q/Tu2ZEFaZv5I/AAAAAAAAATc/hHuXuoqx2yU/s72-c/spoo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-876666669777669784</id><published>2011-12-18T00:19:00.000+09:00</published><updated>2011-12-18T08:21:05.373+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>gtk2hs と Glade の相性</title><content type='html'>&lt;p&gt;gtk2hs を Glade と組み合わせて使うときのメモ。&lt;/p&gt;&lt;p&gt;Haskell の GUI プログラミングを試したくて、テキストボックスに文字列を入れて Enter を押したらラベルに表示されるような簡単なプログラム echo を、gtk2hs を使って書く実験をしてみた。&lt;br/&gt;&lt;br/&gt;で、まず Glade というツールで GUI を定義する XMLを生成して、これを適当に書いた Haskell プログラムに読ませたら、こんなエラーが出た&lt;/p&gt;&lt;pre style="background-color:white;color:black;line-height:150%;"&gt;$ ./echo &lt;br /&gt;&lt;br /&gt;(echo:4887): libglade-WARNING **: Expected &amp;lt;glade-interface&amp;gt;.  Got &amp;lt;interface&amp;gt;.&lt;br /&gt;&lt;br /&gt;(echo:4887): libglade-WARNING **: did not finish in PARSER_FINISH state&lt;br /&gt;echo: user error (Pattern match failure in do expression at echo.hs:8:5-12)&lt;/pre&gt;&lt;p&gt;なんか Glade が生成した GUI定義XML の形式に問題があるっぽい。&lt;/p&gt;&lt;p&gt;調べてみると、Glade の出力形式には libglade と GtkBuilder の二通りの方法があり、gtk2hs が対応しているのは前者という事らしいのだが、ファイルを保存するときに libglade を選んでも、事態は全然変わらない。&lt;/p&gt;&lt;p&gt;さらに調べてみると Glade の3.8系 と 3.10系 で大きな違いがあって、出力XML に関してだと 3.10系では libglade 形式が無くなってるらしい。自分は、特に意識しないまま 3.10 を使っていた模様。&lt;/p&gt;&lt;p&gt;この2つのバージョン間で、保存時のダイアログに以下のような違いがある。&lt;div class="separator" style="clear: both; text-align: center;"&gt; 3.10系&lt;br/&gt;&lt;a href="http://1.bp.blogspot.com/-AxJRMKa2pyw/Tuw1tvN4VjI/AAAAAAAAAS4/tHnzlLySKsM/s1600/glade3.10.filesave.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="162" width="320" src="http://1.bp.blogspot.com/-AxJRMKa2pyw/Tuw1tvN4VjI/AAAAAAAAAS4/tHnzlLySKsM/s320/glade3.10.filesave.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;3.8系&lt;br/&gt;&lt;a href="http://1.bp.blogspot.com/-l5ZtBqxvQaM/Tuw2zjwg0aI/AAAAAAAAATE/2VzET9UhF74/s1600/glade3.8-filesave2.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="206" width="320" src="http://1.bp.blogspot.com/-l5ZtBqxvQaM/Tuw2zjwg0aI/AAAAAAAAATE/2VzET9UhF74/s320/glade3.8-filesave2.png" /&gt;&lt;/a&gt;&lt;/div&gt;XML出力の違いは以下のような感じ&lt;div class="separator" style="clear: both; text-align: center;"&gt; 3.10系&lt;/div&gt;&lt;pre style="background-color:white;color:black;line-height:150%;"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;interface&amp;gt;&lt;br /&gt;  &amp;lt;requires lib="gtk+" version="2.24"/&amp;gt;&lt;br /&gt;  &amp;lt;object class="GtkWindow" id="window1"&amp;gt;&lt;br /&gt;    &amp;lt;property name="can_focus"&amp;gt;False&amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;child&amp;gt;&lt;br /&gt;    …&lt;br /&gt;&lt;/pre&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt; 3.8系&lt;/div&gt;&lt;pre style="background-color:white;color:black;line-height:150%;"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;glade-interface&amp;gt;&lt;br /&gt;  &amp;lt;widget class="GtkWindow" id="window1"&amp;gt;&lt;br /&gt;    &amp;lt;property name="can_focus"&amp;gt;False&amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;child&amp;gt;&lt;br /&gt;    …&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;というわけで、Glade の 3.8 系を使えば、gtk2hs がちゃんと処理できる形式の XML になる。&lt;/p&gt;&lt;p&gt;ただし、うちの環境で使ってる Fedora16 なんかでは、「ソフトウェアの追加／削除」から普通に Glade をインストールすると 3.10系が入って来てしまう。従って、この場合 3.8系を別途インストールする必要がある。&lt;/p&gt;&lt;p&gt;これは、&lt;a href="http://ftp.gnome.org/pub/GNOME/sources/glade3/3.8/"&gt;ここから&lt;/a&gt; glade3-3.8.1.tar.xz を落としてきて、tar Jxf glade3-3.8.1.tar.xz -&gt; ./configure -&gt; make -&gt; make install のようにすれば、/usr/local/bin/glade-3 が使えるようになる。&lt;p&gt;ちなみに、以下が実験で使った Haskellコード&lt;pre class="prettyprint"&gt;module Main where&lt;br /&gt;&lt;br /&gt;import Graphics.UI.Gtk&lt;br /&gt;import Graphics.UI.Gtk.Glade&lt;br /&gt;import Graphics.UI.Gtk.Gdk.Events as Evt&lt;br /&gt;&lt;br /&gt;main = do&lt;br /&gt;    initGUI&lt;br /&gt;    Just xml    &amp;lt;- xmlNew "echo.glade"&lt;br /&gt;    window      &amp;lt;- xmlGetWidget xml castToWindow "window1"&lt;br /&gt;    onDestroy window mainQuit&lt;br /&gt;    label       &amp;lt;- xmlGetWidget xml castToLabel "label1"&lt;br /&gt;    entry       &amp;lt;- xmlGetWidget xml castToEntry "entry1"&lt;br /&gt;    onKeyPress window $ \(Evt.Key _ eventSent _ _ _ _ _ _ name _) -&amp;gt; do&lt;br /&gt;      keyPressHandler label entry name&lt;br /&gt;      return eventSent&lt;br /&gt;    widgetShowAll window&lt;br /&gt;    mainGUI&lt;br /&gt;&lt;br /&gt;keyPressHandler :: Label -&amp;gt; Entry -&amp;gt; String -&amp;gt; IO ()&lt;br /&gt;keyPressHandler label entry "Return" = do&lt;br /&gt;  name &amp;lt;- get entry entryText&lt;br /&gt;  set label [labelText := name]&lt;br /&gt;keyPressHandler _ _ _ = return ()&lt;/pre&gt;たかだかこれだけのコードを書くのに、かなり骨を折るが、いちおう動作する。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-OKluQyEBs3U/TuyyCHIsl0I/AAAAAAAAATQ/eggkvUR8TVs/s1600/yakiniku-teishoku.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="90" width="170" src="http://3.bp.blogspot.com/-OKluQyEBs3U/TuyyCHIsl0I/AAAAAAAAATQ/eggkvUR8TVs/s320/yakiniku-teishoku.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-876666669777669784?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/876666669777669784/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/gtk2hs-glade.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/876666669777669784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/876666669777669784'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/gtk2hs-glade.html' title='gtk2hs と Glade の相性'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-AxJRMKa2pyw/Tuw1tvN4VjI/AAAAAAAAAS4/tHnzlLySKsM/s72-c/glade3.10.filesave.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-159182436321594179</id><published>2011-12-14T00:10:00.001+09:00</published><updated>2011-12-14T00:10:30.545+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>現場でよくある Agile 認識の齟齬</title><content type='html'>&lt;p&gt;現場で、開発プロセスをどうしましょうかなんて話をしていると、対話の流れを止めて指摘するほどではないけど、認識の違いが引っかかって嫌なときがある。今日は、そんな事象のメモ。&lt;/p&gt;&lt;p style="color:white;"&gt;★ Agile プロセスはユルいものだという認識&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpading="0" style="border-collapse:collapse;width:100%;"&gt;&lt;tr&gt;&lt;td width="20%"&gt;&lt;/td&gt;&lt;td width="40%"&gt;ユルい&lt;/td&gt;&lt;td width="40%"&gt;キビしい&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;なんか違う&lt;/td&gt;&lt;td&gt;Agile全般&lt;/td&gt;&lt;td&gt;ウォーターフォール&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;たぶんこう&lt;/td&gt;&lt;td&gt;Adaptive Software Development、Crystal Clear&lt;/td&gt;&lt;td&gt;XP、Scrum、ウォーターフォール&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;Agile が総じてユルいのではなく、実はユルいのもキビしいのもある。この見方は、確かものすご〜く前に読んだ Cockburn の本に載ってたものだけど、仮に読んでなかったとしても同じ認識になってた気がする。&lt;/p&gt;&lt;p&gt;ちなみに、同じ High-Discipline プロセスの中でも、XP と ウォーターフォールでは、前者が高効率・高難度で後者が低効率・低難度って事になると思う。寛容な方のグループの Crystal Clear なんかは、ユルい分、XP のような究極的な生産性は得られないけど、その分、負担が少ないって事になると思う。&lt;/p&gt;&lt;p style="color:white;"&gt;★ 反復型といえば軽量プロセスだという認識&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpading="0" style="border-collapse:collapse;width:100%;"&gt;&lt;tr&gt;&lt;td width="20%"&gt;&lt;/td&gt;&lt;td width="40%"&gt;軽量&lt;/td&gt;&lt;td width="40%"&gt;重量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;なんか違う&lt;/td&gt;&lt;td&gt;反復型プロセス全般&lt;/td&gt;&lt;td&gt;ウォーターフォール&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;たぶんこう&lt;/td&gt;&lt;td&gt;Agile系&lt;/td&gt;&lt;td&gt;UP系（AgileUPは除く）、ウォーターフォール&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;反復型のプロセスはどれもみな軽量だという思い込みもよくあるけど、たいてい「軽量プロセスはドキュメントを作らない」ってドクサも併発してるから、とりあえず反復型にしてみませんかなんて提案しても、習慣による心理的抵抗が大きい。&lt;/p&gt;&lt;p&gt;ウォーターフォール色の強い組織でも、ドキュメント体系を差し当たり尊重したまま、やや長めの期間の反復型プロセスに切り替えた上で、反復型が浸透してきた頃合いを見て、段々と期間を短くしたり文書や儀式を減らして、段階的に軽量にしていくというやり方もある。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-159182436321594179?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/159182436321594179/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/agile.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/159182436321594179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/159182436321594179'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/agile.html' title='現場でよくある Agile 認識の齟齬'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6801036385621916204</id><published>2011-12-13T02:44:00.000+09:00</published><updated>2011-12-13T02:44:25.544+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><title type='text'>Alloy 本</title><content type='html'>&lt;p&gt;土曜に Amazon のお急ぎ便で注文したら、日曜の夜に届いた。&lt;a href="http://amazon.co.jp/o/ASIN/4274068587/yasuabe-1984-22/ref=nosim"&gt;&lt;img src="http://images.amazon.com/images/P/4274068587.09._OU09_SCMZZZZZZZ_.jpg" alt="Alloy本"&gt;&lt;/a&gt;&lt;br/&gt;日曜は暇がなかったので、今日、帰宅してから早速 &lt;a href="http://alloy.mit.edu/alloy/download.html"&gt;Alloy Analyzer をダウンロード&lt;/a&gt;して、テキストに取りかかる。（単なる jar なので java -jar ですぐ動く。）&lt;/p&gt;&lt;p&gt;下図の左側ペインのようにコードを書き込んで、[Execute]&gt;[Show Metamodel]を実行すると、、、&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-eBj1g9qsWv0/TuYyt_sd16I/AAAAAAAAASg/DL8W16U4TKU/s1600/alloy-analyzer.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="167" width="320" src="http://1.bp.blogspot.com/-eBj1g9qsWv0/TuYyt_sd16I/AAAAAAAAASg/DL8W16U4TKU/s320/alloy-analyzer.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;、、、このようなダイアグラムが得られる。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-IIz6op_xlGE/TuYyRTRnuQI/AAAAAAAAASU/c62Pip40kws/s1600/alloy-1st-trial.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="299" src="http://1.bp.blogspot.com/-IIz6op_xlGE/TuYyRTRnuQI/AAAAAAAAASU/c62Pip40kws/s320/alloy-1st-trial.png" /&gt;&lt;/a&gt;&lt;/div&gt;このダイアグラムは、四角形の配置を変えたり、色やフォントを変えたりして、ある程度見せ方を好きなように変えられるようだけど、どうもダイアグラムはそれほど本質的なものではないっぽい。&lt;/p&gt;&lt;p&gt;まあ、1時間ほどいじっただけだし何も理解できてないけど、上の上の図で左側のペインに書いてある Alloy コードがやっぱり主役っぽい。&lt;br/&gt;これに述語（pred）やファクト（fact）をちょっと書き足しては、それに対してアサーション（assert）をちょっと付け加えて、そしたら実行して右側のペインで確認して、って流れになる模様。そうだとしたら、どこか TDD に似ていてとっつきやすい。&lt;/p&gt;&lt;p&gt;とは言っても、関心の重点は実装ではなくむしろ仕様であって高い抽象レベルで仕様をモデリングする事が目的の技術らしい。&lt;br/&gt;ちなみに、抽象度をレベル分けするときに、伝統的に分析レベル、設計レベル、実装レベルなんて言ったりするけど、Alloy と同じ雰囲気で、なおかつレベルの違う他言語を持ってくると、分析レベル：Alloy、設計レベル：LePUS3、実装レベル：Coq てな感じに当てはまるんじゃないかと思う。&lt;/p&gt;&lt;p&gt;まあ、いきなりいろんな事をやり始めなくても、とりあえず Alloy だけでも、例えば金融システムのビジネスルールとかに適用して、仕様バグを取り除くような事は、結構すぐにでも始められそうな予感。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6801036385621916204?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6801036385621916204/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/alloy.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6801036385621916204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6801036385621916204'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/alloy.html' title='Alloy 本'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-eBj1g9qsWv0/TuYyt_sd16I/AAAAAAAAASg/DL8W16U4TKU/s72-c/alloy-analyzer.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-9103885983044296790</id><published>2011-12-11T08:07:00.001+09:00</published><updated>2011-12-11T20:47:06.041+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Haskell+HDBC+MySQL で Hello World</title><content type='html'>&lt;p&gt;Haskell で MySQL を使ってみるウォーミングアップ。&lt;/p&gt;こんな環境&lt;ul&gt;&lt;li&gt;Fedora16&lt;/li&gt;&lt;li&gt;GHC 7.0.4&lt;/li&gt;&lt;li&gt;MySQL 5.5.18&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;まずテーブルを準備する。適当に mysql で MySQL に接続して以下のようにする。&lt;pre style="background-color:white;color:black;line-height:132%;"&gt;mysql&gt; create database hdbc_test;&lt;br /&gt;mysql&gt; connect hdbc_test;&lt;br /&gt;mysql&gt; create table greeting (id int not null auto_increment, text varchar(50), primary key(id));&lt;br /&gt;mysql&gt; insert into greeting(text) values ('Hello, world!');&lt;br /&gt;mysql&gt; select * from greeting;&lt;br /&gt;+-----+---------------+&lt;br /&gt;| id  | text          |&lt;br /&gt;+-----+---------------+&lt;br /&gt;|   1 | Hello, world! |&lt;br /&gt;+-----+---------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;/pre&gt;テーブルの準備ができたら、次は使用するモジュールだけど、&lt;a href="http://book.realworldhaskell.org/read/using-databases.html"&gt;この サイト&lt;/a&gt;によると、Haskell から DB を使うには、HDBC、HSQL、HaskellDBと言った選択肢があるらしい。とりあえず HDBC でいってみる。&lt;pre style="background-color:white;color:black;line-height:132%;"&gt;$cabal install HDBC&lt;br /&gt;$cabal install HDBC-mysql&lt;/pre&gt;&lt;p style="font-size:smaller;"&gt;※ cabal 自体は、Fedora のアプリケーションの追加／削除でインストールした。&lt;br/&gt;※ ghc-pkg という低レベルのコマンドもある。&lt;br/&gt;※ MySQL以外に HDBC でサポートされてるやつを調べるには&lt;a href="http://hackage.haskell.org/packages/archive/pkg-list.html#cat:computer algebra"&gt;ここ&lt;/a&gt;&lt;/p&gt;&lt;p&gt;できたら、MySQL に接続してみる。&lt;br/&gt;まず ghci を立ち上げて、モジュールを取り込んでからDB接続を取得する。&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt;  :m +Database.HDBC Database.HDBC.MySQL&lt;br /&gt;ghci&gt; conn &lt;- connectMySQL MySQLConnectInfo{mysqlHost="localhost", mysqlDatabase="hdbc_test", mysqlUser="root",mysqlPassword="XXXX", mysqlPort=3306, mysqlUnixSocket="/var/lib/mysql/mysql.sock"}&lt;br /&gt;ghci&gt;&lt;/pre&gt;&lt;p&gt;mysqlUnixSocket に設定するファイル名は、/etc/my.conf に書いてあるのでそれを指定すればいい。成功したら、上のようにエラーメッセージなしで次のプロンプトに移る。&lt;br/&gt;&lt;/p&gt;&lt;p&gt;ちなみに、省略時値が既に設定されている defaultMySQLConnectInfo を使えば、この場合だと mysqlHost, mysqlUser, mysqlPort を省略して以下のようにできる。&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt; conn &lt;- connectMySQL defaultMySQLConnectInfo{mysqlDatabase="hdbc_test", mysqlPassword="XXXXX", mysqlUnixSocket="/var/lib/mysql/mysql.sock"}&lt;/pre&gt;&lt;/p&gt;&lt;p style="font-size:smaller;"&gt;※ソースを読みたかったら、&lt;a href="http://hackage.haskell.org/packages/archive/HDBC-mysql/0.6/doc/html/src/Database-HDBC-MySQL-Connection.html"&gt;ここで&lt;/a&gt;見られる&lt;/p&gt;&lt;p&gt;接続が得られたら、いよいよ HelloWorld。&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt; quickQuery' conn "SELECT * from greeting" []&lt;br /&gt;[[SqlInt32 1,SqlByteString "Hello, world!"]]&lt;/pre&gt;うん。できたっぽい。&lt;br/&gt;&lt;p style="font-size:smaller;"&gt;ちなみに エラー無しで取得できたと思った Connection を、いざ使おうとしたら "No instance for (IConnection Connection)"なんて言われる事がある。自分もそうなったけど HDBC 関連のパッケージを更新したら解消した（&lt;a href="http://blog.lambdalifting.org/?p=80"&gt;参考URL&lt;/a&gt;）&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;ついでに、もうちょい他の事もやってみる。&lt;/p&gt;&lt;p&gt;&lt;b&gt;■ prepared statement&lt;/b&gt;&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt; stmt &lt;- prepare conn "INSERT INTO greeting(text) VALUES (?)"&lt;br /&gt;ghci&gt; executeMany stmt [[toSql "Good-bye, world..."], [toSql "Hello, another world2!"]]&lt;br /&gt;ghci&gt; quickQuery' conn "select * from greeting"[]&lt;br /&gt;[[SqlInt32 1,SqlByteString "Hello, world!"],[SqlInt32 2,SqlByteString "Good-bye, world..."],[SqlInt32 3,SqlByteString "Hello, another world!"]]&lt;br /&gt;ghci&gt; commit conn&lt;/pre&gt; JDBC やってるのと同じだね。&lt;/p&gt;&lt;p&gt;&lt;b&gt;■ メタ情報&lt;/b&gt;&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt; describeTable conn "greeting"&lt;br /&gt;[("id",SqlColDesc {colType = SqlIntegerT, colSize = Nothing, colOctetLength = Nothing, colDecDigits = Nothing, colNullable = Just False}),("text",SqlColDesc {colType = SqlVarCharT, colSize = Nothing, colOctetLength = Nothing, colDecDigits = Nothing, colNullable = Just True})]&lt;/pre&gt;うーん…colType は良いけど、colSize がNothing になってるのはどういう訳だろう。ここは varchar (50) を反映していてほしかった。標準SQL の INFORMATION_SCHEMA で、普通にメタ情報を得ることも、もちろんできる。&lt;/p&gt;&lt;p&gt;&lt;b&gt;■ 日本語&lt;/b&gt;&lt;pre style="background-color:white;color:black;line-height:148%;"&gt;ghci&gt; run conn "UPDATE greeting SET text='こんにちは' WHERE id=1" []&lt;br /&gt;ghci&gt; quickQuery' conn "select * from greeting where id=1"[]&lt;br /&gt;[[SqlInt32 1,SqlByteString "S\147kao"]]&lt;/pre&gt;ははは、文字化けした。mysql で見ても化けてる。面倒そうだから後で考えよっと。&lt;/p&gt;&lt;br/&gt;気になるところが幾つかあったけど、最初の試行としてはこんなものだろう。&lt;br/&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;最後に豆知識メモ。&lt;/p&gt;&lt;p&gt;ghci のプロンプトを変えるには、":set prompt "ghci&gt; "と入力すればいい。これを永続化するには、~/.ghc/ghci.conf に同じ事を書く。ただし、どういうわけか、ファイルのパーミッションで、グループに w が付いていると無視される。無視されないようにするには、"chmod g-w .ghc .ghc/ghci.conf "として、書き込み権限を取り除いておけばいい。&lt;/p&gt;&lt;p&gt;あと、いろいろググってると、HaskellDB と HSQL と HDBC とで、似て非なる事柄が一緒くたに引っかかってくるので、酒を飲みながら作業してたりすると、 &lt;a href="http://hackage.haskell.org/packages/archive/HDBC-mysql/0.6.5.1/doc/html/src/Database-HDBC-MySQL-Connection.html"&gt;HDBC.MySQL のソース&lt;/a&gt;のつもりで &lt;a href="http://hackage.haskell.org/packages/archive/haskelldb-hdbc-mysql/0.1.1/doc/html/src/Database-HaskellDB-HDBC-MySQL.html"&gt;HaskellDB.HDBC.MySQL のソース&lt;/a&gt;を読んで小一時間頭をかきむしって苦しむ事になったりする。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-9103885983044296790?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/9103885983044296790/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/haskellhdbcmysql-hello-world.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9103885983044296790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9103885983044296790'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/haskellhdbcmysql-hello-world.html' title='Haskell+HDBC+MySQL で Hello World'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7367118342205516663</id><published>2011-12-09T00:44:00.001+09:00</published><updated>2011-12-09T01:40:24.559+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logic programming'/><category scheme='http://www.blogger.com/atom/ns#' term='雑学'/><title type='text'>Prolog で楽典クイズ</title><content type='html'>&lt;p&gt;我々が日ごろ聞いてるふつうの音楽は、１オクターブの中に高さの異なる音が１２個あって、それぞれの音は「音名」という名前を持っている。&lt;/p&gt;&lt;p&gt;実は、ほとんどの音はそれぞれ三つの音名を持っている。例えば、ミ♯、ファ、ソ♭♭の組み合わせや、レｘ、ミ、ファ♭の組み合わせは同じ音高であったりする。&lt;/p&gt;&lt;p&gt;ところが、ある音だけは二つの音名しか持っていない。この音が何かわかるだろうか。&lt;/p&gt;&lt;p&gt;ダブルシャープとかダブルフラットを使ってるから、小学校で習うかどうかは分からないけど、たぶん義務教育の範囲には入ってる気がするくらいの基礎的な楽典知識だけで構成された問いだけど、面白いことに、意外と音楽をやってる人でも即座には答えられなかったりする。&lt;/p&gt;&lt;p&gt;ピアノの鍵盤を思い浮かべて単なる図形として捉えたら簡単なんだけど、今日は、これを「寝る前ちょこっとプログラミング」のお題にしてみようと、帰りの電車で思いついた。Prolog でやってみる。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;&lt;pre class="prettyprint"&gt;note(0, 'C').&lt;br /&gt;note(2, 'D').&lt;br /&gt;note(4, 'E').&lt;br /&gt;note(5, 'F').&lt;br /&gt;note(7, 'G').&lt;br /&gt;note(9, 'A').&lt;br /&gt;note(11, 'B').&lt;br /&gt;&lt;br /&gt;notes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]).&lt;br /&gt;&lt;br /&gt;alteration('ｘ', -2).&lt;br /&gt;alteration('♯',  -1).&lt;br /&gt;alteration('♮',   0).&lt;br /&gt;alteration('♭',   1).&lt;br /&gt;alteration('♭♭',  2).&lt;br /&gt;&lt;br /&gt;noteWithThreeNames(Names)   :- findNoteNamesByCount(Names, 3).&lt;br /&gt;noteWithOnlyTwoNames(Names) :- findNoteNamesByCount(Names, 2).&lt;br /&gt;&lt;br /&gt;findNoteNamesByCount(Names, Count) :-&lt;br /&gt;   notes(Notes), member(Note, Notes),&lt;br /&gt;   collectNoteNames(Note, Names),&lt;br /&gt;   length(Names, Count).&lt;br /&gt;&lt;br /&gt;collectNoteNames(Note, Names) :-&lt;br /&gt;  findall(Name, findName(Note, Name), Names).&lt;br /&gt;&lt;br /&gt;findName(Note, Names) :- &lt;br /&gt;  alteration(Alteration, Diff), &lt;br /&gt;  getNote(Note + Diff, NaturalTone),&lt;br /&gt;  concat_atom([NaturalTone, Alteration], Names).&lt;br /&gt;&lt;br /&gt;getNote(N, X) :- N2 is N mod 12, note(N2, X).&lt;/pre&gt;&lt;/p&gt;素朴な実装だけど、以下のように正しい結果が得られる。&lt;pre style="background-color:black;color:snow;"&gt;&lt;br /&gt;?- noteWithThreeNames(Names).&lt;br /&gt;Names = ['B♯', 'C♮', 'D♭♭'] ;&lt;br /&gt;Names = ['Bｘ', 'C♯', 'D♭'] ;&lt;br /&gt;Names = ['Cｘ', 'D♮', 'E♭♭'] ;&lt;br /&gt;Names = ['D♯', 'E♭', 'F♭♭'] ;&lt;br /&gt;Names = ['Dｘ', 'E♮', 'F♭'] ;&lt;br /&gt;Names = ['E♯', 'F♮', 'G♭♭'] ;&lt;br /&gt;Names = ['Eｘ', 'F♯', 'G♭'] ;&lt;br /&gt;Names = ['Fｘ', 'G♮', 'A♭♭'] ;&lt;br /&gt;Names = ['Gｘ', 'A♮', 'B♭♭'] ;&lt;br /&gt;Names = ['A♯', 'B♭', 'C♭♭'] ;&lt;br /&gt;Names = ['Aｘ', 'B♮', 'C♭'].&lt;br /&gt;&lt;br /&gt;?- noteWithOnlyTwoNames(Names).&lt;br /&gt;Names = ['G♯', 'A♭'] ;&lt;br /&gt;false.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;音楽の話題でいえば、厳格対位法という、こんなのとは比較にならないくらいパズルっぽいやつがある。これは与えられた音の配列（定旋律）に対して、たくさんの「禁則」をくぐり抜けてごく限られた音の配列（対旋律）を見つけ出していくという、古典音楽作曲の伝統的なトレーニングなんだけど、視点を変えるとパズルの「&lt;a href="http://ja.wikipedia.org/wiki/%E5%B7%9D%E6%B8%A1%E3%82%8A%E5%95%8F%E9%A1%8C"&gt;川渡り問題&lt;/a&gt;」に似てなくもない。&lt;/p&gt;&lt;p&gt;たぶん、とっくにどこかのプログラマが挑戦してるだろうけど、もうちょいヒマができたら自分でもやってみたい気がする。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7367118342205516663?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7367118342205516663/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/prolog.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7367118342205516663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7367118342205516663'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/prolog.html' title='Prolog で楽典クイズ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7020716348961360713</id><published>2011-12-06T01:25:00.001+09:00</published><updated>2012-01-05T00:34:17.300+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Jaskell このやろう！</title><content type='html'>&lt;p&gt;名前だけはずいぶん前から知ってたけど、あまり興味が無くて放置していた Jaskell。&lt;/p&gt;&lt;p&gt;『プロダクティブ・プログラマ』で紹介されて高評価だったから、さぞかし有望株なのだろうと思いきや…&lt;/p&gt;&lt;p&gt;誰も使ってる気配がない…&lt;/p&gt;&lt;p&gt;まあダウンロードはできるから、ちょっと試してみようとしたけど、そもそも動いてくれない。&lt;pre&gt;Exception in thread "main" java.lang.NoSuchMethodError: jfun.parsec.Parsers.plus(Ljfun/parsec/Parser;Ljfun/parsec/Parser;)Ljfun/parsec/Parser;&lt;br /&gt; at jfun.jaskell.JaskellParser.&lt;init&gt;(JaskellParser.java:299)&lt;br /&gt; at jfun.jaskell.JaskellParser.instance(JaskellParser.java:1377)&lt;br /&gt; at jfun.jaskell.JaskellParser.parseExprOrLib(JaskellParser.java:1436)&lt;br /&gt; at jfun.jaskell.Jaskell.parseExprOrLib(Jaskell.java:2356)&lt;br /&gt; at jfun.jaskell.Jaskell.parseExprOrLib(Jaskell.java:2376)&lt;br /&gt; at jfun.jaskell.Jaskell.eval(Jaskell.java:2469)&lt;br /&gt; at jfun.jaskell.Jaskell.evalInputStream(Jaskell.java:2657)&lt;br /&gt; at jfun.jaskell.Jaskell.evalResource(Jaskell.java:2555)&lt;br /&gt; at jfun.jaskell.Jaskell.evalResource(Jaskell.java:2531)&lt;br /&gt; at jfun.jaskell.Jaskell.importPrelude(Jaskell.java:1990)&lt;br /&gt; at jfun.jaskell.shell.Shell.getShellRuntime(Shell.java:42)&lt;br /&gt; at jfun.jaskell.shell.Shell.main(Shell.java:35)&lt;br /&gt;&lt;/pre&gt;ちなみにこの例外は、java コマンドから Jaskell Shell を起動しようとしたときにも、Jaskell インスタンスを生成してそいつにスクリプトを読ませようとしたときにも、 どっちでも発生する。&lt;/p&gt;&lt;p&gt;第一、起動の仕方らしきものにたどり着くまでだいぶかかった。プロダクティブ・プログラマで紹介されている URL、「http://jaskell.codehaus.org/」 は、Jaskell でググっても一番上にくるやつだけど、動かし方がどこにも全然書いてない。&lt;/p&gt;&lt;p&gt;jaskell-1.0.jar を実行したら何か起こるだろうと思ったけど、うんともすんとも言わない。MANIFEST.MFにも、やっぱなんも書いてなかった。&lt;/p&gt;&lt;p&gt;しょうがないから、JavaDoc を読んでたら Jaskell クラスというのがあって、こいつが文字列やファイルを評価する eval () メソッドを持ってるから、インスタンス作って eval() したら、上の例外。&lt;/p&gt;&lt;p&gt;半泣きでググってたら、Jaskell Shell というのを見つけるが、トップページからリンクされてる訳でもなく、どこが本物のプロジェクトページだか、訳が分からない。で、動かしてみたら、また上の例外。&lt;/p&gt;&lt;p&gt;まあ、何個かある jar の組み合わせを変えてみるとか、再コンパイルしてみるとかで、解決しない事もないんだろうけど、もういい。心折れた。降りるわ。&lt;/p&gt;&lt;p&gt;それにしても Neal Ford さんは、なんでこんなの紹介したんだ…。&lt;br/&gt;普通に、Haskell 勉強して行こうやって結論しか出てこない。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7020716348961360713?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7020716348961360713/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/jaskell.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7020716348961360713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7020716348961360713'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/jaskell.html' title='Jaskell このやろう！'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7882242117369225649</id><published>2011-12-04T23:19:00.001+09:00</published><updated>2011-12-05T00:11:32.544+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy+HttpClient で Redmine の wiki 更新</title><content type='html'>&lt;p&gt;Redmine の wiki を、HTTP のクライアントプログラムで更新する方法を考えてみた。言語は何でもいいが、ここでは Groovy を使ってみた。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;例えば、以下のようなコードで、&lt;pre class="prettyprint"&gt;class Test {&lt;br /&gt;   def static content = """\&lt;br /&gt;h1. 大見出し&lt;br /&gt;&lt;br /&gt;なんとかこんとか&lt;br /&gt;${ new Date().toString() }&lt;br /&gt;"""&lt;br /&gt;      public static void main(args) {&lt;br /&gt;      new RedmineWikiRewriter()&lt;br /&gt;         .login("user001", "password")&lt;br /&gt;         .startEdit("project001", "Http_post_test")&lt;br /&gt;         .saveEdit(content)&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;下の画像のように、wiki ページが更新されるような クラス RedmineWikiRewriter を考えてみる。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Kg3eijlRm0Y/TtuDeIhtpfI/AAAAAAAAASI/pIDOqAMR9t8/s1600/redmine-project001-httpposttest.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="222" width="400" src="http://3.bp.blogspot.com/-Kg3eijlRm0Y/TtuDeIhtpfI/AAAAAAAAASI/pIDOqAMR9t8/s400/redmine-project001-httpposttest.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;login() では、与えられたユーザ名とパスワードでログインして、Redmine から返されるクッキーを保持する。&lt;/li&gt;&lt;li&gt;startEdit()は、指定のプロジェクトの指定の wiki ページを開く。これはページのバージョンを得るために必要&lt;/li&gt;&lt;li&gt;saveEdit()は、wiki コンテンツをマルチパートの HTTP POST で送信する&lt;/li&gt;&lt;/ul&gt;コードは以下のようなものになる&lt;p&gt;&lt;pre class="prettyprint"&gt;class RedmineWikiRewriter {&lt;br /&gt;   def static UTF8 = Charset.forName("UTF-8")&lt;br /&gt;&lt;br /&gt;   def HTTPBuilder http = new HTTPBuilder('http://localhost:3000/')&lt;br /&gt;&lt;br /&gt;   def redmineSession&lt;br /&gt;   def authenticityToken&lt;br /&gt;   def contentVersion &lt;br /&gt;   &lt;br /&gt;   def project&lt;br /&gt;   def wikiEntry&lt;br /&gt;   &lt;br /&gt;   public RedmineWikiRewriter login(String username, String password) {&lt;br /&gt;      http.get(path : '/login', query : [q:'Groovy'] ) { resp, reader -&gt; &lt;br /&gt;         authenticityToken = reader.BODY.DIV.DIV&lt;br /&gt;            .findAll { it.id="login-form" }.depthFirst()&lt;br /&gt;            .grep { "authenticity_token"== it.@name.toString() }[0]&lt;br /&gt;            .@value.toString()&lt;br /&gt;      }&lt;br /&gt;      http.request(POST) {&lt;br /&gt;         uri.path = '/login'&lt;br /&gt;         send URLENC, [&lt;br /&gt;            username:username, password:password, &lt;br /&gt;            authenticity_token:authenticityToken]&lt;br /&gt;&lt;br /&gt;         response.success = { resp -&gt;&lt;br /&gt;            redmineSession = resp.getAllHeaders()&lt;br /&gt;               .find {"Set-Cookie"==it.name.toString()}&lt;br /&gt;               .value.split(";")&lt;br /&gt;               .find {it.toString().startsWith("_redmine_session")}&lt;br /&gt;            }&lt;br /&gt;      } &lt;br /&gt;      this&lt;br /&gt;   }&lt;br /&gt;   RedmineWikiRewriter startEdit(String project, String wikiEntry) {&lt;br /&gt;      this.project = project&lt;br /&gt;      this.wikiEntry = wikiEntry &lt;br /&gt;&lt;br /&gt;      http.request(GET) { resp -&gt;&lt;br /&gt;         uri.path = "/projects/"+project+"/wiki/" + wikiEntry + "/edit"&lt;br /&gt;         headers.'Cookie' = redmineSession&lt;br /&gt;         response.success = { res, reader -&gt;&lt;br /&gt;            contentVersion = reader&lt;br /&gt;               .depthFirst()&lt;br /&gt;               .grep{"content_version"==it.@id.toString() }[0]&lt;br /&gt;               .@value.toString()&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;      this&lt;br /&gt;   }&lt;br /&gt;   void saveEdit(String content) {&lt;br /&gt;      DefaultHttpClient httpclient = new DefaultHttpClient();&lt;br /&gt;      def uri = "http://localhost:3000/projects/"+ project +"/wiki/" + wikiEntry&lt;br /&gt;&lt;br /&gt;      HttpPost httppost = new HttpPost(uri)&lt;br /&gt;      httppost.addHeader('Cookie', redmineSession)&lt;br /&gt;      &lt;br /&gt;      MultipartEntity mpe = new MultipartEntity(&lt;br /&gt;         HttpMultipartMode.BROWSER_COMPATIBLE, &lt;br /&gt;         "----WebKitFormBoundaryfmexSJQ5daIXdA04", &lt;br /&gt;         UTF8);&lt;br /&gt;      addPart(mpe, "commit",          "Save");&lt;br /&gt;      addPart(mpe, "project_id",       project);&lt;br /&gt;      addPart(mpe, "action",          "update");&lt;br /&gt;      addPart(mpe, "_method",          "put");&lt;br /&gt;      addPart(mpe, "authenticity_token", authenticityToken)&lt;br /&gt;      addPart(mpe, "id",             wikiEntry)&lt;br /&gt;      addPart(mpe, "content[text]",    content)&lt;br /&gt;      addPart(mpe, "content[version]", contentVersion)&lt;br /&gt;      addPart(mpe, "controller",       "wiki")&lt;br /&gt;      &lt;br /&gt;      httppost.setEntity(mpe);&lt;br /&gt;&lt;br /&gt;      httpclient.execute(httppost);&lt;br /&gt;   }&lt;br /&gt;   static void addPart(MultipartEntity entity, String name, String value) {&lt;br /&gt;      entity.addPart(name, new StringBody(value, UTF8));&lt;br /&gt;   } &lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;span style="font-size:larger;font-weight:bold;"&gt;■ 振り返り&lt;/span&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;saveEdit() でも HttpBuilder を使いたかったが、なぜか思うように動かない。仕方なく、DefaultHttpClient を使用&lt;/li&gt;&lt;li&gt;wiki エントリの新規作成でも動くかどうかは未確認&lt;/li&gt;&lt;li&gt;たかだかこれくらいのコードでも、やってみると予想外に難しい。Redmine の Rubyコードを読んだり、HTTP の Header を調べたりいろいろ手間がかかった。あと multipart の POST も意外と難しい&lt;/li&gt;&lt;li&gt;仕組みはだいたい分かったので、他の言語でも試してみたい。もともとやりたかったのは、Excel 上の VBA からデータを整形して wiki に載せるというのを自動化すると言う事だった。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7882242117369225649?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7882242117369225649/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/groovyhttpclient-redmine-wiki.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7882242117369225649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7882242117369225649'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/groovyhttpclient-redmine-wiki.html' title='Groovy+HttpClient で Redmine の wiki 更新'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Kg3eijlRm0Y/TtuDeIhtpfI/AAAAAAAAASI/pIDOqAMR9t8/s72-c/redmine-project001-httpposttest.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8279598009658361638</id><published>2011-12-03T03:43:00.001+09:00</published><updated>2011-12-03T15:03:37.561+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><title type='text'>Fantom でサンタクロース問題</title><content type='html'>&lt;p&gt;&lt;a href="http://yasutech.blogspot.com/2011/11/fantom_29.html"&gt;前回のせんだみつおゲーム&lt;/a&gt;で Fantom の Actor の使い方が何となく分かったので、サンタクロース問題でもやってみようと思う。クリスマスも近いしな。まあ、本物のプログラマには、そんなの関係ないけどな。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;SantaClausProblem.main()は、サンタ、トナカイ、小人を生成して起動する&lt;pre class="prettyprint"&gt;using concurrent&lt;br /&gt;&lt;br /&gt;class SantaClausProblem {&lt;br /&gt;  Void main() {&lt;br /&gt;    ActorPool pool := ActorPool()&lt;br /&gt;&lt;br /&gt;    Santa santa  := Santa(pool)&lt;br /&gt;    Deer[] deers := (1..9).map |Int n-&gt;Deer| { Deer(pool, n, santa) }&lt;br /&gt;    Elf[] elves  := (1..10).map |Int n-&gt;Elf| { Elf(pool, n, santa) }&lt;br /&gt;&lt;br /&gt;    deers.each |Deer deer| { deer.send("vacation") }&lt;br /&gt;    elves.each |Elf elf| { elf.send("home") }&lt;br /&gt;&lt;br /&gt;    while (!pool.isStopped) { Actor.sleep(1sec) }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Player は登場人物共通のコード。ActorUnderSanta はトナカイと小人の共通コード。&lt;pre&gt;Actor&lt;br /&gt; └ Player&lt;br /&gt;     ├ Santa&lt;br /&gt;     └ ActorUnderSanta&lt;br /&gt;         ├ Deer&lt;br /&gt;         └ Elf&lt;/pre&gt;&lt;pre class="prettyprint"&gt;const class Player: Actor {&lt;br /&gt;  new make(ActorPool pool) : super(pool) {}&lt;br /&gt;&lt;br /&gt;  Void sleepRandom(Range r) { Actor.sleep(1sec* Int.random(r)) }&lt;br /&gt;}&lt;br /&gt;const class ActorUnderSanta: Player {&lt;br /&gt;  const Int number&lt;br /&gt;  const Santa santa&lt;br /&gt;&lt;br /&gt;  new make(ActorPool pool, Int number, Santa santa) : super(pool) {&lt;br /&gt;    this.number = number&lt;br /&gt;    this.santa = santa }&lt;br /&gt;&lt;br /&gt;  Str name() { this.typeof().name + number  }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;トナカイと小人はこんな感じ&lt;pre class="prettyprint"&gt;const class Deer: ActorUnderSanta {&lt;br /&gt;  new make(ActorPool pool, Int number, Santa santa)&lt;br /&gt;    : super(pool, number, santa) {}&lt;br /&gt;&lt;br /&gt;  override Obj? receive(Obj? msg) {&lt;br /&gt;    if ("vacation" == msg) { sleepRandom(1..10); santa.send(this) }&lt;br /&gt;    return msg&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;const class Elf: ActorUnderSanta {&lt;br /&gt;  new make(ActorPool pool, Int number, Santa santa)&lt;br /&gt;    : super(pool, number, santa) {}&lt;br /&gt;&lt;br /&gt;  override Obj? receive(Obj? msg) {&lt;br /&gt;    if ("home" == msg) { sleepRandom(2..15); santa.send(this) }&lt;br /&gt;    return msg&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;サンタはこんな感じ&lt;pre class="prettyprint"&gt;const class Santa: Player {&lt;br /&gt;  new make(ActorPool pool) : super(pool) {}&lt;br /&gt;&lt;br /&gt;  override Obj? receive(Obj? msg) {&lt;br /&gt;    echo (((ActorUnderSanta)msg).name + " が来た")&lt;br /&gt;    &lt;br /&gt;    if (msg is Deer) addDeer((Deer)msg)&lt;br /&gt;    else if (msg is Elf) addElf((Elf)msg)&lt;br /&gt;    &lt;br /&gt;    return msg&lt;br /&gt;  }&lt;br /&gt;  Void addDeer(Deer deer) {&lt;br /&gt;    Deer[] deers := get("deers", (Deer[])[,])&lt;br /&gt;    deers.add(deer)&lt;br /&gt;    wakeUpIfConditionIsMet&lt;br /&gt;  }&lt;br /&gt;  Void addElf(Elf elf) {&lt;br /&gt;    Elf[] elves := get("elves", (Elf[])[,])&lt;br /&gt;    elves.add(elf)&lt;br /&gt;    wakeUpIfConditionIsMet&lt;br /&gt;  }&lt;br /&gt;  Void wakeUpIfConditionIsMet() {&lt;br /&gt;    if (9 == getDeers().size) deliverToys&lt;br /&gt;    else if (3 &lt;= getElves().size) meetInStudy&lt;br /&gt;  }&lt;br /&gt;  Void deliverToys() {&lt;br /&gt;    echo("おもちゃを配る")&lt;br /&gt;    sleepRandom(1..2)&lt;br /&gt;    getDeers().each|Deer deer| { deer.send("vacation") }&lt;br /&gt;    Actor.locals["deers"] = (Deer[])[,]&lt;br /&gt;  }&lt;br /&gt;  Void meetInStudy() {&lt;br /&gt;    echo("小人と打ち合わせ")&lt;br /&gt;    sleepRandom(1..2)&lt;br /&gt;    Elf[] elves := getElves()&lt;br /&gt;    elves.eachRange(0..2, |Elf elf| { elf.send("home") })&lt;br /&gt;    Actor.locals["elves"] = elves.removeRange(0..2)&lt;br /&gt;  }&lt;br /&gt;  Deer[] getDeers() { (Deer[])Actor.locals["deers"] }&lt;br /&gt;&lt;br /&gt;  Elf[] getElves() { (Elf[])Actor.locals["elves"] }&lt;br /&gt;&lt;br /&gt;  Obj get(Str key, Obj defaultValue) {&lt;br /&gt;    Obj? result := Actor.locals[key]&lt;br /&gt;    if (null == result) {&lt;br /&gt;      result = defaultValue&lt;br /&gt;      Actor.locals[key] = result&lt;br /&gt;    }&lt;br /&gt;    return result&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;こんな結果が得られる&lt;pre style="color:black;background-color:white;"&gt;$ fan santaClausProblem.fan&lt;br /&gt;Deer6 が来た&lt;br /&gt;Deer1 が来た&lt;br /&gt;Elf2 が来た&lt;br /&gt;Elf9 が来た&lt;br /&gt;Deer9 が来た&lt;br /&gt;Deer2 が来た&lt;br /&gt;Deer8 が来た&lt;br /&gt;Deer3 が来た&lt;br /&gt;Elf3 が来た&lt;br /&gt;小人と打ち合わせ&lt;br /&gt;Elf5 が来た&lt;br /&gt;Elf8 が来た&lt;br /&gt;Deer4 が来た&lt;br /&gt;Deer7 が来た&lt;br /&gt;Elf1 が来た&lt;br /&gt;小人と打ち合わせ&lt;br /&gt;Deer5 が来た&lt;br /&gt;おもちゃを配る&lt;br /&gt;Elf2 が来た&lt;br /&gt;Elf7 が来た&lt;br /&gt;Elf9 が来た&lt;br /&gt;小人と打ち合わせ&lt;br /&gt;Deer9 が来た&lt;br /&gt;Deer5 が来た&lt;br /&gt;Elf4 が来た&lt;br /&gt;Elf6 が来た&lt;br /&gt;Elf3 が来た&lt;br /&gt;小人と打ち合わせ&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8279598009658361638?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8279598009658361638/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/12/fantom.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8279598009658361638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8279598009658361638'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/12/fantom.html' title='Fantom でサンタクロース問題'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3042838018536129456</id><published>2011-11-29T00:20:00.001+09:00</published><updated>2011-11-29T01:32:39.241+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><title type='text'>Fantom でせんだみつおゲーム</title><content type='html'>&lt;p&gt;Youtube 観てたら、古いテレビの録画で、&lt;a href="http://ja.wikipedia.org/wiki/%E3%81%9B%E3%82%93%E3%81%A0%E3%81%BF%E3%81%A4%E3%81%8A#.E3.81.9B.E3.82.93.E3.81.A0.E3.81.BF.E3.81.A4.E3.81.8A.E3.82.B2.E3.83.BC.E3.83.A0"&gt;せんだみつおゲーム&lt;/a&gt;をやっていた。やっぱりプログラマだから書いてみたくなる。言語は&lt;a href="http://yasutech.blogspot.com/2011/11/fantom.html"&gt;こないだ&lt;/a&gt;見つけた、Fantom にしてみる。&lt;/p&gt;&lt;p&gt;こんな感じ&lt;ul&gt;&lt;li&gt;Actor を５つ生成して、5名の参加者に見立てる&lt;/li&gt;&lt;li&gt;メインのスレッドでは、無限ループしながら Actor にタイミングを出しつづける&lt;/li&gt;&lt;li&gt;Actor は、"SENDA", "MITSUO", "NAHANAHA"を出力しながら、ランダムに次の番のアクターを指名する&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;using concurrent&lt;br /&gt;&lt;br /&gt;class SendaMitsuoGame {&lt;br /&gt;  Void main() { play }&lt;br /&gt;&lt;br /&gt;  Void play() {&lt;br /&gt;    pool := ActorPool()&lt;br /&gt;    Actor[] actors := (1..5).map { Player(pool, it) }&lt;br /&gt;&lt;br /&gt;    actors[0].send("next1")&lt;br /&gt;    actors.each { it.send(actors.toImmutable) }&lt;br /&gt;&lt;br /&gt;    messages := ["senda", "mitsuo", "nahanaha"]&lt;br /&gt;    while (true) {&lt;br /&gt;      message := getHeadAndRotate(messages)&lt;br /&gt;      actors.each { it.send(message) }&lt;br /&gt;&lt;br /&gt;      Actor.sleep(1sec)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  Str getHeadAndRotate(Str[] m) { m.add(m.removeAt(0)).last }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;const class Player : Actor {&lt;br /&gt;  const Int number&lt;br /&gt;&lt;br /&gt;  new make(ActorPool p, Int number) : super(p) {&lt;br /&gt;    this.number = number }&lt;br /&gt;&lt;br /&gt;  override Obj? receive(Obj? msg) {&lt;br /&gt;    if (msg is List) { Actor.locals["all"] = msg }&lt;br /&gt;    else if (msg == "senda") doSenda&lt;br /&gt;    else if (msg == "mitsuo") doMitsuo&lt;br /&gt;    else if (msg == "nahanaha") doNahanaha&lt;br /&gt;    else if (0==((Str)msg).index("next")) {&lt;br /&gt;        setMyTurn(((Str)msg)["next".size..-1].toInt)&lt;br /&gt;    }&lt;br /&gt;    return null&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  Bool isNext(Int n) {&lt;br /&gt;    diff := (n - number).abs()&lt;br /&gt;    return 1 == diff || 4 == diff&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  Bool isMyTurn() { Actor.locals["myTurn"] }&lt;br /&gt;&lt;br /&gt;  Void setMyTurn(Int f) {&lt;br /&gt;    Actor.locals["myTurn"] = (number == f)&lt;br /&gt;    Actor.locals["nextOnesTurn"] = isNext(f) }&lt;br /&gt;&lt;br /&gt;  Void doSenda()  { callAndAssign("SENDA") }&lt;br /&gt;&lt;br /&gt;  Void doMitsuo() { callAndAssign("MITSUO") }&lt;br /&gt;&lt;br /&gt;  Void doNahanaha() {&lt;br /&gt;    if (Actor.locals["nextOnesTurn"])&lt;br /&gt;        echo("" + number + ": NAHANAHA");&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  Void callAndAssign(Str call) {&lt;br /&gt;    if (!isMyTurn()) return&lt;br /&gt;&lt;br /&gt;    next := nextOne()&lt;br /&gt;    echo("" + number + ": " + call + " -&gt; " + next);&lt;br /&gt;&lt;br /&gt;    ((Actor[])Actor.locals["all"]).each { it.send("next" + next) }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  Int nextOne() {&lt;br /&gt;    next := Int.random(1..4)&lt;br /&gt;    if (next &lt; number) return next&lt;br /&gt;    return (++next &lt; 6) ? next: 1&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;出力はこんな感じになる。ミスる事も無く、延々とせんだみつおゲームを繰り返す。適当な確率でミスさせる事も、もちろんできるけど、割愛。&lt;/p&gt;&lt;pre style="background-color:snow;color:black;"&gt;&lt;br /&gt;$ fan senda.fan &lt;br /&gt;1: SENDA -&gt; 2&lt;br /&gt;2: MITSUO -&gt; 5&lt;br /&gt;1: NAHANAHA&lt;br /&gt;4: NAHANAHA&lt;br /&gt;5: SENDA -&gt; 1&lt;br /&gt;1: MITSUO -&gt; 3&lt;br /&gt;4: NAHANAHA&lt;br /&gt;2: NAHANAHA&lt;br /&gt;3: SENDA -&gt; 5&lt;br /&gt;5: MITSUO -&gt; 4&lt;br /&gt;5: NAHANAHA&lt;br /&gt;3: NAHANAHA&lt;br /&gt;4: SENDA -&gt; 3&lt;br /&gt;3: MITSUO -&gt; 1&lt;br /&gt;5: NAHANAHA&lt;br /&gt;2: NAHANAHA&lt;br /&gt;1: SENDA -&gt; 4&lt;br /&gt;4: MITSUO -&gt; 5&lt;br /&gt;1: NAHANAHA&lt;br /&gt;4: NAHANAHA&lt;br /&gt;&lt;/pre&gt;しかし夜遅くまで、俺、何書いてんだ・・・&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3042838018536129456?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3042838018536129456/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/fantom_29.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3042838018536129456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3042838018536129456'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/fantom_29.html' title='Fantom でせんだみつおゲーム'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-9136027644715888429</id><published>2011-11-25T02:56:00.001+09:00</published><updated>2011-11-26T14:10:51.196+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><title type='text'>Groovy + POI</title><content type='html'>&lt;p&gt;Groovy では、クロージャを使って若干の下準備（下例では TableBuilder）をしておくと、以下のようなコードが書ける。&lt;pre class="prettyprint"&gt;&lt;br /&gt;static void main(args) {&lt;br /&gt;   new TableBuilder().with {&lt;br /&gt;     sheet(   "test"&lt;br /&gt;         )(   style(header)&lt;br /&gt;         )(   "No"   )(   "名前"      )( nextRow&lt;br /&gt;         )(   style(normal)&lt;br /&gt;         )(   1      )(   "琵琶湖"    )( nextRow&lt;br /&gt;         )(   2      )(   "多来加湖"  )( nextRow&lt;br /&gt;         )(   3      )(   "富内湖"    )( endTable   )&lt;br /&gt;   }.write(new FileOutputStream("sample.xls"));&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;TableBuilder の中では、Apache POI を使っていて、実行すると 下のような Excel ファイルが sample.xls に書き出される。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-EAK6wbwGObc/Ts_MTwTlMeI/AAAAAAAAAR8/CgbQxXR3VJ0/s1600/closure_sample.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="193" width="223" src="http://2.bp.blogspot.com/-EAK6wbwGObc/Ts_MTwTlMeI/AAAAAAAAAR8/CgbQxXR3VJ0/s320/closure_sample.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;カッコの開き方が気に入らないが、しょうがないらしい。下の A、B は等価だけど、C は別ものに解釈される。上例を C のようなカッコのに直すと、動作しない。&lt;table border="0" cellspacing="0" cellpadding="0" style="width:95%;background-color:snow;color:black;"&gt;&lt;tr&gt;&lt;th style="text-align:center;"&gt;A&lt;/th&gt;&lt;th style="text-align:center;"&gt;B&lt;/th&gt;&lt;th style="text-align:center;"&gt;C&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style="margin:0px 10px 0px 10px;"&gt;   ("A1")("B1")(&lt;br /&gt;    "A2")("B2")&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style="margin:0px 10px 0px 10px;"&gt;    ("A1")("B1"&lt;br /&gt;   )("A2")("B2")&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style="margin:0px 10px 0px 10px;"&gt;   ("A1")("B1")&lt;br /&gt;   ("A2")("B2")&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;TableBuilder は下のコードのようになる。&lt;pre class="prettyprint"&gt;class TableBuilder {&lt;br /&gt;   def book&lt;br /&gt;   TableBuilder() { book = new HSSFWorkbook() }&lt;br /&gt;   def nextRow = { cell, style -&gt;&lt;br /&gt;      cursor.curry(cell.offset(1, -cell.columnIndex), style)&lt;br /&gt;   }&lt;br /&gt;   def endTable = { cell, style -&gt; book }&lt;br /&gt;   def cursor = { cell, style, arg -&gt;&lt;br /&gt;      if (arg instanceof Closure) { arg(cell, style) }&lt;br /&gt;      else { &lt;br /&gt;         cell.setCellValue(arg)&lt;br /&gt;         if (null != style) cell.cellStyle = style &lt;br /&gt;         cursor.curry(cell.next(), style) &lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   def start(sheet){ cursor.curry(sheet.cellAt(0, 0), null) }&lt;br /&gt;   def sheet(name) { start(book.createSheet(name)) }&lt;br /&gt;   def style(styleClosure) {&lt;br /&gt;      { cell, style-&gt; cursor.curry(cell, styleClosure(book))}}&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;また、POI の API が Groovy コードの中で馴染むように、Mixin でメソッドを追加した。&lt;pre class="prettyprint"&gt;class CellMix {&lt;br /&gt;   def next() { offset(0, 1) }&lt;br /&gt;   def offset(r, c) {&lt;br /&gt;      sheet.cellAt(rowIndex + r, columnIndex + c) }&lt;br /&gt;}&lt;br /&gt;class RowMix {&lt;br /&gt;   def cellAt(c) { getCell(c) ?: createCell(c) }&lt;br /&gt;}&lt;br /&gt;class SheetMix {&lt;br /&gt;   def rowAt(r) { getRow(r) ?: createRow(r) }&lt;br /&gt;   def cellAt(r, c) { rowAt(r).cellAt(c); }&lt;br /&gt;}&lt;br /&gt;class CellStyleMix {&lt;br /&gt;   def borderMethodName = { s-&gt; "setBorder" + s.capitalize() }&lt;br /&gt;   def setBorder = { arg, edge -&gt; &lt;br /&gt;      owner."${borderMethodName(edge)}"(arg."$edge" ?:BORDER_NONE); &lt;br /&gt;      setBorder.curry(arg) }&lt;br /&gt;   def setBorder(Map arg) {&lt;br /&gt;   setBorder.curry(arg)("top")("left")("bottom")("right") }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;カッコを連鎖させるやり方にしたのは、単にクロージャとカリー化を試したかっただけで、実は、普通のクラスと leftShift() のオーバライドだけで、下のような C++風の書き方もできて、こっちの方がむしろスッキリしたコードになる。&lt;pre class="prettyprint"&gt;sheet("test") &lt;&lt; &lt;br /&gt;   "A1" &lt;&lt; "B1" &lt;&lt; endRow &lt;&lt;&lt;br /&gt;   "A2" &lt;&lt; "B2" &lt;&lt; endTable&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-9136027644715888429?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/9136027644715888429/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/groovy-poi.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9136027644715888429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9136027644715888429'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/groovy-poi.html' title='Groovy + POI'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-EAK6wbwGObc/Ts_MTwTlMeI/AAAAAAAAAR8/CgbQxXR3VJ0/s72-c/closure_sample.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8346927020204090046</id><published>2011-11-23T18:50:00.001+09:00</published><updated>2011-11-27T20:51:46.737+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other languages'/><title type='text'>Fantom</title><content type='html'>&lt;p&gt;Info Q を読んでたら、&lt;a href="http://www.infoq.com/news/2011/11/scala-ejb2"&gt;Scala は先行き暗いねって記事&lt;/a&gt;があった。その内容自体は、まあ一理あるねくらいだけど、その問題提起をしている人が、気に入ってる言語として Scala と対比してる Fantom というのがあって、ちょっと調べてみた。&lt;/p&gt;&lt;p&gt;&lt;a href="http://fantom.org/doc/examples/index.html"&gt;ここ&lt;/a&gt;でサンプルコードを読んでみると、特にキャッチーな感じはしないけど、その分、実用性を念頭に置いてる気がする。知的な遊びのためよりむしろ割と泥臭い現場でも使えるように考えられてる印象。C# が分かる Javaプログラマで、面倒くさがりな人向けって感じか。言語仕様とか文法のパラダイムよりも、バイトコードやモジュールの扱いみたいなアーキテクチャ寄りの面に長所があるのかもしれない。&lt;/p&gt;&lt;p&gt;Linux にインストールするには、&lt;ul&gt;&lt;li&gt;オフィシャルサイトの&lt;a href="http://fantom.org/"&gt;トップページ&lt;/a&gt;からダウンロードして、&lt;/li&gt;&lt;li&gt;適当なところに展開して、fantom-1.0.XX フォルダの中に入る&lt;/li&gt;&lt;li&gt;adm/unixsetup を実行して bin/下のファイル群に実行権限を付ける&lt;/li&gt;&lt;li&gt;bin/fan -versionを実行して、動作確認&lt;/li&gt;&lt;li&gt;必要に応じて PATH にbin/を追加する&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;以下のようにして、FWT という GUI 上の HelloWorld ができる。&lt;ul&gt;&lt;li&gt;ファイル FwtHello.fan に以下のコードを書く&lt;pre class="prettyprint"&gt;using fwt&lt;br /&gt;class FwtHello : Test&lt;br /&gt;{&lt;br /&gt;  Void main()&lt;br /&gt;  {&lt;br /&gt;    Window { Label { text = "Hello world" }, }.open&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;$ fan FwtHello.fan で以下のようなちっこいウィンドウが表示される。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-LLzImV-Kixc/TszO2TasMwI/AAAAAAAAARw/CWM1rv4StBc/s1600/FwtHello.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="59" width="85" src="http://4.bp.blogspot.com/-LLzImV-Kixc/TszO2TasMwI/AAAAAAAAARw/CWM1rv4StBc/s320/FwtHello.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;全然、Fantom とは関係ない話だけど、Fantom についていろいろググってて、Fantom で迷路の最短経路をとくパズルをやってる人がいたので、その先をたどると面白い記事を見つけた。&lt;/p&gt;&lt;p&gt;問題は「&lt;a href="http://okajima.air-nifty.com/b/2010/01/post-abc6.html"&gt;人材獲得作戦・４　試験問題ほか&lt;/a&gt;」に載ってて、この問題をどのように使ったかという顛末（「&lt;a href="http://okajima.air-nifty.com/b/2009/12/post-f94c.html"&gt;人材獲得作戦・３&lt;/a&gt;」）まで書かれていてとても面白い。&lt;/p&gt;&lt;p&gt;ただ、「問題の性質からいって、キューやリストが必要なのは明らかなのに、言語にCを使う人が相当多い。」ってところだけ残念。以下のようにすればオブジェクト指向も関数型も論理型も関係なく簡単に解ける。&lt;ul&gt;&lt;li&gt;S の上下左右に隣接する空のマスに1 を書き込む&lt;/li&gt;&lt;li&gt;1 に隣接する上下左右の空のマスに2 を書き込む&lt;/li&gt;&lt;li&gt;・・・&lt;/li&gt;&lt;li&gt;N に隣接する上下左右の空のマスにN+1を書き込む&lt;/li&gt;&lt;li&gt;Gに着いたら、隣接するマスを N からカウントダウンする形で戻れば完成&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;コードは簡単だから省略。C 言語はもちろん、多分 COBOL でも書ける。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8346927020204090046?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8346927020204090046/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/fantom.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8346927020204090046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8346927020204090046'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/fantom.html' title='Fantom'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-LLzImV-Kixc/TszO2TasMwI/AAAAAAAAARw/CWM1rv4StBc/s72-c/FwtHello.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2273475859834288431</id><published>2011-11-23T05:35:00.001+09:00</published><updated>2011-11-23T06:49:33.199+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smalltalk'/><title type='text'>Squeak の右クリメニュー</title><content type='html'>&lt;p&gt;Fedora のソフトウェアの追加／削除から Squeak をインストールするとバージョン 3.10 の Mysqueak ってのが入ってくるけど、かなり古いものらしい。 [→&lt;a href="https://admin.fedoraproject.org/pkgdb/applications/Mysqueak?_csrf_token=fc0cb4b1db69d2b5ccd7758dbe4d7438cba3694d"&gt;参照&lt;/a&gt;]&lt;/p&gt;&lt;p&gt;で、squeak.org の&lt;a href="http://www.squeak.org/Download/"&gt;ここから&lt;/a&gt; Squeak All-in-One をダウンロードすると、バージョン 4.2 が入っている。これを適当なところで展開して、squeak.sh を実行すれば、環境が立ち上がる。&lt;p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mCWhJI5M-Wg/TswWyZgrLlI/AAAAAAAAARk/8LYz_fuBlu8/s1600/squeak4.2.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="249" width="320" src="http://3.bp.blogspot.com/-mCWhJI5M-Wg/TswWyZgrLlI/AAAAAAAAARk/8LYz_fuBlu8/s320/squeak4.2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;ちなみに今使っている Linux 環境では、特に設定しなくても、右クリで 'do it'を含むコンテキストメニューがポップアップされたけど、古いやつはマウスの設定を変える必要があった。&lt;ul&gt;&lt;li&gt;何もない背景のとこで左クリック&lt;/li&gt;&lt;li&gt;World のメニューが出てくるので[open...]を選択&lt;/li&gt;&lt;li&gt;サブメニュー[Preference Browser]を選択&lt;/li&gt;&lt;li&gt;"mouse"でフィルタすると [swapMouseButtons] ってのが出てくるので、enabled にチェックを入れる&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;p&gt;Windows 版だと、今のバージョンでもそんな設定が必要になる事もあるらしい。［→&lt;a href="http://stackoverflow.com/questions/6802219/squeak-smalltalk-why-cant-i-activate-the-do-it-menu"&gt;参照&lt;/a&gt;］&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2273475859834288431?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2273475859834288431/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/squeak.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2273475859834288431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2273475859834288431'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/squeak.html' title='Squeak の右クリメニュー'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-mCWhJI5M-Wg/TswWyZgrLlI/AAAAAAAAARk/8LYz_fuBlu8/s72-c/squeak4.2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6089066667779183706</id><published>2011-11-21T20:52:00.001+09:00</published><updated>2011-11-21T22:32:36.080+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><title type='text'>LePUS3</title><content type='html'>昨日のブログを書くために、&lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Wikipedia の Strategy パターンのエントリ&lt;/a&gt;を開いてみたら、見慣れないものがあった。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-_YalhOgA3C0/Tso7iXfy24I/AAAAAAAAARY/F_OZlQx0uBg/s1600/Strategy_pattern_in_LePUS3.gif" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="87" width="320" src="http://4.bp.blogspot.com/-_YalhOgA3C0/Tso7iXfy24I/AAAAAAAAARY/F_OZlQx0uBg/s320/Strategy_pattern_in_LePUS3.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;なんかかっけえ。フリーメイソンとかみたいだ。三角のとことか。&lt;p&gt;LePUS3 というダイアグラムらしい。五十音的には、レプスさんくらいの感じだろうか。&lt;/p&gt;&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/LePUS3"&gt;Wikipedia によると&lt;/a&gt;&lt;ul&gt;&lt;li&gt;UML と同様のオブジェクト指向モデリング言語である。&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Formal_specification"&gt;formal specification&lt;/a&gt; language(形式仕様記述言語) の一つである。&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/First-order_predicate_logic"&gt;First-order predicate logic&lt;/a&gt;(一階述語論理)のサブセットである&lt;/li&gt;&lt;li&gt;Codechart とも呼ばれる&lt;/li&gt;&lt;li&gt;いいところ&lt;ul&gt;&lt;li&gt;&lt;b&gt;スケーラビリティ&lt;/b&gt; ：少しの記号を用いた小さな Codecharts で、大規模なプログラムをモデリングできる&lt;/li&gt;&lt;li&gt;&lt;b&gt;自動検証&lt;/b&gt; ：設計と実装を同期させて、自動的に適合性を検証できる&lt;/li&gt;&lt;li&gt;&lt;b&gt;可視化&lt;/b&gt; ：リバースでソースコードから Codecharts を生成しやすい&lt;/li&gt;&lt;li&gt;&lt;b&gt;パターンの実装&lt;/b&gt; ：プログラムがデザインパターンを実装しているかどうか、自動的に判断できる&lt;/li&gt;&lt;li&gt;&lt;b&gt;設計抽象化&lt;/b&gt; ：実装の詳細に取りかかる前に抽象的なプログラムを表現できる&lt;/li&gt;&lt;li&gt;&lt;b&gt;総称&lt;/b&gt; ：特定の実装ではなく、設計のモチーフとしてデザインパターンを表現できる&lt;/li&gt;&lt;li&gt;&lt;b&gt;厳密性&lt;/b&gt;：設計者は Codecharts によるモデルを厳密に検証できる&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;いつのまにか、Wikipedia のプログラム関連のエントリの、至る所で LePUS3 が使われている。全然、気がつかなかった&lt;/p&gt;&lt;p&gt;オフィシャルサイトは&lt;a href="http://www.lepus.org.uk/"&gt;ここ&lt;/a&gt;&lt;/p&gt;&lt;p&gt;この本で紹介されている。&lt;br/&gt;&lt;a href="http://amazon.co.jp/o/ASIN/0470626941/yasuabe1984-22/ref=nosim"&gt;&lt;img src="http://images.amazon.com/images/P/0470626941.09._OU09_SCTZZZZZZZ_.jpg" alt="Codecharts"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;自分は注文したけど、しかし高い。&lt;br/&gt;7300円もか。そんなにもか・・・&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6089066667779183706?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6089066667779183706/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/wikipedia-strategy-lepus3-wikipedia-uml.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6089066667779183706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6089066667779183706'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/wikipedia-strategy-lepus3-wikipedia-uml.html' title='LePUS3'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-_YalhOgA3C0/Tso7iXfy24I/AAAAAAAAARY/F_OZlQx0uBg/s72-c/Strategy_pattern_in_LePUS3.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-532953901434785725</id><published>2011-11-20T19:16:00.001+09:00</published><updated>2011-11-21T00:52:57.276+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><title type='text'>OSGi で GoF の Strategy</title><content type='html'>&lt;p&gt;久しぶりに OSGi でもいじってみるかと思い立つ。&lt;/p&gt;&lt;p&gt;Wikipedia に載ってる &lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern#Example"&gt;Strategy パターンの サンプル・コード&lt;/a&gt;でも OSGi で動かしてみよっかなと。今回は、Equinox でやってみる。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;OSGi 環境を作る&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;適当な場所に osgi-test フォルダを作る&lt;/li&gt;&lt;li&gt;osgi-test フォルダ 下に plugins フォルダ を作る&lt;/li&gt;&lt;li&gt;Eclipse の plugins下から以下のファイルを osgi-test/plugins フォルダ 下にコピーする。&lt;ul&gt;&lt;li&gt;org.eclipse.osgi_*.jar&lt;/li&gt;&lt;li&gt;org.eclipse.equinox.ds_*.jar&lt;/li&gt;&lt;li&gt;org.eclipse.equinox.util_*.jar&lt;/li&gt;&lt;li&gt;org.eclipse.osgi.services_*.jar&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;うちの環境だとこんな感じになる&lt;pre style="color:navy;background-color:snow;line-height:124%;"&gt;$ cd /tmp/osgi-test&lt;br /&gt;$ tree&lt;br /&gt;.&lt;br /&gt;└── plugins&lt;br /&gt;    ├── org.eclipse.equinox.ds_1.3.1.R37x_v20110701.jar&lt;br /&gt;    ├── org.eclipse.equinox.util_1.0.300.v20110502.jar&lt;br /&gt;    ├── org.eclipse.osgi.services_3.3.0.v20110513.jar&lt;br /&gt;    └── org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;起動して、他のプラグインも追加しておく&lt;pre style="color:navy;background-color:snow;line-height:124%;overflow:auto;"&gt;$ java -jar plugins/org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -console&lt;br /&gt;&lt;br /&gt;osgi&gt; ss&lt;br /&gt;Framework is launched.&lt;br /&gt;id State       Bundle&lt;br /&gt;0 ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106&lt;br /&gt;&lt;br /&gt;osgi&gt; install file:///tmp/osgi-test/plugins/org.eclipse.osgi.services_3.3.0.v20110513.jar&lt;br /&gt;Bundle id is 1&lt;br /&gt;osgi&gt; install file:///tmp/osgi-test/plugins/org.eclipse.equinox.util_1.0.300.v20110502.jar&lt;br /&gt;Bundle id is 2&lt;br /&gt;osgi&gt; install file:///tmp/osgi-test/plugins/org.eclipse.equinox.ds_1.3.1.R37x_v20110701.jar&lt;br /&gt;Bundle id is 3&lt;br /&gt;&lt;br /&gt;osgi&gt; start 1&lt;br /&gt;osgi&gt; start 2&lt;br /&gt;osgi&gt; start 3&lt;br /&gt;osgi&gt; ss&lt;br /&gt;Framework is launched.&lt;br /&gt;id State       Bundle&lt;br /&gt;0 ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106&lt;br /&gt;1 ACTIVE      org.eclipse.osgi.services_3.3.0.v20110513&lt;br /&gt;2 ACTIVE      org.eclipse.equinox.util_1.0.300.v20110502&lt;br /&gt;3 ACTIVE      org.eclipse.equinox.ds_1.3.1.R37x_v20110701&lt;/pre&gt;&lt;p&gt;&lt;p&gt;環境が出来たので、以降ではプラグインを作って動かしてみる。先に書いたとおり、Wikipedia にある Strategy のサンプルコードをネタにして、Strategy、ConcreteStrategyAdd、ConcreteStrategyMultiply、Context を連動させてみる。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;Strategy の作成〜インストール&lt;/p&gt;&lt;p&gt;まずは、Strategy プラグインプロジェクトの作成&lt;ul&gt;&lt;li&gt;[New]-&gt;[Plugin-Project]&lt;/li&gt;&lt;li&gt;Project Name には "ex1.osgi.strategy.strategy"を指定、Activetor 無し、tempate 不使用で[Finish]&lt;/li&gt;&lt;li&gt;MANIFEST.MF の [Runtime]タブを開いて、[Exported Packages]に"ex1.osgi.strategy.strategy" を追加する。&lt;/li&gt;&lt;li&gt;以下の Wikipedia から持ってきた、以下のコードを追加する&lt;pre class="prettyprint"&gt;package ex1.osgi.strategy.strategy;&lt;br /&gt;public interface Strategy {&lt;br /&gt;   int execute(int a, int b);&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;できたら以下のように Export しておく。&lt;ul&gt;&lt;li&gt;プロジェクトのコンテキストメニューから、[Export]-&gt;[Deployable plug-ins and fragments] を選択&lt;/li&gt;&lt;li&gt;[Destination] / [Directory]に、osgi-test フォルダを指定する&lt;/li&gt;&lt;li&gt;[Options] で、"Package plug-ins as individual JAR archives"のみチェックされている事を確認して[Finish]&lt;/li&gt;&lt;/ul&gt;エクスポートしたら、OSGi に install しておく&lt;pre style="color:navy;background-color:snow;line-height:124%;"&gt;osgi&gt; install file:///tmp/osgi-test/plugins/ex1.osgi.strategy.strategy_1.0.0.201111202011.jar&lt;br /&gt;Bundle id is 4&lt;br /&gt;osgi&gt; refresh&lt;br /&gt;osgi&gt; ss&lt;br /&gt;Framework is launched.&lt;br /&gt;id State       Bundle&lt;br /&gt;0 ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106&lt;br /&gt;1 ACTIVE      org.eclipse.osgi.services_3.3.0.v20110513&lt;br /&gt;2 ACTIVE      org.eclipse.equinox.util_1.0.300.v20110502&lt;br /&gt;3 ACTIVE      org.eclipse.equinox.ds_1.3.1.R37x_v20110701&lt;br /&gt;4 RESOLVED    ex1.osgi.strategy.strategy_1.0.0.201111202011&lt;/pre&gt;ss や refresh といったコマンドの意味は、OSGi コンソールから help と打てば、説明が出てくる。&lt;p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;ConcreteStrategyAdd の作成〜インストール&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;[New]-&gt;[Plugin-Project]&lt;/li&gt;&lt;li&gt;Project Name には "ex1.osgi.strategy.add"を指定、Activetor 無し、tempate 不使用で[Finish]&lt;/li&gt;&lt;li&gt;MANIFEST.MF の [Dependencies]タブを開いて、[Required Plugins]に"ex1.osgi.strategy.strategy" を追加する。&lt;/li&gt;&lt;li&gt;以下のようにコード追加する。&lt;pre class="prettyprint"&gt;package ex1.osgi.strategy.add;&lt;br /&gt;import ex1.osgi.strategy.strategy.Strategy;&lt;br /&gt;&lt;br /&gt;public class ConcreteStrategyAdd implements Strategy {&lt;br /&gt;    public int execute(int a, int b) {&lt;br /&gt;        System.out.println("Called ConcreteStrategyAdd's execute()");&lt;br /&gt;        return a + b;  // Do an addition with a and b&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;プロジェクト直下に OSGI-INF フォルダを追加する&lt;/li&gt;&lt;li&gt;OSGI-INF フォルダのコンテキストメニューから、[New]-&gt;[Component Definition]を選択&lt;/li&gt;&lt;li&gt;"Component Definition Information" / Class に ex1.osgi.strategy.add.ConcreteStrategyAdd を指定して[Finish]&lt;/li&gt;&lt;li&gt;component.xml の Service タブで、[Provided Services]に ex1.osgi.strategy.strategy.Strategy を追加する&lt;/li&gt;&lt;/ul&gt;これも Export して、OSGi にインストールしておく。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;Context の作成〜インストール&lt;/p&gt;次は ConcreteStrategyMultiply をやる前に、Context に行ってみる&lt;p&gt;&lt;ul&gt;&lt;li&gt;[New]-&gt;[Plugin-Project]&lt;/li&gt;&lt;li&gt;Project Name には "ex1.osgi.strategy.context"を指定、Activetor 無し、tempate 不使用で[Finish]&lt;/li&gt;&lt;li&gt;MANIFEST.MF の [Dependencies]タブを開いて、[Imported Packages]に"ex1.osgi.strategy.strategy" を追加する。&lt;/li&gt;&lt;li&gt;以下のコードを追加する。Wikipedia のサンプルコードでは、Context#executeStrategy() を実行するのは StrategyExample#main() だけど、面倒だから strategy が関連付けられたときに Context 自身が executeStrategy() のテストコードを実行するようにした。&lt;pre class="prettyprint"&gt;package ex1.osgi.strategy.context;&lt;br /&gt;import ex1.osgi.strategy.strategy.Strategy;&lt;br /&gt;&lt;br /&gt;public class Context {&lt;br /&gt;   private Strategy strategy;&lt;br /&gt; &lt;br /&gt;   public synchronized void setStrategy(final Strategy strategy) {&lt;br /&gt;      this.strategy = strategy;&lt;br /&gt;      testExecuteStrategy();&lt;br /&gt;   }&lt;br /&gt;   public synchronized void unsetStrategy(final Strategy strategy) {&lt;br /&gt;      if (strategy == this.strategy) this.strategy = null;&lt;br /&gt;   }&lt;br /&gt;   public int executeStrategy(int a, int b) {&lt;br /&gt;      return strategy.execute(a, b);&lt;br /&gt;   }&lt;br /&gt;   public void testExecuteStrategy() {&lt;br /&gt;      final long l = System.currentTimeMillis();&lt;br /&gt;      final int a = (int) (l % 10);&lt;br /&gt;      final int b = (int) (l / 10 % 10);&lt;br /&gt;      final int result = executeStrategy(a, b);&lt;br /&gt;      System.out.printf("execute(%d, %d) = %d", a, b, result);&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;プロジェクト直下に OSGI-INF フォルダを追加する&lt;/li&gt;&lt;li&gt;OSGI-INF フォルダのコンテキストメニューから、[New]-&gt;[Component Definition]を選択&lt;/li&gt;&lt;li&gt;"Component Definition Information"/Class にex1.osgi.strategy.context.Context を指定して[Finish]&lt;/li&gt;&lt;li&gt;component.xml の [Service]タブで、[Referenced Services] に Strategy を追加する&lt;/li&gt;&lt;li&gt;追加した Strategy を選択して[Edit]、"Bind"にsetStrategy、"Unbind"にunsetStrategy を指定する&lt;/li&gt;&lt;/ul&gt;できたら、これもエクスポートして、OSGiにインストールしておく。&lt;/p&gt;&lt;br/&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;動作確認&lt;/p&gt;&lt;p&gt;とりあえず、ここまでで動かしてみる。&lt;p&gt;&lt;pre style="color:navy;background-color:snow;line-height:124%;"&gt;osgi&gt; start 4&lt;br /&gt;osgi&gt; start 5&lt;br /&gt;osgi&gt; start 6&lt;br /&gt;Called ConcreteStrategyAdd's execute()&lt;br /&gt;execute(3, 1) = 4&lt;br /&gt;osgi&gt; &lt;/pre&gt;期待通りに動作する。（実は、start 4 は無くても良いし、start 5 と start 6 の順番は逆でも良い。）&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;ConcreteStrategyMultiply の追加と動作確認&lt;/p&gt;最後に、ConcreteStrategyMultiply を付け加えて、ConcreteStrategyMultiply と差し替えてみる。&lt;p&gt;&lt;ul&gt;&lt;li&gt;[New]-&gt;[Plugin-Project]&lt;/li&gt;&lt;li&gt;Project Name には "ex1.osgi.strategy.multiply"を指定、Activetor 無し、tempate 不使用で[Finish]&lt;/li&gt;&lt;li&gt;MANIFEST.MF の [Dependencies]タブを開いて、[Required Plugins]に"ex1.osgi.strategy.strategy" を追加する。&lt;/li&gt;&lt;li&gt;下のようにコード追加&lt;pre class="prettyprint"&gt;package ex1.osgi.strategy.multiply;&lt;br /&gt;import ex1.osgi.strategy.strategy.Strategy;&lt;br /&gt;&lt;br /&gt;public class ConcreteStrategyMultiply implements Strategy {&lt;br /&gt;    public int execute(int a, int b) {&lt;br /&gt;        System.out.println("Called ConcreteStrategyMultiply's execute()");&lt;br /&gt;        return a * b;   // Do a multiplication with a and b&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;プロジェクト直下に OSGI-INF フォルダを追加する&lt;/li&gt;&lt;li&gt;OSGI-INF フォルダのコンテキストメニューから、[New]-&gt;[Component Definition]を選択&lt;/li&gt;&lt;li&gt;"Component Definition Information"/Class に net.yasuabe.osgi.ex1.strategy.multiply.ConcreteStrategyMultiplyを指定して[Finish]&lt;/li&gt;&lt;li&gt;component.xml の Service タブで、[Provided Services]に ex1.osgi.strategy.strategy.Strategy を追加する&lt;/li&gt;&lt;/ul&gt;これもエクスポートして、OSGiにインストールしておく。&lt;/p&gt;&lt;p&gt;エクスポートしたら、Context から実行される Strategy を、Add から Multiply に変えてみる。&lt;pre style="color:navy;background-color:snow;line-height:124%;"&gt;osgi&gt; ss&lt;br /&gt;Framework is launched.&lt;br /&gt;&lt;br /&gt;id State       Bundle&lt;br /&gt;0 ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106&lt;br /&gt;1 ACTIVE      org.eclipse.osgi.services_3.3.0.v20110513&lt;br /&gt;2 ACTIVE      org.eclipse.equinox.util_1.0.300.v20110502&lt;br /&gt;3 ACTIVE      org.eclipse.equinox.ds_1.3.1.R37x_v20110701&lt;br /&gt;4 ACTIVE      ex1.osgi.strategy.strategy_1.0.0.201111202011&lt;br /&gt;5 ACTIVE      ex1.osgi.strategy.add_1.0.0.201111202028&lt;br /&gt;6 ACTIVE      ex1.osgi.strategy.context_1.0.0.201111202042&lt;br /&gt;7 RESOLVED    ex1.osgi.strategy.multiply_1.0.0.201111202123&lt;br /&gt;&lt;br /&gt;osgi&gt; stop 5&lt;br /&gt;osgi&gt; start 7&lt;br /&gt;Called ConcreteStrategyMultiply's execute()&lt;br /&gt;execute(3, 1) = 3&lt;br /&gt;osgi&gt; ss&lt;br /&gt;Framework is launched.&lt;br /&gt;id State       Bundle&lt;br /&gt;0 ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106&lt;br /&gt;1 ACTIVE      org.eclipse.osgi.services_3.3.0.v20110513&lt;br /&gt;2 ACTIVE      org.eclipse.equinox.util_1.0.300.v20110502&lt;br /&gt;3 ACTIVE      org.eclipse.equinox.ds_1.3.1.R37x_v20110701&lt;br /&gt;4 ACTIVE      ex1.osgi.strategy.strategy_1.0.0.201111202011&lt;br /&gt;5 RESOLVED    ex1.osgi.strategy.add_1.0.0.201111202028&lt;br /&gt;6 ACTIVE      ex1.osgi.strategy.context_1.0.0.201111202042&lt;br /&gt;7 ACTIVE      ex1.osgi.strategy.multiply_1.0.0.201111202123&lt;br /&gt;osgi&gt; stop 7&lt;br /&gt;osgi&gt; start 5&lt;br /&gt;Called ConcreteStrategyAdd's execute()&lt;br /&gt;execute(4, 3) = 7&lt;br /&gt;osgi&gt; &lt;br /&gt;&lt;/pre&gt;Context を起動したまま、Strategy を差し替えられるのが確認できる。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;雑感&lt;/p&gt;&lt;p&gt;今まで、何回か、いわゆるパッケージ開発案件に関わってきたけど、納品先個別の要件の扱い方について、何パターンかの手法がある。&lt;/p&gt;&lt;p&gt;一番泥臭いのだと、トランクのソースコードに個別要件対応のコードを入れてしまって、条件文で切り分けるというベタベタのローテク手法がある。「バカじゃね？」って思う人も多いかもしれないけど、実際の現場では結構多い。&lt;/p&gt;&lt;p&gt;それよりは、少しはマシな手法だと、納品先別にブランチを切って個別要件はそこに入れていくという事になる。まあ、これも知的な方法とは言いにくいけど、割と普通に行われている。&lt;/p&gt;&lt;p&gt;もっと良い方法としては、パッケージ共通部分と個別にカスタマイズ可能な部分について最初に見通しを立てた上で、カスタマイズ可能な部分がプラガブルになるようにアーキテクチャを設計する手法がある。&lt;/p&gt;&lt;p&gt;この手法をとると、機能の差し替えや追加、また管理面においてもリスクが少なくて、柔軟なソフトウェアになるんだけど、この場合にもさらに、プラグインの方式を自分で作るか、既存の仕様や製品を使うかで道が分かれる。&lt;/p&gt;&lt;p&gt;必ずしも自作にこだわる必要がないとしたら、OSGi がかなりの有力候補なのではないかと思う。（個人的には、はっきり言って、かなり高い割合で自作の道を取るのは不正解だと思うけど。）&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-532953901434785725?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/532953901434785725/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/osgi-gof-strategy.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/532953901434785725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/532953901434785725'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/osgi-gof-strategy.html' title='OSGi で GoF の Strategy'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2252248130231713233</id><published>2011-11-19T18:33:00.001+09:00</published><updated>2011-11-20T02:53:59.243+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Eclipse + Groovy + NekoHTML</title><content type='html'>&lt;p&gt;Redmine や Trac の wiki などを使ってプロジェクト内で情報共有している HTMLベースのコンテンツを、プログラムで取り扱うやり方を考えていて、Groovy でも使ってみようかと思い立つ。&lt;/p&gt;&lt;p&gt;で、やっぱり Eclipse で使いたいのでプラグインを入れる。Indigo なら &lt;a href="http://dist.springsource.org/release/GRECLIPSE/e3.7/"&gt;update site は ここ&lt;/a&gt;で、Required とマークされている Groovy Eclipse ってのがあるから、これを選択してインストール。&lt;/p&gt;&lt;p&gt;インストールできたら、お試しプロジェクトを作る。パッケージエクスプローラ上の右クリから New -&gt; Other と進むと、Groovy Project がリストに出てくるから、選択して適当に操作すると、Groovy Project が生成される。&lt;/p&gt;&lt;p&gt;適当に Hello World を書いて、main() メソッド上の右クリから[Run As]を選択すると、サブメニュー、[1 Groovy Console], [2 Groovy Script], [3 Java Application]が表示される。どれを選んでも、同じコードが同じように実行される。&lt;/p&gt;&lt;p&gt;これで、Eclipse で Groovy が使える書けるようになった。&lt;/p&gt;&lt;p&gt;Groovy 自体、たいして使ったことがないので、練習がてら「wikipedia の適当なページから「他の言語」にリストアップされている言語を、標準出力に書き出す」という簡単なお題をやってみる事にする。&lt;/p&gt;&lt;p&gt;Groovy で HTTP GET や HTML/XML を扱う方法をググりながら、以下のようなコードを書いてみた。&lt;pre class="prettyprint"&gt;class Ex2 {&lt;br /&gt;   static void main(args){&lt;br /&gt;      new XmlSlurper(&lt;br /&gt;            new org.cyberneko.html.parsers.SAXParser())&lt;br /&gt;         .parse("http://ja.wikipedia.org/wiki/秋刀魚")&lt;br /&gt;         .depthFirst()&lt;br /&gt;         .grep{it.name() == 'DIV' &amp;&amp; it.@id == 'p-lang'}[0]&lt;br /&gt;         .DIV.UL.LI.each { println it.text() }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Eclipse から実行すると、秋刀魚を解説している10個の言語の名前が書き出される。あまり便利ではなかったが、デバッガも一応使える。&lt;/p&gt;&lt;p&gt;XmlSlurper のコンストラクタに渡しているものは、NekoHtml の SAXParser というやつで、HTML にタグを補完して well-formed な XML として扱えるようにしてくれる。&lt;/p&gt;&lt;p&gt;使えるようにするには、&lt;a href="http://nekohtml.sourceforge.net/"&gt;ここ&lt;/a&gt;から zip か tgz をダウンロードして、中の nekohtml.jar と xercesImpl.jar （または xercesMinimal.jar ）を、~/.groovy/lib 下に置けばいい。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2252248130231713233?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2252248130231713233/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/eclipse-groovy-nekohtml.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2252248130231713233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2252248130231713233'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/eclipse-groovy-nekohtml.html' title='Eclipse + Groovy + NekoHTML'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6087439598587456934</id><published>2011-11-13T16:47:00.001+09:00</published><updated>2011-11-13T17:59:00.603+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logic programming'/><title type='text'>論理パズル で Prolog のウォーミングアップ</title><content type='html'>&lt;p&gt;テストケース（開発者が作る、いわゆる DeveloperTest のテストケースじゃなくて、開発はやらないテスト部隊が使うテストケース）を作るための小道具として Prolog を使うと便利かもと思って、自宅の環境に SWI-Prolog を用意してみた。&lt;/p&gt;&lt;p&gt;Fedora の「ソフトウェアの追加／削除」でリストアップされてたので、選択して適用するだけでインストールできた。&lt;/p&gt;&lt;p&gt;本当は、与えられた条件にしたがって、縦に要因、横にテストケースを並べた直交表もどきの表を生成するような仕組みを作りたいんだけど、その前にウォーミングアップしてみる。&lt;/p&gt;&lt;p&gt;手元にある論理パズル集の中から簡単なものを選んで、Prolog で解いてみる事にする。&lt;/p&gt;&lt;p&gt;お題は以下のようなもの。&lt;ul&gt;&lt;li&gt;とあるミスコンで、好美、恵美、明美、麻美、宏美が予選通過した&lt;/li&gt;&lt;li&gt;なかよし4人組が以下のように優勝者を予想した&lt;ul&gt;&lt;li&gt;まゆみ：好美と恵美ではないだろう&lt;/li&gt;&lt;li&gt;大貴：恵美か明美だろう&lt;/li&gt;&lt;li&gt;崇臣：好美か麻美だろう&lt;/li&gt;&lt;li&gt;やす美：好美と麻美ではないだろう&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;予想が的中した人数は２名だった。&lt;/li&gt;&lt;/ul&gt;優勝したのはだれか？&lt;/p&gt;あまり Prolog に詳しいわけではないけど、素朴に書くと以下のようになるのではないだろうか。&lt;pre class="prettyprint"&gt;&lt;br /&gt;% 出場者&lt;br /&gt;contestant(akemi). &lt;br /&gt;contestant(asami). &lt;br /&gt;contestant(hiromi). &lt;br /&gt;contestant(emi). &lt;br /&gt;contestant(yoshimi).&lt;br /&gt;&lt;br /&gt;% 誰が誰の優勝を予想しているか&lt;br /&gt;expect(mayumi, akemi). expect(mayumi, asami). expect(mayumi, hiromi).&lt;br /&gt;expect(daiki, akemi). expect(daiki, emi).&lt;br /&gt;expect(takaomi, yoshimi). expect(takaomi, asami).&lt;br /&gt;expect(yasumi, emi). expect(yasumi, akemi). expect(yasumi, asami).&lt;br /&gt;&lt;br /&gt;% 結局、優勝者は２名の予想者に予想された出場者だった&lt;br /&gt;winner(Contestant):- expectors(Contestant, 2).&lt;br /&gt;&lt;br /&gt;% 優勝者と予想者数の関係&lt;br /&gt;expectors(Contestant, Count):-&lt;br /&gt;  contestant(Contestant),  &lt;br /&gt;  countExpectators(Contestant, [mayumi, daiki, takaomi, yasumi], Count).&lt;br /&gt;&lt;br /&gt;% 優勝者を予想した人を数える&lt;br /&gt;countExpectators(_, [], 0 ).&lt;br /&gt;countExpectators(Contestant, [Expector|OtherExpectors], Count) :-&lt;br /&gt;  expect(Expector, Contestant), &lt;br /&gt;  countExpectators(Contestant, OtherExpectors, Count2),&lt;br /&gt;  Count is Count2 + 1.&lt;br /&gt;countExpectators(Contestant, [Expector|OtherExpectors], Count) :-&lt;br /&gt;  not(expect(Expector, Contestant)),&lt;br /&gt;  countExpectators(Contestant, OtherExpectors, Count).&lt;br /&gt;&lt;/pre&gt;これを SWI-Prolog に読ませて、以下のようにすると答えが出る。&lt;pre style="background-color:black;color:snow;"&gt;&lt;br /&gt;?- winner(Winner).&lt;br /&gt;Winner = emi .&lt;/pre&gt;ちなみに明美の優勝を予想した人数は、上で定義した述語 expectors 使って、以下のように求められる。&lt;pre style="background-color:black;color:snow;"&gt;&lt;br /&gt;?- expectors(akemi, Count).&lt;br /&gt;Count = 3 .&lt;/pre&gt;逆に、同じ expectors を使って、3名が優勝を予想した出場者を求めることもできる。これがPrologの面白いところでもある。&lt;pre style="background-color:black;color:snow;"&gt;&lt;br /&gt;?- expectors(W, 3).&lt;br /&gt;W = akemi ;&lt;br /&gt;W = asami ;&lt;br /&gt;false.&lt;/pre&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;ソフトウェアのテストケースを作ろうとすると、あるテスト対象の振る舞いに影響を与える条件群について、すべての条件を掛け合わせると現実的でないテストケース数になったりする&lt;/p&gt;&lt;p&gt;なので、少ないテストケース数でなるべく各条件を網羅できるように工夫する事になるんだけど、その辺りの作業がちょっとしたパズルみたいになってくる事がある。&lt;/p&gt;&lt;p&gt;で、せっかくプログラミングを生業としているのだから、プログラムでなんとかしようかって発想になるんだけど、手続き型言語を使うと、やりたい事とコード上の表現がいまいち直截性に欠けていたりする。&lt;/p&gt;&lt;p&gt;あまり流行ってはいなけど、こういう時は Prolog が割と使えそうな気がしないでもない。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6087439598587456934?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6087439598587456934/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/developertest-prolog-swi-prolog-fedora.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6087439598587456934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6087439598587456934'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/developertest-prolog-swi-prolog-fedora.html' title='論理パズル で Prolog のウォーミングアップ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-4243198173875197683</id><published>2011-11-10T22:55:00.001+09:00</published><updated>2011-11-19T20:20:32.402+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開発インフラ'/><title type='text'>Fedora のアップグレードで平常心の訓練</title><content type='html'>&lt;p&gt;Fedora 16 が昨日か一昨日リリースされたので、Fedora15 からアップグレードしてみた。&lt;/p&gt;&lt;p&gt;まず、&lt;a href="http://fedoraproject.org/wiki/Upgrading_Fedora_using_yum#Fedora_15_-.3E_Fedora_16"&gt;Fedora のサイト&lt;/a&gt;に書いてあるアップグレード手順どおりにやってみる。&lt;/p&gt;&lt;pre style="color:black;background-color:snow;"&gt;&lt;br /&gt;rpm --import https://fedoraproject.org/static/A82BA4B7.txt&lt;br /&gt;yum update yum&lt;br /&gt;yum clean all&lt;br /&gt;yum --releasever=16 --disableplugin=presto distro-sync&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;うん。やっぱり、うまくいかない。&lt;br/&gt;&lt;code style="color:white;"&gt;--skip-broken&lt;/code&gt; が使えないからとか何とかメッセージが出て、途中で止まる。&lt;/p&gt;&lt;p&gt;まあ、初めはいつもこんなもんだ。俺は、ぜんぜん動じない。で、ちょっと調べて以下のようにして再挑戦。&lt;/p&gt;&lt;pre style="color:black;background-color:snow;"&gt;&lt;br /&gt;yum --releasever=16 --disableplugin=presto distro-sync --skip-broken&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;今度は、 「Transaction Check Error で、&lt;code style="color:white;"&gt;gnome-icon-theme-symbolic&lt;/code&gt; と &lt;code style="color:white;"&gt;gnome-power-manager&lt;/code&gt; が keyboard-brightness-symbolic.svg のアレやら何やら（意訳）」とか言ってくる。こやつめ、ハハハ！&lt;/p&gt;&lt;p&gt;よく分からないけど、試しに以下のようにしてみた（gnome-icon-theme-symbolicとか言うやつは、この際、忘れる）。&lt;/p&gt;&lt;pre style="color:black;background-color:snow;"&gt;&lt;br /&gt;yum --releasever=16 --disableplugin=presto distro-sync --skip-broken --exclude=gnome-icon-theme-symbolic&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;うん、なんだか上手く行ってるっぽい。エラーも無く yum が終了。再起動してログインしたら、Fedora 16 のデスクトップ画像が見えた。端末から&lt;span style="color:white;"&gt; cat /etc/fedora-release &lt;/span&gt;とやってみたら、&lt;span style="color:white;"&gt; Fedora release 16 (Verne)&lt;/span&gt;と出た。&lt;/p&gt;&lt;p&gt;うん、これは出来ておるね。出来たっぽいね。&lt;/p&gt;&lt;p&gt;まあ、いちいち書いてはいないけど本当はもっと試行錯誤して、正直つらかった。よく覚えてないけど、気がつくと頬が濡れてたから、俺ちょっと泣いてたのかもしれん。まあでも、どうやら一応、Fedora 16 にアップグレードできた。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;で、まずは 「ソフトウェアの追加／削除」で Eclipse を Indigo に変える。実はこれが、そもそもの目的だった。うまくインストールから起動まで確認できて一段落。ほっとする。&lt;/p&gt;&lt;p&gt;更に、他のいろんなもの全部をアップグレードしたくて、「ソフトウェアの更新」を起動すると、700個近く検出された。かまわず[Install Updates]押下。&lt;br/&gt;&lt;br/&gt;・・・って、ま〜たかよ。また、gnome-icon-theme-symbolic と gnome-power-manager が干渉してるとか言ってきた。&lt;/p&gt;&lt;p&gt;今度は、&lt;span style="color:snow;"&gt; yum remove gnome-power-manager&lt;/span&gt; で、電力管理の何かを削除してみる。多分使ってないし、要るなら後でなんとかすればいいし。&lt;br/&gt;で、再度、[Install Updates]。&lt;/p&gt;&lt;p&gt;すると今度は、「libnih が GLIBC とナントカカントカ」だの言ってきやがって、ギギギ、てめえコノヤ……まあ、短気は損気とも言うからな。&lt;/p&gt;&lt;p&gt;&lt;span style="color:snow;"&gt; rpm -q --whatrequires libnih&lt;/span&gt; で見てみると、別にどこからも依存されてる形跡がないので、yum remove してしまう。&lt;/p&gt;&lt;p&gt;再び、[Install Updates]を再試行すると、今度はどんどん進む。これは今渡こそ、上手く行ってるっぽい。&lt;/p&gt;&lt;p&gt;小一時間で 700 近い更新が適用。清々しい気分。再起動しろというので、にこやかにOKボタン押下。&lt;/p&gt;&lt;p&gt;で、しばらく待ってると、いつものようにユーザ選択のポップアップが表示された。ユーザ名を選んでからパスワードを入力。&lt;/p&gt;&lt;p&gt;…そしたら、困った顔のマシンの画像で「ああ、何かがおかしいです、ログインし直してください」とか、メッセージを出してくる。&lt;br/&gt;はあ？何だ、その言い草？しかし、何度やってもログインできず、同じ戯言を繰り返してくる・・・&lt;/p&gt;何度やっても、何度やっても、何度やっても、何度やっても、何度やっても、何度やっても、何度やっても、&lt;br/&gt;&lt;p&gt;おぎゃーーーーーーー！！！&lt;/p&gt;&lt;br/&gt;&lt;p&gt;…ひとしきり地団太を踏んで暴れると、嗚咽も収まり、だんだん冷静さが戻ってきた。いつまでもクヨクヨしない。泣いたってログインできないよって、ばあちゃん言ってたし、俺は大人だしな。&lt;/p&gt;&lt;p&gt;で、なんとなく SELinux のせいだろうと思ったので、無効になるようにしたいのだけど、ログインできない状態でどうすれば良いか分からない。幸い予備のマシンがあったからググったら、シングルユーザモードというのがあって、Windows の safe mode みたいな事ができるらしい。&lt;/p&gt;&lt;p&gt;なんか、起動中に良い感じのタイミングで「E」キーを押すと、カーネルの選択画面になるので、そこで single を追加指定すれば root でログインできる（詳しいやり方は、シングルユーザモードで検索するとなんぼでも出てくる）。&lt;/p&gt;&lt;p&gt;で、CUI ログインしたら、&lt;span style="color:snow;"&gt; vim /etc/sysconfig/selinux&lt;/span&gt;で SELinux の設定ファイルを開いて、「SELINUX=enforcing」から「SELINUX=disabled」に書き換える。&lt;/p&gt;&lt;p&gt;で、もっかい再起動。&lt;br/&gt;今度こそ、ちゃんとログインできた。&lt;br/&gt;ほっとしたが、えらく手間がかかったなあ・・・。&lt;/p&gt;&lt;p&gt;まあ、こういった アップグレード関連のアレコレとかって、Linux そのものが好きでベータ版から使ってる人には、大半が常識的で造作ない事なんだろうけど、自分はすごい苦手。こういった作業はたまにしかしないし、してもさっぱり記憶が定着しないし、本当、弱点だわ。&lt;/p&gt;# Fedora 自体は気に入っているが&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-4243198173875197683?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/4243198173875197683/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/fedora-16.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4243198173875197683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4243198173875197683'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/fedora-16.html' title='Fedora のアップグレードで平常心の訓練'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7614412939217279229</id><published>2011-11-05T18:16:00.001+09:00</published><updated>2012-01-04T21:54:50.204+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>FEST+JavaScript で半自動 Swing テスト</title><content type='html'>&lt;p&gt;あ〜、暇だから、Swing フォームを JavaScript で動かすやり方でも考えてみっかな。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;例えば、打鍵＋目視に基づいた手動画面テストが既に実施されていたり、チェックリストとかテスト仕様書が出来ている場合に、作業負荷を減らすために、後から部分的に自動化を導入して、半自動テストにしたい場合がある。&lt;/p&gt;&lt;p&gt;ところで&lt;a href="http://code.google.com/p/fest/"&gt;fest&lt;/a&gt; という、Swing アプリを Javaコードから機能テストするための API セットがあり、Javaコード からUIイベントを発生させて画面上のコンポーネントを操作するAPIが一揃い入っている（AWT の Robot をベースにしたものらしい）。&lt;/p&gt;&lt;p&gt;また、JavaScript コードを Javaプログラムから動かす仕組みは、Java 1.6 から備わっていて、特に何か特別なライブラリを必要とせずに、簡単に使えるようになっている。&lt;/p&gt;&lt;p&gt;これらを利用すれば、テスト対象フォームの外で JavaScript を実行して、フォーム上の要素を制御することができるはず。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 実験台&lt;/p&gt;&lt;p&gt;実験台として、以下のフォームを考えてみる。&lt;/p&gt;&lt;p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-giEPytWirf4/TrTK_fVFYqI/AAAAAAAAAQo/Ah_2VlcGDAk/s1600/Test_Target.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="150" width="250" src="http://1.bp.blogspot.com/-giEPytWirf4/TrTK_fVFYqI/AAAAAAAAAQo/Ah_2VlcGDAk/s320/Test_Target.png" /&gt;&lt;/a&gt;&lt;/div&gt;こんな仕様&lt;ul&gt;&lt;li&gt;テキストボックスの名前は "field1"&lt;/li&gt;&lt;li&gt;チェックボックスの名前は "check1"&lt;/li&gt;&lt;li&gt;ボタンの名前は "button1" で、押下すると "check1"がチェックされている場合は field1 を大文字化した文字列、チェックされていない場合は field1 そのままの文字列を、標準出力に書き出す。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;実験台だから単純なフォームにしたけど、実際の現場での開発対象フォームは入力項目が何十個もあって、実行ボタンを押すまでに必要な打鍵動作が多く、１回なら問題ないけど、同じようなテストケースや回帰テストをしたりすると心身ともに疲れたりする。やはり、そういうのは、何とかして省力化したい。&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 方針&lt;/p&gt;まず、テスト対象フォームを開くと同時に、以下のような別ウィンドウを開く。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-6rHisDDpKSw/TrTQc58dMzI/AAAAAAAAAQ0/jCn9XnmRggM/s1600/JavaScript_input_window.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="150" width="250" src="http://3.bp.blogspot.com/-6rHisDDpKSw/TrTQc58dMzI/AAAAAAAAAQ0/jCn9XnmRggM/s320/JavaScript_input_window.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;で、ここで JavaScript を入力して Excecute ボタンを押下すると、手動の打鍵と同等の JavaScript が実行されるようにしたい。&lt;div style="font-size:smaller;"&gt;&lt;/div&gt;&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 実装&lt;/p&gt;&lt;p&gt;JavaScript 入力用のウィンドウ ScriptInputWindow は、最初にテスト対象ウィンドウの &lt;a href="http://easytesting.org/swing/apidocs/org/fest/swing/fixture/FrameFixture.html"&gt;FrameFixture&lt;/a&gt; を受け取る。&lt;pre class="prettyprint"&gt;public static void main(String[] args) {&lt;br /&gt;   JFrame frame = showWindow(new TestTargetWindow("Test Target"), 0);&lt;br /&gt;   FrameFixture window = new FrameFixture(frame);&lt;br /&gt;   showWindow(new ScriptInputWindow(window), 3000);&lt;br /&gt;}&lt;br /&gt;public static JFrame showWindow(JFrame frame, int xpos) {&lt;br /&gt;   frame.setSize(250, 150);&lt;br /&gt;   frame.setLocation(xpos, 0);&lt;br /&gt;   frame.setVisible(true);&lt;br /&gt; &lt;br /&gt;   return frame;&lt;br /&gt;}&lt;/pre&gt;&lt;div style="font-size:90%;"&gt;見ての通りテスト対象ウィンドウは TestTargetWindow だけど、ScriptInputWindow と TestTargetWindow は同じテストハーネスのプロセスから実行する事になる。もしかすると、開発対象システムに固有な何か特別な親ウィンドウとか、ランチャーとかを介さないと、テスト対象ウィンドウ単体ではフォームを開けないと心配する人もいるかもしれないが、大抵の場合は instrumentation ベースのモックツールを使えば何とかなるし、そんなに難しくもない。&lt;/div&gt;&lt;/p&gt;&lt;p&gt;ScriptInputWindow はまず最初に、テスト対象フォーム上のコントロールを、JavaScript 用の &lt;a href="http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html"&gt;ScriptEngine&lt;/a&gt; に登録する。ScriptEngine も ScriptInputWindow  が保持しておく。&lt;pre class="prettyprint"&gt;public ScriptInputWindow(FrameFixture window) {&lt;br /&gt;   super("JavaScript input window");&lt;br /&gt;&lt;br /&gt;   initializeControlls();  &lt;br /&gt;&lt;br /&gt;   this.jsEngine = new ScriptEngineManager().getEngineByName("JavaScript");&lt;br /&gt;   registerComponents(window, window.component(), 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("restriction")&lt;br /&gt;private void registerComponents(&lt;br /&gt;      FrameFixture window, Container container, int indent) {&lt;br /&gt;&lt;br /&gt;   for (Component component: container.getComponents()) {&lt;br /&gt;      String name = component.getName();&lt;br /&gt;      if (null != name) {&lt;br /&gt;         ComponentFixture&lt;? extends Component&gt; comp = selectComponent(window, name);&lt;br /&gt;         if (null != comp) this.jsEngine.put(name, comp);&lt;br /&gt;      }&lt;br /&gt;      if (component instanceof JComponent)&lt;br /&gt;            listComponents(window, (Container)component, indent + 1);&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;div style="font-size:small;"&gt;selectComponent() は ContainerFixture から name に一致する ComponentFixture を選んでくるメソッドだけど、面倒なので省略。&lt;/div&gt;&lt;/p&gt;&lt;p&gt;ボタンを押すと書き込んだJavaScriptコードを実行する部分は以下のようなもの。&lt;pre class="prettyprint"&gt;executeButton.addActionListener(new ActionListener() {&lt;br /&gt;   public void actionPerformed(ActionEvent arg0) {&lt;br /&gt;      ExecutorService e = Executors.newSingleThreadExecutor();&lt;br /&gt;      e.execute(new Runnable() {&lt;br /&gt;         public void run() {&lt;br /&gt;            try {&lt;br /&gt;               String text = ScriptInputWindow.this.textArea.getText();&lt;br /&gt;               ScriptInputWindow.this.jsEngine.eval(text);&lt;br /&gt;            } catch (Exception e) {&lt;br /&gt;               e.printStackTrace();&lt;br /&gt;             }&lt;br /&gt;          }&lt;br /&gt;      });&lt;br /&gt;   }&lt;br /&gt;});&lt;/pre&gt;&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 試行&lt;/p&gt;以下のコードを書き込んで実行すると、テキストボックスの内容が "123abcABC" に変わり、チェックボックスがチェックされ、ボタンが押され、標準出力に”123ABCABC”が出力される。&lt;pre style="background-color:snow;color:indigo;"&gt;field1.setText("123abcABC");&lt;br /&gt;check1.check();&lt;br /&gt;button1.click();&lt;/pre&gt;&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 応用&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;フォーム上のコントロールの操作以前に、まずコントロールの名前を知ってなきゃならないんだけど、必要な時に階層状に表示してテスターに見せる機能もあった方が良いかもしれない。これは registerComponents でやってる事をそのままどっかに書き出すだけだから簡単。&lt;/li&gt;&lt;li&gt;自動打鍵の結果として得られた画面上の更新項目を、比較しやすい形式でどこか（TextArea とかクリップボードでもファイルでも）に書き出す仕組みもあると便利かもしれない。グリッドとかツリーとかあると、ちょっと手間がかかるかも。&lt;/li&gt;&lt;li&gt;自動打鍵後に、用意しておいた期待値と自動的に比較する仕組みがあると、かなり全自動に近づいてくる。&lt;/li&gt;&lt;li&gt;手動打鍵の記録なんかまでやるとなると、それは難しい。商用製品でも買った方がマシかもしれない（下記の参考記事をみるとFESTでも対応作業中みたいな書きっぷりだけど、どうなったのか不明）。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p style="font-size:larger;font-weight:bold;"&gt;■ 参考サイト&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.ibm.com/developerworks/java/library/j-swingtest/?ca=dgr-lnxw03Viriodth-LX&amp;S_TACT=105AGX59&amp;S_CMP=grlnxw03"&gt;Debugging and testing Swing code&lt;/a&gt;→日本語訳→&lt;a href="http://www.ibm.com/developerworks/jp/java/library/j-swingtest/"&gt;Swing コードをデバッグし、テストする&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/"&gt;Scripting for the Java Platform&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7614412939217279229?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7614412939217279229/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/festjavascript-swing.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7614412939217279229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7614412939217279229'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/festjavascript-swing.html' title='FEST+JavaScript で半自動 Swing テスト'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-giEPytWirf4/TrTK_fVFYqI/AAAAAAAAAQo/Ah_2VlcGDAk/s72-c/Test_Target.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8458785680096690501</id><published>2011-11-03T16:17:00.002+09:00</published><updated>2011-11-03T16:22:57.366+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><title type='text'>仲間外れはどれか？</title><content type='html'>&lt;p&gt;下の図は、仲間外れを見つける問題例だけど、小学校受験のためのものだから幼稚園児向けということになる。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ntMxJuW83dc/TrInGFifl0I/AAAAAAAAAQc/WZLW6oHsxGs/s1600/namakahazure.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="59" width="320" src="http://4.bp.blogspot.com/-ntMxJuW83dc/TrInGFifl0I/AAAAAAAAAQc/WZLW6oHsxGs/s320/namakahazure.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;仲間外れといっても、一応、少なくとも野菜ではあるのだから、問題の趣旨を一旦置いておけば、あながち間違った括りとは言えなくもない。&lt;/p&gt;&lt;p&gt;でも、じゃあ、「カボチャ」の代わりに、「八百屋さん」だったり「プログラマ（好きな食べ物：肉、嫌いな食べ物：野菜）」とかだったとしても、同じカテゴリって言い張る奴っているのだろうか。まあ、こんなアホな質問はした事はないけど、身の回りには多分いないと思う。つうか、いたら嫌だ。&lt;p&gt;&lt;p&gt;ところが、それに相当するようなソースコードなら、プロの開発現場でもしょっちゅう見かける。今日はそんな事を書いてみる。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;こんなコードがあったとする。&lt;/p&gt;&lt;p&gt;このコードには、ダメなところがいくつかあるけど、特にまずい問題点を、ちゃんと技術者っぽい言葉で説明できるだろうか。&lt;/p&gt;&lt;pre class="prettyprint"&gt;/** 色を指定できるカーペット。 */&lt;br /&gt;public class Carpet {&lt;br /&gt;   private final int color;&lt;br /&gt;   public Carpet(int color) {&lt;br /&gt;      this.color = color;&lt;br /&gt;   } &lt;br /&gt;   //…&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/** システムで使える色の集合  */&lt;br /&gt;public class Colors {&lt;br /&gt;   private static final Map&lt;String, Integer&gt; COLORS = new HashMap&lt;String, Integer&gt;();&lt;br /&gt;   static {&lt;br /&gt;      COLORS.put("赤", 0xFF0000);&lt;br /&gt;      COLORS.put("緑", 0x00FF00);&lt;br /&gt;      COLORS.put("青", 0x0000FF);&lt;br /&gt;   };&lt;br /&gt;   private Colors() {} &lt;br /&gt;   public static int colorNameToRgbValue(String colorName) {&lt;br /&gt;      return COLORS.get(colorName); &lt;br /&gt;   }&lt;br /&gt;   public static List&lt;Carpet&gt; createCarpets(String[] colorNames) {&lt;br /&gt;      List&lt;Carpet&gt; result = new ArrayList&lt;Carpet&gt;();&lt;br /&gt;      for (String colorName: colorNames) {&lt;br /&gt;         result.add(new Carpet(COLORS.get(colorName)));&lt;br /&gt;      }&lt;br /&gt;      return result;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;p style="font-size:smaller;"&gt;Colors は本当は enum を使うべきだけど、サンプルの都合上普通のクラスにした。また、そもそもユーティリティクラスがまずいってのは、取り敢えずこの際、放っておく事にする。&lt;/p&gt;&lt;p&gt;Colors という色のセットを表すクラスに、色に関係ない事はないけど明らかに異質でレベルの違う Carpet という概念を扱うメソッド、createCarpets() が定義されている。&lt;p&gt;&lt;p&gt;こういうとき、ちょっと堅苦しい言い方だけど、「&lt;span style="color:white;"&gt;凝集性&lt;/span&gt;が低い」という（もちろん低いほどダメ）。&lt;/p&gt;&lt;p&gt;もっと言うと、&lt;span style="color:white;"&gt;暗合的凝集度&lt;/span&gt;と&lt;span style="color:white;"&gt;論理的凝集度&lt;/span&gt;の間くらいになると思われ、レベルとしてはサイテーに近い。（技術者っぽくない言葉でいうと、暗合的凝集度は「なんで同じクラスに入れてんのかイミフ」なやつで、論理的凝集度は「言い訳できない事ないけど必然性に乏しい」やつ。）&lt;/p&gt;&lt;p&gt;この凝集性と表裏一体の概念として、&lt;span style="color:white;"&gt;結合度&lt;/span&gt;というのもある。&lt;/p&gt;&lt;p&gt;上のコードは結合度が高い（こっちは高いほどダメ）のだけど、実質的にグローバル関数といえるメソッド群がクラス変数という実質グローバルな情報を介して結びついている点で「&lt;span style="color:white;"&gt;共通結合&lt;/span&gt;」であり、６段階あるうちの悪い方から2番目で、やはりかなり酷いコードと言える。&lt;/p&gt;&lt;p&gt;さらに、凝集性や結合度はオブジェクト指向隆盛以前の、構造化手法全盛期からある設計評価基準だけど、オブジェクト指向に関連の強い言葉「&lt;span style="color:white;"&gt;責務&lt;/span&gt;」を用いて表現すれば、「createCarpets によって、Colors が一つ以上の異なる責務を負っている事が問題」と言う事もできる（責務：言うまでもなく CRC の R(Responsibility)）。&lt;/p&gt;&lt;p&gt;つうわけで、上のコードは単純過ぎる例ではあるものの、技術的には「低凝集・高結合度で、複数の責務を負った下手糞なコード」だと言える。まあ、そういうコードや設計を放置しておくと、その先どうなるかについて、技術者じゃない人になら説明する必要があるけど、技術者同士なら説明不要だと思う（思いたい）。&lt;/p&gt;&lt;p&gt;ただし、実はクソヘタプログラマだけがこんなコードを書いているのではなくて、そこそこの技術者／チームでも、開発期間の中で生じるいろんな行きがかり上、たまたまこんな感じになってしまって、そのまま直す機会を逸してしまってる場合もある。&lt;/p&gt;&lt;p&gt;まあ、でも。そんな時のためのリファクタリング技術なわけで、ちゃんとテストコードを実行するという前提（当たり前だけど、無ければ必ず書き足す）さえ守れば、なんぼでも体質改善すれば良い。&lt;/p&gt;&lt;p&gt;だけど、そもそもダメだって事が認識できないとなると、いろんな意味でかなりやばい。説明するこっちも、クラスの責務から説明すればいいのか、結合度・凝集度から説明すればいいのか、それとも小学校受験の仲間外れ問題まで遡って説明しなければならないのかと考えてしまって、なんかもうキッツイわ…&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8458785680096690501?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8458785680096690501/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8458785680096690501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8458785680096690501'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/blog-post.html' title='仲間外れはどれか？'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-ntMxJuW83dc/TrInGFifl0I/AAAAAAAAAQc/WZLW6oHsxGs/s72-c/namakahazure.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2516245363741260227</id><published>2011-11-01T01:19:00.002+09:00</published><updated>2012-01-04T21:55:01.529+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>Eclipse と JMockit でテストファースト</title><content type='html'>&lt;p&gt;&lt;a href="http://yasutech.blogspot.com/2011/10/blog-post.html"&gt;以前のブログ&lt;/a&gt;で、他の２つのクラスとのコラボレーションを含む簡単なクラスのテストをJMockitを使って書いたけど、その時は、敢えてレガシーコードに後付けテストを追加するような感じで書いてみた。&lt;/p&gt;&lt;p&gt;やろうとしている事は以下のようなものだった。&lt;ol&gt;&lt;li&gt;作ろうとしているのは Foo というクラスで、文字列を返すメソッド hoge() を持っている&lt;/li&gt;&lt;li&gt;Foo#hoge() が返す文字列は、Baz#hoge() から取得したものである&lt;/li&gt;&lt;li&gt;ただし、Baz のインスタンスは、Bar のインスタンスを経由しないと使えない&lt;/li&gt;&lt;/ol&gt;これを以下に、テストファーストで実装してみる。ただし今日は、Eclipse を極力活用するという趣向でやってみる。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;まず①の クラス Foo とメソッド hoge()だけど、以下の様に、まず最初にテストクラスを書く。&lt;pre class="prettyprint"&gt;public class FooTest {&lt;br /&gt;   @Test public void hoge() {&lt;br /&gt;      Assert.assertEquals("dummy", new Foo().hoge());&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;まだクラス Foo が無いから当然コンパイルエラーの赤波が表示されるので、以下のように仮実装する。&lt;pre class="prettyprint"&gt; public class Foo {&lt;br /&gt;   public String hoge() {&lt;br /&gt;      return null;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;span style="color:white;font-weight:bold;"&gt;ただし、これをそのままタイプしてはいけない。&lt;/span&gt;Eclipse を使うという前提なのだから Ctrl+1を2回（クラスに一回、メソッドに一回）使うだけでタイプせずに済むので、これを活用する。&lt;br/&gt;とりあえず、ここまでで JUnit を実行して、&lt;span style="color:red;"&gt;テストが失敗&lt;/span&gt;するのを見てから、hoge() の戻り値を"dummy"に変えて、&lt;span style="color:#00FF00;"&gt;テスト成功&lt;/span&gt;に変わるのを確認しておく&lt;/p&gt;&lt;p&gt;で次に、② の Baz#hoge() への委譲。これもテスト・コードから書く。&lt;pre class="prettyprint"&gt;public class FooTest {&lt;br /&gt;   @Test public void hoge() {&lt;br /&gt;      new NonStrictExpectations() {&lt;br /&gt;         Baz baz;&lt;br /&gt;         {&lt;br /&gt;            baz.hoge(); result = "dummy"; times = 1;&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;      Assert.assertEquals("dummy", new Foo().hoge());&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;ここでももちろん、Baz も Baz#hoge() も未だ無いわけだから赤波が表示されるけど、さっきと同様に Ctrl+1 を 2回使って Baz の空実装を Eclipseに生成させる。ただし今度は Baz#hoge() の中身を以下の様に書き換える。&lt;pre  class="prettyprint"&gt;public class Baz {&lt;br /&gt;   public String hoge() {&lt;br /&gt;      //FIXME [your user name] Nov 1, 2011&lt;br /&gt;      throw new AssertionError();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;自分の環境では、この FIXMEコメントから AssertionError送出の2行は、Java エディターのテンプレートに登録してあるので、fixme とタイプして Ctrl+1を押せば、その日の日付とログインしているユーザ名で2行挿入される。&lt;br/&gt;&lt;br/&gt;で、赤波が消えたら、また JUnit を実行して Baz#hoge() が呼ばれていないという&lt;span style="color:#FF0000;"&gt;アサーション例外が上がる&lt;/span&gt;のを確認し、Foo#hoge() を以下の様に書き換える。&lt;pre class="prettyprint"&gt;public String hoge() {&lt;br /&gt;   return new Baz().hoge();&lt;br /&gt;}&lt;/pre&gt;書いたらまた JUnitを実行して、今度は&lt;span style="color:#00FF00;"&gt;緑になる&lt;/span&gt;のを確認。&lt;/p&gt;&lt;p&gt;最後に、③ の Bar インスタンスを経由して Baz インスタンスを得るところ。これもやっぱりテストコードから。&lt;pre class="prettyprint"&gt;public class FooTest {&lt;br /&gt;   @Test public void hoge() {&lt;br /&gt;      new NonStrictExpectations() {&lt;br /&gt;         Baz baz;&lt;br /&gt;         Bar bar;&lt;br /&gt;         {&lt;br /&gt;            bar.baz(); result = baz; times = 1;&lt;br /&gt;            baz.hoge(); result = "dummy"; times = 1;&lt;br /&gt;         }&lt;br /&gt;      };&lt;br /&gt;      Assert.assertEquals("dummy", new Foo().hoge());&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;またここでも Baz#hoge() と同様に、Ctrl+1 をクラスとメソッドにそれぞれ適用して空実装を生成し、FIXME付きのアサーション例外送出コードを書いておく。&lt;br/&gt;&lt;br/&gt;赤波が消えたらJUnit実行。Bar#baz() が呼ばれてないって&lt;span style="color:#FF0000;"&gt;アサーション例外が上がったら&lt;/span&gt;、おもむろに Fooを以下のように書き換える。&lt;pre class="prettyprint"&gt;public class Foo {&lt;br /&gt;   private final Bar bar = new Bar();&lt;br /&gt;   public String hoge() {&lt;br /&gt;      return this.bar .baz().hoge();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;但し、これも Ctrl+1 （→ Create field 〜）を活用し、無駄なタイピングをせずに編集する。できたら、Junit を実行し&lt;span style="color:#00FF00;"&gt;緑&lt;/span&gt;になることを確認。&lt;/p&gt;&lt;p&gt;というわけで、完了。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;ちなみに、&lt;a href="http://yasutech.blogspot.com/2011/10/coq.html"&gt;この間から&lt;/a&gt;かじり始めた &lt;a href="http://www.iij-ii.co.jp/lab/techdoc/coqt/coqt2.html"&gt;Coq のチュートリアルの第2回&lt;/a&gt;で、結論から１個ずつ論理を遡って証明を完成させていく手順が紹介されていたけど、テストファーストと似ているところがあると思った。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2516245363741260227?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2516245363741260227/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/11/eclipse-jmockit.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2516245363741260227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2516245363741260227'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/11/eclipse-jmockit.html' title='Eclipse と JMockit でテストファースト'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3171036374126237216</id><published>2011-10-29T20:59:00.000+09:00</published><updated>2011-10-29T23:06:57.014+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='非RDB'/><title type='text'>暇だから MongoDB でも入れてみるか</title><content type='html'>&lt;p&gt;せっかくの休日、Eclipse の Xtext を試してみたかったのに、Indigo はコアダンプ吐いて即死するし、Helios はプロジェクトの作成に失敗するわで、15分くらいで心が折れた。&lt;/p&gt;&lt;p&gt;で、代わりの暇つぶしとして、最近 NoSQL について下調べしていて見かけた MongoDB とか言う奴でもいじってみようかなと思いつく。&lt;a href="http://www.mongodb.org/display/DOCS/Quickstart+Unix"&gt;この辺り&lt;/a&gt;を参考（飽くまでも参考）にして、Fedora15 の 32bit 環境でやってみた。&lt;p style="font-size:smaller;border:1px dashed grey;"&gt;実は、Fedora で管理しているMongoDB が「ソフトウェアの追加と削除」で最初からリストアップされてるんだけど、これをインストールしても、なんかちゃんと起動しなかった。&lt;/p&gt;&lt;/p&gt;====&lt;p&gt;まずはインストールだけど、配布元の 10gen を Fedora （というか yum）に認識させるために、ファイル /etc/yum.repos.d/10gen.repo を作って以下の記述を追加する。&lt;pre style="background-color:snow;color:navy;line-height:140%;"&gt;[10gen]&lt;br /&gt;name=10gen Repository&lt;br /&gt;baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/i686&lt;br /&gt;gpgcheck=0&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;そうすると、「ソフトウェアの追加と削除」にリストアップされるから、以下を選択して[適用]&lt;ul&gt;&lt;li&gt;mongo-10gen-server-2.0.1-mongodb_1&lt;/li&gt;&lt;li&gt;mongo-10gen-2.0.1-mongodb_1&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;インストールされたら、起動してみたい所だけど、その前に、なんかデータを保存するフォルダを作っとく必要があるらしい。&lt;pre style="background-color:snow;color:navy;line-height:140%;"&gt;$ sudo mkdir -p /data/db/&lt;br /&gt;$ sudo chown `id -u` /data/db&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;準備ができたので、Fedora の[サービス]ツールで mongod を開始する。&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-26DNqdbET0Q/TqvmO7ezsAI/AAAAAAAAAQE/ZHSTX-ioigw/s1600/Screenshot-%25E3%2582%25B5%25E3%2583%25BC%25E3%2583%2593%25E3%2582%25B9%25E3%2581%25AE%25E8%25A8%25AD%25E5%25AE%259A.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="220" width="320" src="http://4.bp.blogspot.com/-26DNqdbET0Q/TqvmO7ezsAI/AAAAAAAAAQE/ZHSTX-ioigw/s320/Screenshot-%25E3%2582%25B5%25E3%2583%25BC%25E3%2583%2593%25E3%2582%25B9%25E3%2581%25AE%25E8%25A8%25AD%25E5%25AE%259A.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;端末で、mongo を起動して動作確認。&lt;pre style="background-color:snow;color:navy;line-height:140%;"&gt;$ mongo&lt;br /&gt;&gt; one = {name: "one", value: 1}&lt;br /&gt;&gt; two = {name: "two", value: 2}&lt;br /&gt;&gt; three = {name: "three", value: 3}&lt;br /&gt;&gt; db.things.save(one)&lt;br /&gt;&gt; db.things.save(two)&lt;br /&gt;&gt; db.things.save(three)&lt;br /&gt;&gt; db.things.find()&lt;br /&gt;{ "_id" : ObjectId("4eabd63586daea21618266ca"), "name" : "one", "value" : 1 }&lt;br /&gt;{ "_id" : ObjectId("4eabd63786daea21618266cb"), "name" : "two", "value" : 2 }&lt;br /&gt;{ "_id" : ObjectId("4eabd63a86daea21618266cc"), "name" : "three", "value" : 3 }&lt;br /&gt;&gt; db.things.find({name:"one"}, {_id:0})&lt;br /&gt;{ "name" : "one", "value" : 1 }&lt;br /&gt;&gt; db.things.find({value:2}, {name:1})&lt;br /&gt;{ "_id" : ObjectId("4eabd63786daea21618266cb"), "name" : "two" }&lt;br /&gt;&gt; db.things.find({value:3}, {name:1,_id:0})&lt;br /&gt;{ "name" : "three" }&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;ちゃんと動いてるらしい。&lt;/p&gt;&lt;p&gt;次は、java コードから動かしてみたい（&lt;a href="http://www.mongodb.org/display/DOCS/Java+Tutorial"&gt;チュートリアル&lt;/a&gt;）。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3171036374126237216?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3171036374126237216/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/eclipse-xtext-indigo-helios-15-nosql.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3171036374126237216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3171036374126237216'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/eclipse-xtext-indigo-helios-15-nosql.html' title='暇だから MongoDB でも入れてみるか'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-26DNqdbET0Q/TqvmO7ezsAI/AAAAAAAAAQE/ZHSTX-ioigw/s72-c/Screenshot-%25E3%2582%25B5%25E3%2583%25BC%25E3%2583%2593%25E3%2582%25B9%25E3%2581%25AE%25E8%25A8%25AD%25E5%25AE%259A.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-405134861289687732</id><published>2011-10-27T00:19:00.000+09:00</published><updated>2011-11-01T23:35:55.692+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>JavaScript + XSLT の小技</title><content type='html'>&lt;p&gt;ここ数年、一部界隈でアンチXMLみたいな動きがあったりするが、現実には XML はいろんな場面で使われている。中には数万行のものがあったりするけど、さすがにそのサイズになると、直接、内容を読もうとすると、結構不便だったりする。&lt;/p&gt;&lt;p&gt;というわけで、最近重宝している ブラウザと Javascript と XSLT を使った小技を書いてみる。&lt;/p&gt;&lt;p&gt;こんな感じの XML があるとする。&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;numerals&amp;gt;&lt;br /&gt;  &amp;lt;numeral&amp;gt;&amp;lt;arabic&amp;gt;1&amp;lt;/arabic&amp;gt;&amp;lt;jp&amp;gt;壱&amp;lt;/jp&amp;gt;&amp;lt;en&amp;gt;one&amp;lt;/en&amp;gt;&amp;lt;/numeral&amp;gt;&lt;br /&gt;  &amp;lt;numeral&amp;gt;&amp;lt;arabic&amp;gt;2&amp;lt;/arabic&amp;gt;&amp;lt;jp&amp;gt;弐&amp;lt;/jp&amp;gt;&amp;lt;en&amp;gt;two&amp;lt;/en&amp;gt;&amp;lt;/numeral&amp;gt;&lt;br /&gt;  &amp;lt;numeral&amp;gt;&amp;lt;arabic&amp;gt;3&amp;lt;/arabic&amp;gt;&amp;lt;jp&amp;gt;参&amp;lt;/jp&amp;gt;&amp;lt;en&amp;gt;thee&amp;lt;/en&amp;gt;&amp;lt;/numeral&amp;gt;&lt;br /&gt;&amp;lt;/numerals&amp;gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;これを XSLT で HTML に変換して、ブラウザ上で左下のようなリストを表示し、それぞれのリスト要素に設定されているハイパーリンクをクリックすると、右下の様に詳細が表示されるといった事をしたい。&lt;table width="100%"&gt;&lt;tr&gt;&lt;td&gt;&lt;ul&gt;&lt;li&gt;壱&lt;/li&gt;&lt;li&gt;弐&lt;/li&gt;&lt;li&gt;参&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;td style="font-size:200%;"&gt;⇨&lt;/td&gt;&lt;td&gt;&lt;table border="1" cellspacing="0" cellpadding="0" style="align:center;border-collapse:collapse;"&gt;&lt;tr&gt;&lt;td&gt;数字&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;日本語&lt;/td&gt;&lt;td&gt;弐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;英語&lt;/td&gt;&lt;td&gt;two&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;以下、その方法。&lt;/p&gt;====&lt;p&gt;リストを表示する XSLT は以下のようなものになる。ポイントは&amp;lt;a&amp;gt;要素を生成しているところで、javascript 関数 showDetail()に arabic 要素を渡すようなリンクが作られる。&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;&lt;br /&gt;  &amp;lt;xsl:template match="/"&amp;gt;&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;      &amp;lt;xsl:for-each select="numerals/numeral"&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&lt;br /&gt;          &amp;lt;xsl:element name="a"&amp;gt;&lt;br /&gt;            &amp;lt;xsl:attribute name="href"&amp;gt;&lt;br /&gt;              javascript:showDetail(&amp;lt;xsl:value-of select="arabic"/&amp;gt;)&lt;br /&gt;            &amp;lt;/xsl:attribute&amp;gt;&lt;br /&gt;            &amp;lt;xsl:value-of select="jp"/&amp;gt;&lt;br /&gt;         &amp;lt;/xsl:element&amp;gt;&lt;br /&gt;        &amp;lt;/li&amp;gt;&lt;br /&gt;      &amp;lt;/xsl:for-each&amp;gt;&lt;br /&gt;    &amp;lt;/ul&amp;gt;&lt;br /&gt;  &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;で、次に詳細を表示するためのXSLTは以下で、ポイントはパラメータ arabic をグローバルで宣言しているところ。&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;&lt;br /&gt;  &amp;lt;xsl:param name="arabic"/&amp;gt;&lt;br /&gt;  &amp;lt;xsl:template match="/numerals/numeral"&amp;gt;&lt;br /&gt;    &amp;lt;xsl:for-each select=".[arabic=$arabic]"&amp;gt;&lt;br /&gt;      &amp;lt;table&amp;gt;&lt;br /&gt;       &amp;lt;tr&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;数字&amp;lt;/td&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;&amp;lt;xsl:value-of select="arabic"/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;       &amp;lt;/tr&amp;gt;&lt;br /&gt;       &amp;lt;tr&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;日本語&amp;lt;/td&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;&amp;lt;xsl:value-of select="jp"/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;       &amp;lt;/tr&amp;gt;&lt;br /&gt;       &amp;lt;tr&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;英語&amp;lt;/td&amp;gt;&lt;br /&gt;         &amp;lt;td&amp;gt;&amp;lt;xsl:value-of select="en"/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;       &amp;lt;/tr&amp;gt;&lt;br /&gt;      &amp;lt;/table&amp;gt;&lt;br /&gt;    &amp;lt;/xsl:for-each&amp;gt;&lt;br /&gt;  &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;いよいよ、Javascript と それを含むHTMLだけど、ソースは以下のようなものになる。&lt;pre class="prettyprint"&gt;&amp;lt;html&amp;gt;&lt;br /&gt; &amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;script type="text/javascript" src="sarissa.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;  &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;   function loadXmlFile(fileName) {&lt;br /&gt;     var result = Sarissa.getDomDocument();&lt;br /&gt;     result.async = false;&lt;br /&gt;     result.load(fileName);&lt;br /&gt;     return result;&lt;br /&gt;   }&lt;br /&gt;   function replaceResultArea(xmlDom) {&lt;br /&gt;     var serializer = new XMLSerializer(); &lt;br /&gt;     var output = serializer.serializeToString(xmlDom.documentElement);&lt;br /&gt; &lt;br /&gt;     document.getElementById("resultArea").innerHTML = output;&lt;br /&gt;   }&lt;br /&gt;   function showList() {&lt;br /&gt;     var xml = loadXmlFile("test.xml");&lt;br /&gt;     var xslt = loadXmlFile("ul.xsl");&lt;br /&gt;&lt;br /&gt;     var processor = new XSLTProcessor();&lt;br /&gt;     processor.importStylesheet(xslt);&lt;br /&gt;     var xmlDom = processor.transformToDocument(xml);&lt;br /&gt;&lt;br /&gt;     replaceResultArea(xmlDom);&lt;br /&gt;   }&lt;br /&gt;   function showDetail(arabic) {&lt;br /&gt;     var xml = loadXmlFile("test.xml");&lt;br /&gt;     var xslt = loadXmlFile("detail.xsl");&lt;br /&gt;&lt;br /&gt;     var processor = new XSLTProcessor();&lt;br /&gt;     processor.importStylesheet(xslt);&lt;br /&gt;     processor.setParameter("", "arabic", arabic);&lt;br /&gt;     var xmlDom = processor.transformToDocument(xml);&lt;br /&gt;&lt;br /&gt;     replaceResultArea(xmlDom);&lt;br /&gt;   }&lt;br /&gt;  &amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;/head&amp;gt;&lt;br /&gt; &amp;lt;body onload="showList()"/&amp;gt;&lt;br /&gt;   &amp;lt;div id="resultArea"/&amp;gt;   &lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;div style="font-size:smaller;"&gt;冒頭で参照している sarrisa.js はXMLを扱うための JavaScript ライブラリで http://dev.abiss.gr/sarissa/ からダウンロードできる。ただし Chrome がどうもサポートされてないっぽい。本当にそうなら残念（まあ、それほど困らないけど）。&lt;/div&gt;&lt;/p&gt;&lt;p&gt;以上、「(1)パラメータを与えつつ、(2)動的に XSLT を適用して、(3)ブラウザ上で表示を切り替える」方法。サンプルなんで、簡単なものだけどなんぼでも応用がきく。（例えば、静的ソース解析ツールが吐いたXML形式のレポートを分析したり、XMIで出力したUMLのドキュメントを解析してメトリクスを試算したりとか。）&lt;/p&gt;&lt;p&gt;ちなみに、個人的には XML それ自体に対する忌避感みたいなのは、全くといって良いほど無い。他の大抵の技術要素と同じく、上手く使えば役に立つし、下手に使えば役に立たないという単純な問題。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-405134861289687732?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/405134861289687732/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/javascript-xslt.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/405134861289687732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/405134861289687732'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/javascript-xslt.html' title='JavaScript + XSLT の小技'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7418138872111447596</id><published>2011-10-24T22:57:00.000+09:00</published><updated>2012-01-04T22:15:47.308+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>簡単な後付けテストで基本を再確認</title><content type='html'>&lt;p&gt;こんなクラスがあるとする。&lt;pre class="prettyprint"&gt;public class Foo {&lt;br /&gt;   private final Bar bar = new Bar();&lt;br /&gt;   public String hoge() {&lt;br /&gt;      return this.bar.baz().hoge();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt; 見ての通り、Foo は メソッド hoge()の中で、関連オブジェクト bar から取得した baz に、hoge() 処理を移譲している（日本語にすると、なんのこっちゃだが…）。&lt;/p&gt;&lt;p&gt;Bar と Baz は以下のような感じで後回しにしてある。&lt;pre class="prettyprint"&gt;public class Bar {&lt;br /&gt;   public Baz baz() {  throw new AssertionError();  }&lt;br /&gt;}&lt;br /&gt;public class Baz {&lt;br /&gt;   public String hoge() {  throw new AssertionError(); }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;ここで、Foo#hoge() をテストするにはどうするか。つまり以下の/* ??? */ のところに何を入れたらテストできるか。&lt;pre class="prettyprint"&gt;public class FooTest {&lt;br /&gt;   @Test public void hoge() {&lt;br /&gt;      /* ??? */&lt;br /&gt;      Assert.assertEquals("hello", new Foo().hoge());&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;とりあえず２個だけ例を書いてみると（ちょっとずつニュアンスの違うものを何通りも書けるが）、以下のようになる。&lt;pre class="prettyprint"&gt;@Test public void hoge1() {&lt;br /&gt;   new Expectations() {&lt;br /&gt;      @Mocked("baz") Bar bar;&lt;br /&gt;      @Mocked("hoge") Baz baz; {&lt;br /&gt;         bar.baz(); result = baz;&lt;br /&gt;         baz.hoge(); result = "hello";&lt;br /&gt;      }&lt;br /&gt;   };&lt;br /&gt;   Assert.assertEquals("hello", new Foo().hoge());&lt;br /&gt;}&lt;br /&gt;@Test public void hoge2() {&lt;br /&gt;   new NonStrictExpectations() {&lt;br /&gt;      Bar bar;&lt;br /&gt;      Baz baz; {&lt;br /&gt;         bar.baz(); result = baz; times=1;&lt;br /&gt;         baz.hoge(); result = "hello"; times=1;&lt;br /&gt;      }&lt;br /&gt;   };&lt;br /&gt;   Assert.assertEquals("hello", new Foo().hoge());&lt;br /&gt;}&lt;/pre&gt;JMockit を使い始めたばかりだと、結構、とまどうんじゃないかと思う。デバッガで追ってみると、例えば "result = baz" のところで、初期化していないはずの baz に何故かインスタンスが設定されているし、代入されたと思った result が null のままだったりして、普通の Java ソースの感覚で読んでいると訳が分からなかったりする。&lt;/p&gt;&lt;p&gt;とは言ってもまあ、すぐ慣れるし、そうなると逆に、JMockit 無しのテストを考える事が、時折難しく感じられてくる。&lt;/p&gt;&lt;p&gt;ただ、JMockit を使うと後付けテストもかなり簡単になるにはなるけど、やっぱりテストファーストが基本というのは押さえておいた方が良い。この例はもともと簡単だから、それほど大変なテストコードにはならないけど、もっと複雑なものになると、後付けとテストファーストではテストコーディングの生産性が大きく違ってくる。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;テストファースト版は、&lt;a href="http://yasutech.blogspot.com/2011/11/eclipse-jmockit.html"&gt;こっちに&lt;/a&gt;書いた。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7418138872111447596?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7418138872111447596/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7418138872111447596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7418138872111447596'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/blog-post.html' title='簡単な後付けテストで基本を再確認'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6935410756460935785</id><published>2011-10-23T01:53:00.002+09:00</published><updated>2011-10-23T02:00:59.426+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RDB'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Fedora 15 + JavaDB</title><content type='html'>&lt;p&gt;自宅マシンで javaDB を使って試したいことがあったんだけど、OpenJDK には JavaDB が入っていないらしい。「ソフトウェアの追加と削除」にもリストアップされない。という訳でRPMからインストールしてみた。&lt;/p&gt;&lt;p&gt;まず、&lt;a href="http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-database-419422.html#JavaDB-10.5.3.0-M-G-F"&gt;ここ&lt;/a&gt;からダウンロード&lt;/p&gt;&lt;p&gt;で、&lt;a href="http://www.oracle.com/technetwork/java/javadb/downloads/installation-instructions-156321.html"&gt;Oracle サイトのここ&lt;/a&gt;を見てインストール&lt;pre style="color:light-grey;background-color:black;"&gt;$ chmod +x javadb-10_5_3_0-linux-rpm.bin &lt;br /&gt;$ ./javadb-10_5_3_0-linux-rpm.bin &lt;br /&gt;# su&lt;br /&gt;# cd javadb-10.5.3.0/&lt;br /&gt;# rpm -ivh sun-javadb-*.rpm&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;ij コマンド で起動して、試してみる&lt;pre style="color:light-grey;background-color:black;"&gt;ij&amp;gt; connect 'jdbc:derby:testdb1;create=true'; &lt;br /&gt;ij&amp;gt; create table t1 (col1 int primary key, col2 varchar(10));&lt;br /&gt;ij&amp;gt; insert into t1 (col1, col2) values (100, '俺'));&lt;br /&gt;ij&amp;gt; select * from t1;&lt;br /&gt;COL1       |COL2      &lt;br /&gt;----------------------&lt;br /&gt;100        |俺   &lt;/pre&gt;&lt;/p&gt;&lt;p&gt;まあ問題なさそう。&lt;br/&gt;※実はエラーメッセージとか help とかが文字化けしてたけど、javaコードから使うのがメインだから放置。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6935410756460935785?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6935410756460935785/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/fedora-15-javadb.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6935410756460935785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6935410756460935785'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/fedora-15-javadb.html' title='Fedora 15 + JavaDB'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8027398812612258711</id><published>2011-10-18T22:47:00.001+09:00</published><updated>2011-11-01T01:05:13.984+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logic programming'/><title type='text'>Coq をインストールしてみた</title><content type='html'>&lt;p&gt;今日、現場の昼休みに、最近噂の Coq の&lt;a href="http://www.iij-ii.co.jp/lab/techdoc/coqt/"&gt;チュートリアル&lt;/a&gt;を見つけたので、早速インストールしてみる。&lt;/p&gt;&lt;p&gt;Fedora 15 でアプリケーションの追加と削除を開くと、Coq 8.3がリストアップされてきたので、チェックを入れて適用。&lt;/p&gt;&lt;p&gt;さらに、端末を開いて coqide と打ち込んでみると、ひとしきり追加のインストールが実行されたあと、CoqIDE が開いた。とりあえず、チュートリアル 一回目の練習問題を解いてみるが、初回なんで難しくない。&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-yO5Ydwrp9Ok/Tp2BsCA7sEI/AAAAAAAAAP4/SG_tUOVvz6w/s1600/Screenshot-CoqIde.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="138" width="320" src="http://3.bp.blogspot.com/-yO5Ydwrp9Ok/Tp2BsCA7sEI/AAAAAAAAAP4/SG_tUOVvz6w/s320/Screenshot-CoqIde.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;結構面白い。明日もやろっと。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8027398812612258711?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8027398812612258711/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/coq.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8027398812612258711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8027398812612258711'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/coq.html' title='Coq をインストールしてみた'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-yO5Ydwrp9Ok/Tp2BsCA7sEI/AAAAAAAAAP4/SG_tUOVvz6w/s72-c/Screenshot-CoqIde.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-9071138186115323617</id><published>2011-10-17T23:40:00.000+09:00</published><updated>2011-11-21T21:13:30.604+09:00</updated><title type='text'>リファクタリング再読 4章 テストの構築</title><content type='html'>&lt;p&gt;このブログで、何度も引用してきたけど、10年以上前に読んだリファクタリングが、今読んでも面白い。&lt;/p&gt;&lt;p&gt;面白いと言っても、当たり前の事が普通に書いてあるだけなんだけど、忘れた頃に読み返すと、自分が現場でいつも言っている事と大部分一致していて、若い頃に受けた影響ってやっぱりずっと残るんだと実感する。&lt;span style="font-size:smaller;"&gt;（さすがに、このレベルの名著ですら、やはり10年も経つとある程度の陳腐化は避けられず、全てに同意はできるわけではないけど…）&lt;/span&gt;&lt;/p&gt;&lt;p&gt;今日は 『4章 テストの構築』から、何点か引用して考えてみたい。&lt;/p&gt;====&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;テストを完全に自動化して、その結果もテストにチェックさせること。(P.90)&lt;/div&gt;xUnit Patterns の言葉で言うと、&lt;a href="http://xunitpatterns.com/Manual%20Intervention.html"&gt;Manual Intervention&lt;/a&gt;は止めようねって事で、まあ、JUnitの基本中の基本。とはいっても、@Test メソッドの中で普通のアサーションで書ける比較を、標準出力に書き出して目視確認してたおバカさんを、こないだ発見した。こんなレベルの人が「JUnit 使用歴○○年です！」なんつってプロジェクトに入り込んできちゃったりするから、この業界っておそろしい。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;テストを頻繁に実行せよ。コンパイル時にはテストを局所化して、一日に最低一度は全てのテストを実行せよ。(P.94) &lt;/div&gt;今は普通に CIサーバでコミット時にテスト走らせたり、incremental test とかも普及してるから、一日一度はさすがに10年前って感じがするが、なるべく頻繁に実行すべしってのが、この文の趣意。まあ、なんぼ言っても、他人のテストコードをコケさせておきながら、コンパイルが通ってるってだけでテストもせず、平気でコミットする間抜けが減るどころか永遠に増え続けてるから、気が滅入るが…。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;バグレポートを受け取ったら、まずそのバグを明らかにするための単体テストを書け。(P.97)&lt;/div&gt;これは今も昔も良いプラクティスで、余り反論する人を見たことがないけど、数年前までは、いざバグを再現させるテストコードを書こうにも、そもそもテスタビリティが低すぎて、異常に難易度が高い場面もあった。今は、instrumentation を活用したテストフレームワークが普及しているから、そうでもないけど。（テストツールのテスト能力が高まっただけで、ソースコードのテスタビリティは大して進歩していないのが悲しいが）&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;ここでお話しするのは「単体テスト」です。&lt;span style="color:red;"&gt;これはプログラマの生産性を向上するために行うものです。&lt;/span&gt;これで品質管理部門が満足するとしても、それは副作用に過ぎません(p.96)&lt;/div&gt;リファクタリング〜xUnit の文脈の中で、「機能テスト」と対置されて語られる「単体テスト（UnitTest）」って、ウォーターフォール・モデルの単体テストを単に自動化しただけのものとはかなり違うんだけど、この勘違いは今でもかなり根強い。自分が、現場で説明する時には、「外部品質じゃなくて内部品質をあげるためのツールだから」とか言う事がある。分からない人はどう言い換えてもやはり分かってくれないけど、わかる人はなるほどそうかと納得してくれたりする。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;不完全なテストでも、書いて実行する方が、実行できない完全なテストよりもましだ。&lt;/div&gt;テストを書けば自分が楽になるって認識が成立しないとプログラマはテストを書きたがらないわけで、つまり下手なプログラマって、テストコードによって自分で自分の作業を楽にする事ができないプログラマなんだけど、その手の輩に無理やりテストを書かせようとするから無理なカバレッジ基準が制定されて、後付けでパスを通そうとするから、却って生産性が下がる。そんなのどうせ、まともなアサーションが書かれるわけないのにさ。&lt;br/&gt;&lt;br/&gt;本当は、自覚して UnitTest を使えてるプログラマが、どこにどの程度テストコードを書くか自分で判断すればいい事なんだけど、最低辺も含めて、いろんな人が集まるプロジェクトでは、うーんやっぱ難しいのかな…&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;大事な事は、一番怪しいと思う部分をテストすることです。それが最も効率の良いテスト方法です。(p.97)&lt;/div&gt;&lt;div style="border:1px dashed grey;"&gt;失敗の恐れのある境界条件を考えて、そこを集中的にテストせよ。(p.99)&lt;/div&gt;&lt;div style="border:1px dashed grey;"&gt;失敗すると予想される時に、例外が上がることをテストし忘れないこと。(p.100)&lt;/div&gt;境界条件や例外条件なんかをテストするにしても、テスト駆動／テストファーストでやるのが、結局は一番楽で確実なんだけど、現場のレベルによってはいくら言い聞かせても浸透しない。後付けでテスト書いたって、カバレッジだけに必死になって、どこが「怪しい」かなんて完全に眼中の外になってしまう事が分かりきってるんだけどね。&lt;/p&gt;&lt;br/&gt;&lt;p&gt;&lt;div style="border:1px dashed grey;"&gt;テストで全てのバグが見つからないからといって、テストを書くのを止めてはならない。ほとんどのバグはテストで補足される。&lt;/div&gt;そもそも開発者が要件を誤解していたり、忘れていたりしたら、そういった認識エラーは本体コードと同様にテストコードにも織り込まれてしまうから、開発者テストだけで捕捉するのは論理的に不可能。そういった限界がある事を認識した上で、機能テストも絡めた全体的なテスト計画を立てるのが常道。&lt;/p&gt;&lt;br/&gt;====&lt;p&gt;あと、引用ではないけどテスト関連で付け加えると、『リファクタリング』に載ってるリファクタリング・パターンのほとんどに「コンパイルして&lt;b&gt;テスト&lt;/b&gt;する」と言う手順が組み込まれている事も、改めて確認できる。&lt;br/&gt;&lt;br/&gt;この10数年で、リファクタリングという言葉が普及したおかげもあってか、動いてるコードに手を入れる心理的ハードルが昔より低くなったけど、「動いているコードはいじるな」っていう昔からの不文律を乗り越えて良いのは、テストコードという前提あってこそという、基本中の基本が蔑ろにされ始めてるのを感じる。テストもせずにコードをいじって、CIサーバから常時テスト失敗メールが飛んできてるのに何とも思わない連中が、どんどん増えてきている気がする。&lt;br/&gt;&lt;br/&gt;出来ている現場の出来てる人達はびっくりするかもしれないけど、まだまだこんな感じの現場が多いんだよな…いかん、また眠れなくなってくる…&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-9071138186115323617?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/9071138186115323617/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/4.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9071138186115323617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/9071138186115323617'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/4.html' title='リファクタリング再読 4章 テストの構築'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-5865564930372703912</id><published>2011-10-10T09:42:00.002+09:00</published><updated>2012-01-04T21:55:49.792+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>自動テストのレベル分け</title><content type='html'>&lt;p&gt;最近は、「xUnit で UnitTest を書いてカバレッジとってます」なんて、どいつもこいつも謳ってるけど、お前らマジかと。それで出来てるつもりなのかと…?&lt;/p&gt;&lt;p&gt;というわけで、秋の朝がさわやかなので、自動テストの&lt;span style="color:snow;"&gt;出来てる度合い&lt;/span&gt;の段階区分を考えてみたい。&lt;/p&gt;　&lt;span style="font-weight:bold; font-size:larger;color:snow;"&gt;Level 3: 出来てる：常時テスト成功、高カバレッジ&lt;/span&gt;&lt;p&gt;ちゃんとできてるプロジェクトの出来る子ちゃん達からしたら、取り立てて言及することもない当たり前の状態だと思う。&lt;/p&gt;&lt;p&gt;"&lt;a href="http://c2.com/cgi/wiki?CleanCheckIn"&gt;Clean Check-In&lt;/a&gt;" が普通に守られているから、当然、テストも常時全件成功する。まあ基本中の基本。&lt;/p&gt;&lt;p&gt;で、TDD/TestFirst で開発してるから、開発の最初期から高カバレッジ（計測対象範囲内でのカバレッジ基準充足）で始まり、進捗に伴いソースコード量が増えていく中でも、高カバレッジを維持したまま推移する。&lt;/p&gt;&lt;br/&gt;&lt;span style="font-weight:bold; font-size:larger;color:snow;"&gt;Level 2:怪しい：ほぼ常時テスト成功、低カバレッジ&lt;/span&gt;&lt;p&gt;"常時"かつ"全件"、テストが成功してはいるけど、カバレッジが低いプロジェクト。まあ、後付けでテストを書こうとすると、えてしてそんな感じになる。&lt;/p&gt;&lt;p&gt;原因としては、単にスキルがないから仕方なく後付けになったり、確信的にテストをサボっていたり、いろいろあるにせよ、結果的に以下のような感じになる。&lt;/p&gt;&lt;p&gt;①：&lt;span style="text-decoration:underline"&gt;テスト・コーディングに凄い余計な時間が掛かる。&lt;/span&gt;テスト・ファーストでやってさえいれば自然に得られたはずの保守性・メンテ性が備わってない低テスタビリティ・コードに無理やりテストコードを書いてく事になるから、まともな生産性は無理。&lt;/p&gt;&lt;p&gt;② ：&lt;span style="text-decoration:underline"&gt;テスティング・ポイントがウヤムヤになる。&lt;/span&gt;本体コードを書いていた時点では脳内にあったはずのコーディング意図がとっくに揮発した状態で、テストコードを後付けする破目になる。何をテストしてるのか本人が分かってない状態。&lt;/p&gt;&lt;p&gt;③ ：&lt;span style="text-decoration:underline"&gt;テストコードがザルになる。&lt;/span&gt;①で指摘した生産性の低いテストコードを、②で指摘した曖昧状態のプログラマが書いてくわけだから、「何かをテストする」事ではなくカバレッジを通す事が自己目的化してしまい、結果、Assertion も Expectation も不十分で、単に実行経路に含まれただけの空虚なテストコードになってしまう。&lt;/p&gt;&lt;p&gt;まあ、後付けテストの全てがそんな糞テストコードばかりとは限らないけど、テストコードは本体コードより先に書いとくに越したことはない。それが普通なのだと認識するだけで、悪い事がいろいろ避けられて良い事がいろいろ増えてくる。&lt;/p&gt;&lt;br/&gt;&lt;span style="font-weight:bold; font-size:larger;color:snow;"&gt;Level 1:下手糞：常時テスト失敗、低カバレッジ&lt;/span&gt;&lt;p&gt;低カバレッジでも、取り敢えずテストが存在して差し当たり成功していれば、まだ見どころはある。また、たまたま間違えてテストを壊す事もあると思うが、そんなのすぐ直せば良い事で別に問題じゃない。&lt;/p&gt;&lt;p&gt;だけど、テストが通らないコードをコミットするのが常態化していたり、CIサーバでテストが失敗してるのに放置されていたりしたら、それはかなりの低スキル・チームの疑いがある。&lt;/p&gt;&lt;/p&gt;実は、そうしたプロジェクトでは、Level 3 の状態を志してはいたもののスキル不足で健闘虚しくって感じじゃなくて、 Level 1 の状態で普通・正常だと思ってる開発者が大勢を占めていたりする。酷いのになると「今までに経験したプロジェクトではそれが普通だったし、テストが壊れても気にしない方がリファクタしやすい。」なんて事を真顔で主張したりする（リファクタするためにこそテストコードが必要だという最低限の常識を弁えていれば、そうした発言は出ないんだけど…）。&lt;/p&gt;&lt;p style="font-size:smaller;"&gt;そうやって考えてくと、そもそも技術者の○○使用経験とか○○歴とかって何なのだろうという問題に突き当たるが、これは別の機会に考えてみたい。あと、Level 1 で生じている問題には、余りにも劣化した形で普及し実践されている『リファクタリング』もあるのだけど、これも別の機会に考える。&lt;/p&gt;&lt;p&gt;朝から、気が滅入ってきた。山でも歩いてこよっと。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-5865564930372703912?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/5865564930372703912/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/xunit-unittest-level-3-clean-check-in.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5865564930372703912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5865564930372703912'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/xunit-unittest-level-3-clean-check-in.html' title='自動テストのレベル分け'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3113770559225547608</id><published>2011-10-09T23:49:00.000+09:00</published><updated>2011-10-09T23:49:23.155+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>Eclipse から XSLT 2.0 を使うやり方</title><content type='html'>今更だけど、Eclipse の XSL Developer Tool で XSLT2.0 を使うやり方が分かったのでメモっとく。&lt;ul&gt;&lt;li&gt;まず、Saxon home edition の新しいやつ (&lt;a href="http://sourceforge.net/projects/saxon/files/Saxon-HE/9.3/saxonhe9-3-0-8j.zip/download  "&gt;saxonhe9-3-0-8j.zip&lt;/a&gt;)をダウンロード。&lt;/li&gt;&lt;li&gt;ダウンロードしたZIPを適当なとこに展開して、中の saxon9he.jar を出しておく。&lt;/li&gt;&lt;li&gt;Eclipse のメニューを [Window]&gt;[Preference]&gt;[XML]&gt;[XSL]&gt;[Java Processors] ってたどる。&lt;/li&gt;&lt;li&gt;Add を押して開いたダイアログボックスで、だいたい以下の様な感じで入力。追加したやつのチェックボックスを選択しておく。&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Jbg8iWXl-a0/TpGst_XbgSI/AAAAAAAAAPw/mGOvHB6-ULk/s1600/setting-xslt-processor%2B.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="198" width="320" src="http://2.bp.blogspot.com/-Jbg8iWXl-a0/TpGst_XbgSI/AAAAAAAAAPw/mGOvHB6-ULk/s320/setting-xslt-processor%2B.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;これで使えるようになる。試しに、&lt;a href="http://yasutech.blogspot.com/2009/12/xslt_1589.html"&gt;昔のポスト&lt;/a&gt;で書いた XSLT で平均と分散を計算するやつを、XSLT2.0 を使ってやってみる。&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;&lt;br /&gt;  &amp;lt;xsl:output indent="yes" /&amp;gt;&lt;br /&gt;  &amp;lt;xsl:template match="/list"&amp;gt;&lt;br /&gt;    &amp;lt;xsl:variable name="result"&amp;gt;&lt;br /&gt;      &amp;lt;xsl:call-template name="stat"&amp;gt;&lt;br /&gt;        &amp;lt;xsl:with-param name="items" select="item" /&amp;gt;&lt;br /&gt;        &amp;lt;xsl:with-param name="subtotal" select="0" /&amp;gt;&lt;br /&gt;        &amp;lt;xsl:with-param name="count" select="0" /&amp;gt;&lt;br /&gt;      &amp;lt;/xsl:call-template&amp;gt;&lt;br /&gt;    &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;    &amp;lt;average&amp;gt;&lt;br /&gt;      &amp;lt;xsl:value-of select="$result/avg" /&amp;gt;&lt;br /&gt;    &amp;lt;/average&amp;gt;&lt;br /&gt;    &amp;lt;varianece&amp;gt;&lt;br /&gt;      &amp;lt;xsl:value-of select="$result/sumOfD2 div $result/count" /&amp;gt;&lt;br /&gt;    &amp;lt;/varianece&amp;gt;&lt;br /&gt;  &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;  &amp;lt;xsl:template name="stat"&amp;gt;&lt;br /&gt;    &amp;lt;xsl:param name="items"/&amp;gt;&lt;br /&gt;    &amp;lt;xsl:param name="subtotal"/&amp;gt;&lt;br /&gt;    &amp;lt;xsl:param name="count"/&amp;gt;&lt;br /&gt;    &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;      &amp;lt;xsl:when test="$items"&amp;gt;&lt;br /&gt;        &amp;lt;xsl:variable name="t"&amp;gt;&lt;br /&gt;          &amp;lt;xsl:call-template name="stat"&amp;gt;&lt;br /&gt;            &amp;lt;xsl:with-param name="items" select="$items[position() &amp;gt; 1]" /&amp;gt;&lt;br /&gt;            &amp;lt;xsl:with-param name="subtotal" select="$subtotal + $items[1]" /&amp;gt;&lt;br /&gt;            &amp;lt;xsl:with-param name="count" select="$count + 1" /&amp;gt;&lt;br /&gt;          &amp;lt;/xsl:call-template&amp;gt;&lt;br /&gt;        &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;        &amp;lt;sumOfD2&amp;gt;&amp;lt;xsl:value-of select="($items[1]-$t/avg)*($items[1]-$t/avg)+$t/sumOfD2"/&amp;gt;&amp;lt;/sumOfD2&amp;gt;&lt;br /&gt;        &amp;lt;count&amp;gt;&amp;lt;xsl:value-of select="$t/count"/&amp;gt;&amp;lt;/count&amp;gt;&lt;br /&gt;        &amp;lt;avg&amp;gt;&amp;lt;xsl:value-of select="$t/avg"/&amp;gt;&amp;lt;/avg&amp;gt;&lt;br /&gt;      &amp;lt;/xsl:when&amp;gt;&lt;br /&gt;      &amp;lt;xsl:otherwise&amp;gt;&lt;br /&gt;        &amp;lt;sumOfD2&amp;gt;0&amp;lt;/sumOfD2&amp;gt;&lt;br /&gt;        &amp;lt;count&amp;gt;&amp;lt;xsl:value-of select="$count"/&amp;gt;&amp;lt;/count&amp;gt;&lt;br /&gt;        &amp;lt;avg&amp;gt;&amp;lt;xsl:value-of select="$subtotal div $count"/&amp;gt;&amp;lt;/avg&amp;gt;&lt;br /&gt;      &amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;    &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;  &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="http://yasutech.blogspot.com/2009/12/xslt_1589.html"&gt;前回&lt;/a&gt;と同じ入力XMLから同じ結果が得られることが確認できた。&lt;/p&gt;&lt;p&gt;前にやった時は、結果ツリーフラグメントの制約から template の結果を文字列にして返さざるを得なくて煩わしかったけど、XSLT 2.0 の temporary tree では 普通の XML データとして扱えるので、やってる事をより直截に表現したコードになった。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3113770559225547608?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3113770559225547608/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/10/eclipse-xslt-20.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3113770559225547608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3113770559225547608'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/10/eclipse-xslt-20.html' title='Eclipse から XSLT 2.0 を使うやり方'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-Jbg8iWXl-a0/TpGst_XbgSI/AAAAAAAAAPw/mGOvHB6-ULk/s72-c/setting-xslt-processor%2B.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-1017313360844440849</id><published>2011-09-29T01:03:00.000+09:00</published><updated>2011-10-01T04:24:37.479+09:00</updated><title type='text'>リファクタリング本の Cyclomatic complexity</title><content type='html'>&lt;p&gt;&lt;a href="http://amazon.co.jp/o/ASIN/4894712288/yasuabe1984-22/ref=nosim"&gt;『リファクタリング』&lt;/a&gt; を読んだ人なら、以下のコードに見覚えがあるかもしれない。第一章「最初の例」でのリファクタリング実演のために用意された架空の「長すぎるメソッド（Long method）」で、このメソッドを含む一群のコードを改善する過程で、リファクタ術が披露される。&lt;/p&gt;&lt;p&gt;まあ、実演のためのサンプルだから、本気でバカ長いメソッドを掲載するわけにはいかないだろうけど、それでも全然簡潔ではないし見た目も悪い。&lt;/p&gt;&lt;p&gt;自分なら普通、こういうのを製品コードに残したりはしないけど、それは単に自分にとって綺麗とか汚いといった審美的な感覚だけではなくて、他の開発者のミスリーディングを引き起こしたり生産性を下げたりといった、つまり他人様に迷惑をかける真似はすべきでないという、割と真面目というか普通な社会人的常識からでもあったりする。&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public String statement() {&lt;br /&gt;      double totalAmount = 0;&lt;br /&gt;      int frequentRenterPoints = 0;&lt;br /&gt;      Enumeration&lt;Rental&gt; rentals = _rentals .elements();&lt;br /&gt;      String result = "Rental Record for " + getName() + "\n";&lt;br /&gt;      while (rentals.hasMoreElements()) {&lt;br /&gt;         double thisAmount = 0;&lt;br /&gt;         Rental each = (Rental) rentals.nextElement();&lt;br /&gt;         &lt;br /&gt;         switch (each.getMovie().getPriceCode()) {&lt;br /&gt;         case Movie.REGULAR:&lt;br /&gt;            thisAmount += 2;&lt;br /&gt;            if (each.getDaysRented() &gt; 2)&lt;br /&gt;               thisAmount += (each.getDaysRented() - 2) * 1.5;&lt;br /&gt;            break;&lt;br /&gt;         case Movie.NEW_RELEASE:&lt;br /&gt;            thisAmount += each.getDaysRented() * 3;&lt;br /&gt;            break;&lt;br /&gt;         case Movie.CHILDRENS:&lt;br /&gt;            thisAmount += 1.5;&lt;br /&gt;            if (each.getDaysRented() &gt; 3)&lt;br /&gt;               thisAmount += (each.getDaysRented()  - 3) * 1.5;&lt;br /&gt;            break;&lt;br /&gt;         }&lt;br /&gt;         frequentRenterPoints ++;&lt;br /&gt;         if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &amp;&amp;&lt;br /&gt;               each.getDaysRented() &gt; 1) frequentRenterPoints ++;&lt;br /&gt;         &lt;br /&gt;         result += "\t" + each.getMovie().getTitle() + "\t" +&lt;br /&gt;         String.valueOf(thisAmount) + "\n";&lt;br /&gt;         totalAmount += thisAmount;&lt;br /&gt;      }&lt;br /&gt;      result += "Amount owed is " + String.valueOf(totalAmount) + "\n";&lt;br /&gt;      result += "You earned " + String.valueOf(frequentRenterPoints) +&lt;br /&gt;      " frequent renter points";&lt;br /&gt;      &lt;br /&gt;      return result;&lt;br /&gt;   }&lt;/pre&gt;&lt;p&gt;ところで、このコードの扱いにくさを「計測」するとどうなるか。よく使われている尺度としては、Cyclomatic Complexity があるが、どんなもんだろう。&lt;/p&gt;&lt;p&gt;ちなみに、CheckStyle の解説では、&lt;ul&gt;&lt;li&gt;1-4: considered good&lt;/li&gt;&lt;li&gt;5-7: ok&lt;/li&gt;&lt;li&gt;8-10: consider re-factoring&lt;/li&gt;&lt;li&gt;11+: re-factor now!&lt;/li&gt;&lt;/ul&gt;とある。&lt;/p&gt;&lt;p&gt;で、実際に測ってみると出てきた複雑度は 9 だった。"consider re-factoring"という事になるから、本の中での実演のネタとしては、正に丁度良かったという事になる。&lt;/p&gt;&lt;p&gt;さらに本に従って最後の段階までリファクタを施したコードの CyclomaticComplexity を測ってみると、結局 2 にまで低減していた。さすがにこれくらいまでやると、変な引け目も後ろめたさもなくソース・コードを共有できる。&lt;/p&gt;&lt;p&gt;で、せっかくある程度客観的にコードの良し悪しがでるのだから、自分だけじゃなくチームにも、簡潔で扱いやすいコードを書く方向で前向きに頑張ってほしいと思うのだけど、いろんな人が集まる現実のプロジェクトではそうも言ってられない場合も多い。&lt;/p&gt;&lt;p&gt;特に、すでにある程度コードが書き貯まったプロジェクトで、途中で CyclomaticComplexity チェックを適用したりなんかすると、「11+」どころか、妥協して15以上とかで設定しても警告が大量発生して、結局「今回は諦めようぜ」って感じになる。&lt;/p&gt;&lt;p&gt;人生って厳しいよね。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-1017313360844440849?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/1017313360844440849/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/09/cyclomatic-complexity.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1017313360844440849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1017313360844440849'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/09/cyclomatic-complexity.html' title='リファクタリング本の Cyclomatic complexity'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-5536106319317838325</id><published>2011-09-18T00:12:00.000+09:00</published><updated>2011-11-03T17:15:20.085+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>依存 jar を変更したらどうなるか</title><content type='html'>あるアプリケーションがビルド時に参照していた ライブラリの jar を変更して、そのアプリケーション再コンパイルせずに実行したらどうなるか。&lt;br/&gt;&lt;br/&gt;====&lt;br/&gt;以下のようなライブラリ・コードを書き、コンパイルして foo.jar に丸めておく。&lt;pre class="prettyprint"&gt;package p1;&lt;br /&gt;&lt;br /&gt;public class Foo {&lt;br /&gt;  public String bar() {&lt;br /&gt;    return "hello";&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;で、このライブラリを使う以下のようなクライアントコードを書いて、-cp に foo.jar を指定してコンパイルする。&lt;pre class="prettyprint"&gt;package p2;&lt;br /&gt;&lt;br /&gt;import p1.Foo;&lt;br /&gt;&lt;br /&gt;public class Client {&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    System.out.println(new Foo().bar());&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;コンパイルされたクラスを java コマンドで -cp に foo.jar  を指定して実行すると、標準出力に hello と出力される。&lt;/p&gt;&lt;br/&gt;さて、ここで クラス Foo を変更して、つまり foo.jar の中身を変えて、再コンパイルせずに再度 &lt;code&gt;Client#main()&lt;/code&gt; を実行したらどうなるか。&lt;p style="color:white;"&gt;(1) メソッドの中身を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public String bar() {&lt;br /&gt;    return "good-bye";&lt;br /&gt;  }&lt;/pre&gt;問題無し。標準出力に good-bye と表示される。&lt;p style="color:white;"&gt;(2) メソッドの名前を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public String Bar() {&lt;br /&gt;    return "hello";&lt;br /&gt;  }&lt;/pre&gt;メソッド p1.Foo.bar()Ljava/lang/String が見当たらないって事で、NoSuchMethodError が送出される。リフレクションのコーディングでよく catch したりするNoSuchMethodExceptionではなく、NoSuchMethodError が投げられてきた。&lt;p style="color:white;"&gt;(3) メソッドの引数を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public String Bar(String s) {&lt;br /&gt;    return "hello";&lt;br /&gt;  }&lt;/pre&gt;これは (2) と同じ&lt;p style="color:white;"&gt;(4) メソッドの戻り値を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public Object Bar() {&lt;br /&gt;    return "hello";&lt;br /&gt;  }&lt;/pre&gt;これも (2) と同じ。戻り値も識別される。&lt;p style="color:white;"&gt;(5) throws を追加してみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public String bar() throws IOException {&lt;br /&gt;    throw new IOException("test");&lt;br /&gt;  }&lt;/pre&gt;これは意外にも普通に実行されて、IOExceptionが送出されてスタックトレースされる。意外というのは、これを再コンパイルしようとすると、コンパイルエラーが出るからで、Client#main() に throws を追加するか、bar() を try-catch で囲むかしないと、コンパイルが通らない。でも、コンパイルは通らなくても実行時のメソッド呼び出しは成功する。&lt;p style="color:white;"&gt;(6) メソッドの可視性を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;  private String bar() {&lt;br /&gt;    return "hello";&lt;br /&gt;  }&lt;/pre&gt;これは IllegalAccessError が送出される。つまり、一応 p1.Foo.bar()Ljava/lang/String の存在は識別された上で、アクセスに失敗して例外が発生した模様。&lt;p style="color:white;"&gt;(7) クラスの可視性を変えてみる&lt;/p&gt;&lt;pre class="prettyprint"&gt;class Foo {&lt;br /&gt;…&lt;/pre&gt;(6) と同様だが、クラス p1.Foo の存在を識別したあとに、アクセスするところで失敗している。&lt;p style="color:white;"&gt;(8) 定数を変えてみる&lt;/p&gt;&lt;p&gt;メソッドは以上のような感じで、フィールドもだいたい想像がつく。で、ここでちょっと定数を試してみる事にする。&lt;/p&gt;&lt;p&gt;まずライブラリコードを以下のように変える。&lt;/p&gt;&lt;pre class="prettyprint"&gt;package p1;&lt;br /&gt;&lt;br /&gt;public class Foo {&lt;br /&gt;  public static final int C = 100;&lt;br /&gt;}&lt;/pre&gt;次に、クライアントコードを以下の様に変える&lt;pre class="prettyprint"&gt;package p2;&lt;br /&gt;&lt;br /&gt;import p1.Foo;&lt;br /&gt;&lt;br /&gt;public class Client {&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    System.out.println(Foo.C);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;両方コンパイルして実行すると、標準出力に100が実行される。&lt;/p&gt;&lt;p&gt;ここでライブラリコードを以下の様に修正し、jar を作り直す。&lt;/p&gt;&lt;pre class="prettyprint"&gt;  public static final int C = 200; &lt;/pre&gt;で、クライアントコードを再実行すると、標準出力に 200 が出力されると思いきや、実際には変更前と同じ100が出力される。&lt;br/&gt;javap で見てみると、バイトコードに定数 100 が埋め込まれているのがわかる。なるほど定数はこういう扱いらしい。&lt;pre style="color:snow;background-color:black;line-height:120%;"&gt;public static void main(java.lang.String[]);&lt;br /&gt;  Code:&lt;br /&gt;   0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   3: bipush 100&lt;br /&gt;   5: invokevirtual #3; //Method java/io/PrintStream.println:(I)V&lt;br /&gt;   8: return &lt;/pre&gt;&lt;p style="color:white;"&gt;(9) null値 を試してみる&lt;/p&gt;ライブラリ・コード を以下のように変更して、両方とも再コンパイルして実行してみる。&lt;pre class="prettyprint"&gt;package p1;&lt;br /&gt;&lt;br /&gt;public class Foo {&lt;br /&gt;  public static final String C = null;&lt;br /&gt;}&lt;/pre&gt;標準出力には、null が出力される。&lt;p&gt;ここでライブラリ・コードを、public static final String C = "a"; に変更して、クライアントを実行してみる。&lt;/p&gt;(8) の結果から、null が出力される結果を類推してしまうが、実際には "a" が出力される。理由は、Java 言語仕様として null 定数として扱われないためコンパイル時には byte コードに直接書き込まれず、実行時に初めて Foo.Cの値を読むことになるかららしい。javap は以下のようになる。&lt;pre style="color:snow;background-color:black;line-height:120%;"&gt;public static void main(java.lang.String[]);&lt;br /&gt;  Code:&lt;br /&gt;   0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;&lt;br /&gt;   3: getstatic #3; //Field p1/Foo.C:Ljava/lang/String;&lt;br /&gt;   6: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V&lt;br /&gt;   9: return&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-5536106319317838325?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/5536106319317838325/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/09/jar.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5536106319317838325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5536106319317838325'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/09/jar.html' title='依存 jar を変更したらどうなるか'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3938377673435281829</id><published>2011-08-27T23:06:00.002+09:00</published><updated>2011-08-27T23:10:36.396+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><title type='text'>Advanced Level テストマネージャ試験受けてみた</title><content type='html'>今日、&lt;a href="http://jstqb.jp/index.html"&gt;JSTQB&lt;/a&gt; という団体がやってる、ソフトウェア・テスト技術者試験の Advanced Level 試験（Foundation Levelの上級試験）を受けてきた。&lt;br /&gt;&lt;br /&gt;全65問のうち、きっと問題のミスだろうと思われる不可解なところを除けば、全問できたような気がする。まあ9割5分とか9割でも普通は合格だと思う。&lt;br /&gt;&lt;br /&gt;というかあまり難しくなかった。去年、実施したらしいトライアル版試験の統計をみると合格率10%というから、さぞかし難関だろうと思ってたけど、試験時間を半分過ぎた辺りから余裕な感じで退出する人も多かったりして、今回は合格率50%を越えるような気がしないでもない。&lt;br /&gt;&lt;br /&gt;ところで、試験勉強はISTQB（JSTQBの親の国際団体）が出している試験のシラバス（学習事項）をひたすら読むだけだけど、これがよくできていて勉強が苦にならない。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://yasutech.blogspot.com/2011/01/jstqb.html"&gt;以前のポスト&lt;/a&gt;で、Foundation Level のシラバスを紹介したけど、さすがにそれよりはテスター向けの専門性が高い。それでも自分のようなテスト専門じゃない開発者にとっても、読み応えがある。&lt;br /&gt;&lt;br /&gt;実プロジェクトのテスト技術者の教科書としてもそのまま使えそうな内容で、暗記事項の羅列などはほとんど無いかわりに、なんというか現場感覚があるので、過去に携わったプロジェクトや今現在進行中のプロジェクトについて、いろいろ考えさせられる。&lt;br /&gt;&lt;br /&gt;ちなみに Advanced Level 資格には テストマネージャ、テストアナリスト、テストテクニカルアナリストという種別があり（今回のはテストマネージャだった）、３つそろったら、なんか格上の称号が与えられるらしい。まあ、欲しくないと言えば嘘になる。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3938377673435281829?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3938377673435281829/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/08/advanced-level.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3938377673435281829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3938377673435281829'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/08/advanced-level.html' title='Advanced Level テストマネージャ試験受けてみた'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-4959042520648898495</id><published>2011-08-15T00:18:00.002+09:00</published><updated>2012-01-04T21:56:11.758+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>JMockit: 基底クラスのコンストラクタのすりかえ</title><content type='html'>基底クラスのコンストラクタ呼び出しだけをモックですりかえるにはどうすれば良いか。&lt;br /&gt;&lt;br /&gt;以下のように実験してみた。AssertionError を投げているところを、設定ファイルの読み込みとかマスタデータへの依存とか、面倒なセットアップが必要だったり時間がかかったりする処理に読み替えると、ニーズが分かると思う。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;例題 (1)&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey; padding-left:7px;"&gt;クラス BaseClass を継承したクラス CuT があるとする。こんな感じ。&lt;br /&gt;&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;public class CuT extends BaseClass {&lt;br /&gt;&lt;br /&gt;   public CuT() {&lt;br /&gt;&lt;br /&gt;      super();&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;ところが、BaseClass の実装はこんな感じだったとする。&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;public class BaseClass {&lt;br /&gt;&lt;br /&gt;   protected BaseClass() {&lt;br /&gt;&lt;br /&gt;      throw new AssertionError();&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;以下のテストコードを実行すると、当然、AssertionEror が発生してテストが落ちるが、落とさずにインスタンスを作るにはどうすれば良いか？&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;@Test public void testCuTConstructor() {&lt;br /&gt;&lt;br /&gt;   //ここに何を書けば落ちないか&lt;br /&gt;&lt;br /&gt;   new CuT();&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;答え (1)&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey;padding-left:7px;"&gt;以下の様にして、基底クラスのコンストラクタをすり替えられる。&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;@Test public void $init() {&lt;br /&gt;&lt;br /&gt;   new MockUp&amp;lt;BaseClass&amp;gt;() {&lt;br /&gt;&lt;br /&gt;      @Mock void $init() { /*とりあえず何もしない*/}&lt;br /&gt;&lt;br /&gt;   };&lt;br /&gt;&lt;br /&gt;   new CuT();&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;例題(2)&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey;padding-left:7px;"&gt;例題(1) にちょっと書き足してみる。&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;public class BaseClass {&lt;br /&gt;&lt;br /&gt;   protected final int bar;&lt;br /&gt;&lt;br /&gt;   protected BaseClass(int bar) {&lt;br /&gt;&lt;br /&gt;      this.bar = bar;&lt;br /&gt;&lt;br /&gt;      throw new AssertionError();&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class CuT extends BaseClass {&lt;br /&gt;&lt;br /&gt;   public CuT(int bar) {&lt;br /&gt;&lt;br /&gt;      super(bar);&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int foo() {&lt;br /&gt;&lt;br /&gt;      return this.bar * 100;&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Test public void $init2() {&lt;br /&gt;&lt;br /&gt;   new MockUp&amp;lt;BaseClass&amp;gt;() {&lt;br /&gt;&lt;br /&gt;      //ここに何も書かないと、下のアサーションが失敗する&lt;br /&gt;&lt;br /&gt;   };&lt;br /&gt;&lt;br /&gt;   Assert.assertEquals(200, new CuT(2).foo());&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;このままだと基底クラスの bar が 2 で初期化されず、foo() が 0 * 100 = 0を返してしまうので、アサーションが失敗する。MockUp&lt;BaseClass&gt; の匿名インナー型定義に、何を書き足せばテストが通るか？&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;答え (2)&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey;padding-left:7px;"&gt;コンストラクタ実行中のタイミングで、モック対象インスタンスの bar フィールドに適当な値を設定すれば良いわけだが、そのインスタンスをどう取得するかというのが問題。"it"フィールドという仕組みを利用すれば良いらしい。&lt;pre style="padding-left:5px;margin-left:5px;" class="prettyprint"&gt;@Test public void $init2() {&lt;br /&gt;&lt;br /&gt;   new MockUp&amp;lt;BaseClass&amp;gt;() {&lt;br /&gt;&lt;br /&gt;      BaseClass it;&lt;br /&gt;&lt;br /&gt;      @Mock void $init(int bar) { &lt;br /&gt;&lt;br /&gt;         Deencapsulation.setField(it, bar);&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;   };&lt;br /&gt;&lt;br /&gt;   Assert.assertEquals(200, new CuT(2).foo());&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;この例では、bar は private フィールドなのでDeencapsulation ユーティリティクラスを使っている。ちなみに bar は final だけど、問題なく設定できている。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-4959042520648898495?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/4959042520648898495/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/08/jmockit_15.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4959042520648898495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4959042520648898495'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/08/jmockit_15.html' title='JMockit: 基底クラスのコンストラクタのすりかえ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6944427347764406474</id><published>2011-08-14T19:21:00.017+09:00</published><updated>2012-01-04T21:56:53.040+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>JMockit を使って簡単に「後回し」するやり方</title><content type='html'>二つのクラスがあって、片方がもう片方に依存しているとする。つまり、参照関係や使用関係がある。&lt;br /&gt;&lt;br /&gt;両方とも開発対象の場合、常に「依存される」側からしか作ろうとしない／作れない開発者がいるけど、逆の方向、つまり「依存される」側を一旦後回しにして「依存する」側から作った方が見通しが良い場合が多い。&lt;br /&gt;&lt;br /&gt;方法はいくつもあるが、今日は JMockit を使って実演してみる。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆ 仕様&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight:bold;" &gt;依存する側のクラス&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey;"&gt;クラス CuT：Collaborator を使うクラス。こいつから作る。&lt;br /&gt;　関連オブジェクト：&lt;br /&gt;　　col1: Collaboratorのインスタンス&lt;br /&gt;　　col2: Collaboratorのインスタンス&lt;br /&gt;　コンストラクタ：受け取った2つの整数によりcol1 と col2 を初期化する&lt;br /&gt;　メソッド：&lt;br /&gt;　　int foo(int number):&lt;br /&gt;　　　col1 と col2 の bar() に number を渡し、結果の合計を返す&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight:bold;" &gt;依存される側のクラス&lt;/span&gt;&lt;br /&gt;&lt;div style="border:1px dotted grey;"&gt;Collaborator：CuT に使われるクラス。後回しにする。&lt;br /&gt;　コンストラクタ：受け取った整数を保持する&lt;br /&gt;　メソッド：&lt;br /&gt;　　int bar(int number)&lt;br /&gt;　　　コンストラクタで受け取った整数と引数 number を用いて、何か計算をして返す。&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆ コーディング&lt;/span&gt;&lt;br /&gt;両クラスのガラだけ書いてみる。CuT から作ってく趣旨なので、テストクラス CuTTest も書き始める。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class CuT {}&lt;br /&gt;&lt;br /&gt;public class Collaborator {}&lt;br /&gt;&lt;br /&gt;public class CuTTest {}&lt;/pre&gt;&lt;br /&gt;まず、コンストラクタのテストを CuTTest に追加する。CuT のコンストラクタで受け取った引数が、二つの Collaborator のコンストラクタに受け渡されれば良いので、次のようなテストメソッドを書く。&lt;br /&gt;&lt;pre class="prettyprint"&gt;@Test public void $init(final Collaborator mock) {&lt;br /&gt;&lt;br /&gt; new Expectations() {&lt;br /&gt;&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;     new Collaborator(2);&lt;br /&gt;&lt;br /&gt;     new Collaborator(3);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt; };&lt;br /&gt;&lt;br /&gt; new CuT(2, 3);&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;とりあえず、存在しないコンストラクタを呼んでいるのでコンパイルエラーになるから、これを解消する。&lt;br /&gt;&lt;br /&gt;まず、Collaborator のコンストラクタだが、こいつは以下の様なコードで後回しにする。&lt;pre class="prettyprint"&gt;public Collaborator(int i) {&lt;br /&gt;&lt;br /&gt; throw new AssertionError();&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;次に、CuT のコンストラクタだが、まずモックがちゃんと効いているか確かめるために、以下のように空の実装を書いて、一度テストを実行してみる。&lt;pre class="prettyprint"&gt;public CuT(int number1, int number2) {}&lt;/pre&gt;テスト実行すると、「コンストラクタが引数 2 で呼ばれていない」といった感じのエラーメッセージが出力されるので、今度は以下のような感じで、ちゃんと書く。&lt;pre class="prettyprint"&gt;public class CuT {&lt;br /&gt;&lt;br /&gt; final Collaborator col1;&lt;br /&gt;&lt;br /&gt; final Collaborator col2;&lt;br /&gt;&lt;br /&gt; public CuT(int number1, int number2) {&lt;br /&gt;&lt;br /&gt;    this.col1 = new Collaborator(number1);&lt;br /&gt;&lt;br /&gt;    this.col2 = new Collaborator(number2);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;再度テスト実行すると、テスト成功。&lt;br /&gt;&lt;br /&gt;続いて同様に、まずテストから foo() を書く。&lt;br /&gt;&lt;br /&gt;テスティングポイントは、「foo() で受け取った引数を、col1, col2 の bar()に渡している事」と「col1, col2 の bar()の戻り値の合計を、foo() の戻り値とする」なので、以下のようなテストコードになる。&lt;br /&gt;&lt;pre class="prettyprint"&gt;@Test public void foo(&lt;br /&gt;&lt;br /&gt;    @Mocked(capture=1) final Collaborator col1,&lt;br /&gt;&lt;br /&gt;    @Mocked(capture=1) final Collaborator col2) {&lt;br /&gt;&lt;br /&gt; new Expectations() {{&lt;br /&gt;&lt;br /&gt;    col1.bar(7); result = 10;&lt;br /&gt;&lt;br /&gt;    col2.bar(7); result = 100;&lt;br /&gt;&lt;br /&gt; }};&lt;br /&gt;&lt;br /&gt; Assert.assertEquals(110, new CuT(2, 3).foo(7));&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;Collaborator#bar() の実装が無いので、コンストラクタ同様に AssertionError 送出のみの後回しコードを追加して、コンパイルエラーを解消する。&lt;pre class="prettyprint"&gt;public int bar(int i) {&lt;br /&gt;&lt;br /&gt; throw new AssertionError();&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;CuT#foo() は、とりあえずダミーの固定値を返すようにして、テストを実行してみる。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public int foo(int i) {&lt;br /&gt;&lt;br /&gt; return -1;&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;実行すると「bar が引数7 で呼ばれていない」といったエラーメッセージが出力される。期待通りなので、おもむろに foo() の実装を本物コードに修正する。&lt;pre class="prettyprint"&gt;public int foo(int i) {&lt;br /&gt;&lt;br /&gt; return this.col1.bar(i) + this.col2.bar(i);&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;これで、テストがちゃんと通るようになる。&lt;br /&gt;&lt;br /&gt;一段落ついたら、クラス CuT の事は忘れて、Collaborator 実装に集中して取りかかればいい。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆ 補足&lt;/span&gt;&lt;br /&gt;ちなみに、JMockit に不慣れで capture の意味が分からなければ、このサンプルの col1 と col2 の capture を変えてテスト実行すれば、capture がどういう働きを持つのか分かると思う（場合によっては Expectations を NonSrictExpectations に替える必要がある）。&lt;br /&gt;&lt;br /&gt;例えば、col1 のcapture を2に変えると、foo()の戻り値は20になる。col2 をそのまま変えずに col1 の capture を 0 にすると、foo()の戻り値は100になり、col2 の capture を2にすると、foo()の戻り値は200になる。&lt;br /&gt;&lt;br /&gt;テストメソッド CuTTest#foo() のパラメータの col1, col2 が、CuT のフィールドのcol1, col2 のどれに対応するかが、capture で制御されているのが分かると思う。&lt;br /&gt;&lt;br /&gt;さらに、もう一つ追記。上の CuTTest#foo()は以下のように書き換えられる。&lt;br /&gt;&lt;pre class="prettyprint"&gt;@Test public void foo_explicitVerification(&lt;br /&gt;&lt;br /&gt;    @Mocked(capture=1) final Collaborator col1,&lt;br /&gt;&lt;br /&gt;    @Mocked(capture=1) final Collaborator col2) {&lt;br /&gt;&lt;br /&gt; new NonStrictExpectations() {{&lt;br /&gt;&lt;br /&gt;    col1.bar(anyInt); result = 10;&lt;br /&gt;&lt;br /&gt;    col2.bar(anyInt); result = 100;&lt;br /&gt;&lt;br /&gt; }};&lt;br /&gt;&lt;br /&gt; Assert.assertEquals(110, new CuT(2, 3).foo(7));&lt;br /&gt;&lt;br /&gt; new Verifications() {{&lt;br /&gt;&lt;br /&gt;    col1.bar(7);&lt;br /&gt;&lt;br /&gt;    col2.bar(7);&lt;br /&gt;&lt;br /&gt; }};&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;若干、冗長になるが、テストの都合で指定したい動作と、検証したい動作を分けて書いている。実際の業務ロジックなんかで複雑な相互作用がある場合など、Expectations に全部書いてしまうと何がテスティングポイントだったのか分かりにくくなる事がある（特に後付けでテストを書かざるを得ない状況などで）。そんなとき Verifications のブロックに本当に検証すべきだった事を書いておくと、テスティングポイントを見失わずにすむ。&lt;br /&gt;&lt;br /&gt;ちなみに、Verifications には、FullVerifications, FullVerificationsInOrder, VerificationsInOrderといった派生クラスがあるから、適当に使い分けるべし。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6944427347764406474?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6944427347764406474/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/08/jmockit.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6944427347764406474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6944427347764406474'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/08/jmockit.html' title='JMockit を使って簡単に「後回し」するやり方'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-1949756700654506823</id><published>2011-07-11T00:03:00.002+09:00</published><updated>2012-01-04T21:52:31.269+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>JMockit と Swing と無名クラス</title><content type='html'>JMockit を使った Swing の UnitTest を考えてみる。今日はとりあえず、最初の一歩。&lt;br /&gt;&lt;span style="smaller"&gt;参考資料はこれ → &lt;a href="http://jmockit.googlecode.com/svn/trunk/www/tutorial/BehaviorBasedTesting.html"&gt;Behavior-based testing with JMockit&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;まずこんなコードから始めてみる。Swing に限らず、GUI フレークワークの入門書の最初に出てくるような、何もないウィンドウを単に開いてみるだけのもの。&lt;pre class="prettyprint"&gt;public class Exercise1 {&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;     JFrame frame = new JFrame();&lt;br /&gt;     frame.setSize(500, 300);&lt;br /&gt;     frame.setVisible(true);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;要するに 500×300のウィンドウがビジブルになれば良い訳で、以下のようなテストコードになる。&lt;pre class="prettyprint"&gt;public class Exercise1Test {&lt;br /&gt;  @Test public void main() {&lt;br /&gt;     new Expectations() {&lt;br /&gt;        @NonStrict JFrame frame; {&lt;br /&gt;        frame.setSize(500, 300);times=1;&lt;br /&gt;        frame.setVisible(true);times=1;&lt;br /&gt;     }};&lt;br /&gt;     Exercise1.main(new String[]{});&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;ここで、ウィンドウのクローズイベントに対応するアプリケーション終了処理が無い事に気づき、例えば、以下のように追加したとする。&lt;pre class="prettyprint"&gt;public static void main(String[] args) {&lt;br /&gt;  JFrame frame = new JFrame();&lt;br /&gt;  frame.addWindowListener(new WindowAdapter() {&lt;br /&gt;     @Override public void windowClosing(WindowEvent e) {&lt;br /&gt;        System.exit(0);&lt;br /&gt;     }&lt;br /&gt;  });&lt;br /&gt;  frame.setSize(500, 300);&lt;br /&gt;  frame.setVisible(true);&lt;br /&gt;}&lt;/pre&gt;この無名クラスを含むコードをどうやってテストするか。&lt;br /&gt;&lt;br /&gt;以下のような方針をとってみた。&lt;ul&gt;&lt;li&gt;System クラスをパーシャルモックして、exit(0) 呼び出しを expect する（変な日本語だが…）。&lt;/li&gt;&lt;li&gt;無名インナークラスについては、次のようにする。&lt;ul&gt;&lt;li&gt;addWindowListener に渡された、WindowListener を保持しておく。&lt;/li&gt;&lt;li&gt;main() 実行の後で、保持しておいた WindowListener のwindowClosing()を明示的に呼び出す。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;コードはこんな感じ。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class Exercise1Test2 {&lt;br /&gt;  @Mocked({"exit"}) System system;&lt;br /&gt; &lt;br /&gt;  static class WindowListenerCapturer implements Delegate {&lt;br /&gt;     WindowListener captured;&lt;br /&gt;     void addWindowListener(WindowListener l) {&lt;br /&gt;        captured = l;&lt;br /&gt;     };&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  @Test&lt;br /&gt;  public void main() {&lt;br /&gt;     final WindowListenerCapturer delegate = new WindowListenerCapturer();&lt;br /&gt;     new Expectations() {&lt;br /&gt;        @NonStrict JFrame frame; {&lt;br /&gt;        frame.addWindowListener((WindowListener)any); result = delegate;&lt;br /&gt;        frame.setSize(500, 300);times=1;&lt;br /&gt;        frame.setVisible(true);times=1;&lt;br /&gt;     }};&lt;br /&gt;     new Expectations() {{&lt;br /&gt;        System.exit(0);&lt;br /&gt;     }};&lt;br /&gt;     Exercise1.main(new String[]{});&lt;br /&gt;     delegate.captured.windowClosing(null);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;ここでは、実際の実行パスの流れと同じになるように、main() からの Expectation と、windowClosing() からの Expectation を分けて書いてみた。&lt;br /&gt;&lt;br /&gt;WindowListenerCapturer を使わないで、result = new Delegate() { ... }として、「...」のところで、windowClosing() を呼ぶやり方も試してみたが、何故か Eclipse プラグインがテスト終了を認識しない。&lt;br /&gt;&lt;br /&gt;まあ上で示したコードでも、キャプチャのためのコードが若干増えることになるとはいえ、実行時の流れを表していると言う点では、却って分かりやすいような気もする。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-1949756700654506823?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/1949756700654506823/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/07/jmockit-swing.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1949756700654506823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1949756700654506823'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/07/jmockit-swing.html' title='JMockit と Swing と無名クラス'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6492473379411914619</id><published>2011-07-07T00:44:00.002+09:00</published><updated>2011-07-07T00:49:24.769+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Effective Java から例外関連項目</title><content type='html'>以下、『&lt;a href="http://amazon.co.jp/o/ASIN/0321356683/yasuabe1984-22/ref=nosim"&gt;Effective Java (2nd Edition)&lt;/a&gt;』 から、9章「例外」に関係する項目。&lt;br /&gt;&lt;br /&gt;&lt;div style="font-size:smaller;"&gt;&lt;span style="color:green;"&gt;緑&lt;/span&gt;：推奨  &lt;span style="color:yellow;"&gt;黄&lt;/span&gt;：注意  &lt;span style="color:red;"&gt;赤&lt;/span&gt;：禁止&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 57&lt;/span&gt;: Use exceptions only for exceptional conditions&lt;/span&gt;&lt;br /&gt;ループとかに使うなという基本中の基本。パフォーマンスにも悪影響あり。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 58&lt;/span&gt;: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors&lt;/span&gt;&lt;br /&gt;まあ一応、教科書的な原則としてはこんな感じだろう。ただチェック例外の是非については、結構物議を醸す。そもそも、こんなの必要なのかと。Spring なんかも RuntimeException 派だし、C＃や C++ でチェック例外が無いからといって困った事も全然ない。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 59&lt;/span&gt;: Avoid unnecessary use of checked exceptions&lt;/span&gt;&lt;br /&gt;むやみにチェック例外を使うなと。例えば、「とりあえず呼んでみて例外が上がったらハンドリングする」なんてやり方より、「呼ぶ前にまずチェックする」やり方の方が、よりインテンショナルなコードになる場合がある。そんなメソッドのシグネーチャに例外を含めたって、誰の得にもならず負担が増えるだけ。&lt;br /&gt;&lt;br /&gt;しかしここでも、いっそチェック例外なんて止めりゃいいじゃんなんて思いが、やはり沸いてきたりする…&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:green;"&gt;Item 60&lt;/span&gt;: Favor the use of standard exceptions&lt;/span&gt;&lt;br /&gt;例外に限らず全ての Java 標準APIに言えるけど、よく調べ、よく理解して、使い倒していくと、いろんな意味で効率的。低リスクで高い生産性が得られる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 61&lt;/span&gt;: Throw exceptions appropriate to the abstraction&lt;/span&gt;&lt;br /&gt;よくAPI なんかについて、低レベルとか高レベルとか言うけど、例外についてもレベルに合わせて使い分けよう、必要なら変換もしようという話。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:green;"&gt;Item 62&lt;/span&gt;: Document all exceptions thrown by each method&lt;/span&gt;&lt;br /&gt;メソッドのドキュメントで、例外の説明をちゃんとしとけと。特に、RuntimeException だけで押し通す方針を選択した場合、チェック例外の面倒くささから解放される分、このドキュメント化だけはちゃんとしないと単なる手抜きになる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:green;"&gt;Item 63&lt;/span&gt;: Include failure-capture information in detail messages&lt;/span&gt;&lt;br /&gt;せっかく例外投げるんだから、ちゃんと原因究明の手がかりも含めようという、まっとうな話。まあ、面倒くさいし省かれがちだけど、これが正論。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 64&lt;/span&gt;: Strive for failure atomicity&lt;/span&gt;&lt;br /&gt;例外送出による実行中断のおかげで、システムの状態が中途半端になったりしないように、例外発生時には呼び出し前の状態を復元しようという項目。&lt;br /&gt;&lt;br /&gt;こういうのを考えると、注意喚起力が強いチェック例外って、やっぱアリかなあなんて思えてくる。少なくともドキュメントには、やはり可能性のある例外を列挙しておきたい。まあキャッチしたとしても、状態の復元はいつも簡単には行かないだろうけど。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 65&lt;/span&gt;: Don't ignore exceptions&lt;/span&gt;&lt;br /&gt;これについては、&lt;a href="http://yasutech.blogspot.com/2011/02/donotcatchgeneralexceptiontypes.html"&gt;前に書いた&lt;/a&gt;。驚くべき事に、例外を基底クラスでキャッチしてモミ消した挙句、鼻高々という面白い人種が、業界の底辺には多数棲息しているが、これらのおバカさん達についてもレポートした。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6492473379411914619?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6492473379411914619/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/07/effective-java.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6492473379411914619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6492473379411914619'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/07/effective-java.html' title='Effective Java から例外関連項目'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-5100670313886710045</id><published>2011-07-04T01:28:00.007+09:00</published><updated>2012-01-04T21:57:08.464+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>JMockit</title><content type='html'>&lt;a href="http://yasutech.blogspot.com/2011/06/java-static-mocking.html"&gt;数日前のポスト&lt;/a&gt;で、この２・３年に普及してきた、Java の Mocking / Isolation フレームワークに触れた。今日は、そのうちの一つ JMockit を使って、以下のお題について解を考えてみる。&lt;br /&gt;&lt;br /&gt;&lt;div style ="border:1px dashed orange;padding:3px 6px 3px 6px;"&gt;クラス TestTarget があり、Collaborator オブジェクトへの関連と、メソッド methodA() を持っている。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class TestTarget {&lt;br /&gt;   private final Collaborator collaborator = new Collaborator();&lt;br /&gt;   public String methodA(String pattern) {&lt;br /&gt;      int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);&lt;br /&gt;      return String.format(pattern, collaborator.methodB(hour));&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;methodA() では、Collaborator オブジェクトのメソッド methodB() を呼んでいるが、methodB() の振る舞いについて分かっている事は、24時間制の「時」を表す整数を与えると、その時刻を表す単語（"morning"や"夕方"など）を返すと言う事だけである。&lt;br /&gt;&lt;br /&gt;さて、ここで methodA() における、Collaborator オブジェクトとの協調を含む、TestTarget の振る舞いをテストするコードはどのようなものになるか。&lt;/div&gt;&lt;br /&gt;見ての通り、methodA() の振る舞いは、&lt;ol&gt;&lt;li&gt;Calendar から現在時刻の「時」の部分を取得し&lt;/li&gt;&lt;li&gt;これを Collaborator.methodB に渡して戻り値を受け取り&lt;/li&gt;&lt;li&gt;更にこれを書式化して返すというものになる。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;テスティングポイントは以下のようになる。&lt;ol&gt;&lt;li&gt;Calendar から、正しく「時」を取得している事&lt;/li&gt;&lt;li&gt;collaborator に渡された「時」が、上記1で取得したものである事&lt;/li&gt;&lt;li&gt;collaborator から返された文字列を正しく用いて、メソッドの戻り値を作っている事&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;また、以下のような事に留意する必要がある。&lt;ul&gt;&lt;li&gt;&lt;span style="text-decoration : underline;"&gt;Collaborator.methodB() の現時点の挙動には依存しない事。&lt;/span&gt;&lt;br /&gt;時間の区切りがどうなっているか、言語が何であるかなどは、今後変わる可能性があるが、TestTarget クラスの責任範囲外である。&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration : underline;"&gt;Collaborator.methodB() の実コードを呼ばない事。&lt;/span&gt;&lt;br /&gt;Collaborator は外部サービスが起動している事に依存していて、実行時間も無視できない。また TestTarget のテストで Collaborator コードまで呼ばれてしまうと、コード・カバレッジが実際を正しく反映しなくなると言う問題もある。&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration : underline;"&gt;このテストをどの時間帯に実行しても結果が変わらない事。&lt;br /&gt;&lt;/span&gt;つまり、Calendar が返す時刻に依存してはいけない。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;この UnitTest を、従来の dynamic proxy ベースの ツール（jmock など）を使ったり、ましてや状態ベースの普通の JUnitテストで書こうとすると、難しいテストコーディングになったと思う。&lt;br /&gt;&lt;br /&gt;JMockit を使うと以下のような感じになる。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class TestTargetTest {&lt;br /&gt;   @NonStrict Collaborator collaborator;&lt;br /&gt;   @Mocked({"getInstance", "get(int)"}) Calendar mockCalendar;&lt;br /&gt;   @Test public void methodA() {&lt;br /&gt;      final int HOUR = 7; &lt;br /&gt;      new Expectations() {{&lt;br /&gt;         collaborator.methodB(HOUR); result = "morning";&lt;br /&gt;         Calendar.getInstance(); result = mockCalendar;&lt;br /&gt;         mockCalendar.get(Calendar.HOUR_OF_DAY); result = HOUR;&lt;br /&gt;      }};&lt;br /&gt;      String actual = new TestTarget().methodA("good %s!");&lt;br /&gt;      Assert.assertEquals("good morning", actual);&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;コードの意味は以下のようなもの&lt;ul&gt;&lt;li&gt;Calendar.getInstance() が モックの Calendar を返すように、getInstance() コードを差し替えた&lt;/li&gt;&lt;li&gt;Calendar のモックは、今、何時なのか尋ねられる事を期待し、またその際、固定値7 を返すよう記述した。&lt;/li&gt;&lt;li&gt;Collaborator のモックが、固定値7 で methodB()が呼ばれることを期待し、その際、固定値"morning"を返すよう記述した&lt;/li&gt;&lt;li&gt;上記設定で、TestTarget.methodA()に"good %s!"が与えられ、"good morning"が得られる事を検証するよう記述した。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;一度グリーンにしてから、いろいろコードを変えてみて期待通りにレッドになることを観察してみた。&lt;br /&gt;&lt;br /&gt;せいぜい jmock の延長くらいかと思っていたら、使用感はかなり異なっていて、若干戸惑う。ただし、状態変化ベースだけではなく、相互作用ベースの UnitTest まで理解していれば、それほど高いハードルではない。DynamicProxy 系のテストを書いていていろいろ悩んだり困った経験のある人ほど、理解が早いと思う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-5100670313886710045?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/5100670313886710045/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/07/jmockit_04.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5100670313886710045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5100670313886710045'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/07/jmockit_04.html' title='JMockit'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-4401796125196922823</id><published>2011-06-30T02:04:00.006+09:00</published><updated>2011-07-03T23:01:23.842+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>技術者と英語：「読める」だけで嬉しい三つの事</title><content type='html'>TOEIC 800点前後というと、レベルBに当たる。&lt;br /&gt;&lt;br /&gt;TOEIC が提示している&lt;a href="http://www.toeic.or.jp/toeic/pdf/data/proficiency.pdf"&gt;相関表&lt;/a&gt;の説明によると、「どんな状況でも適切なコミュニケーションができる素地を備えている」、「日常会話は完全理解」、「業務上も支障なし」とされている。&lt;br /&gt;&lt;br /&gt;なんて言っても、実は「話す」「書く」が未経験でも「聴く」「読む」がソコソコできれば、割と取れる点数だったりする。自分もだいぶ前に 800を越えたが、恥ずかしながら全然喋った事なんかない。&lt;br /&gt;&lt;br /&gt;つうか話す相手も機会も今のところ一切無いし、従って興味も沸かず努力のしようもないんだけど、ソフトウェア開発技術者としては、「読める」だけで結構役に立つ事がある。&lt;br /&gt;&lt;br /&gt;以下の３つ。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;◆ 英語でググれる&lt;/span&gt;&lt;br /&gt;言うまでもなくインターネットは日本語情報より英語情報の方が圧倒的に多いし、技術情報は特に英語圏発のものが時間的にも先行している事が多い。&lt;br /&gt;&lt;br /&gt;英語が読めると、&lt;a href="http://www.google.co.jp/preferences?"&gt;Google の search settings&lt;/a&gt; で、English を設定しておいても別に問題ないから、情報量の少ない日本語サイトを避けて効率的に検索できる。&lt;br /&gt;&lt;br /&gt;技術系BBSでのディスカッションやトラブルシューティングでも、海外の方が盛んで検索にもヒットしやすい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;◆ 技術系の洋書が読める&lt;/span&gt;&lt;br /&gt;最近は、少しだけ改善したようだけど、一昔前の邦訳書は、かなり読みにくいものが多かった。APIリファレンス的なものはまだマシな方だけど、ちょっとユーモアを交えた語り口になったり、思想的に難解な話になったりすると、途端に日本語がおかしくなる。&lt;br /&gt;&lt;br /&gt;邦訳書の日本語に対する文句は至る所で聞くけど、最初から原書にしておけば、無駄なイライラをせずにすむ。つうか、無駄な変換レイヤーが無いという点で情報処理の視点からもある意味合理的なわけで、技術者ならなおさら原書を選択すべき。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;◆ ソースコードが英語に見えてくる&lt;/span&gt;&lt;br /&gt;意外と意識されていない事が多いが、ほとんどの高級プログラミング言語は英語ベースだったりする。&lt;br /&gt;&lt;br /&gt;まず単語の面で、言語のキーワードにおいても、各種 API の識別子においても、そのほとんどは英語の語彙、つまり何百年も前からアングロサクソンが日常のコミュニケーションの中で使ってきた言葉で構成されている。&lt;br /&gt;&lt;br /&gt;また文法の面でも、意識的にか無意識的にか知らないけど、メソッド呼び出しの文が、「subject.verb(object)」みたいな感じで、だいたい英語の語順に従うようになっていたりする。&lt;br /&gt;&lt;br /&gt;なので、上手に書いたプログラムは自然言語としての英語に近くなり、下手なコメントやダイアグラムなんかよりも、書き手の意図を読者に、より効率的、より直截に伝える高い表現力を持つ事ができる。&lt;br /&gt;&lt;br /&gt;英語が「読める」ようになるだけでも、人間同士が意思疎通するコトバという観点から見たプログラムの良し悪しがより分かるようになり、ソースの読み書き両面に良い効用が出てくる。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;div style="font-size:smaller;"&gt;ちなみに、逆に英語が全然読めない人の場合、英文としての表現力さえ備えるに至った良質なコードを前にしても、解読を要する意味不明な記号の羅列か、もしかすると ASCII アート的な図形にしか見えていないのでは、と疑わしくなる場面がよくある。&lt;br /&gt;&lt;br /&gt;こういう人達って、「ソースを読む」ではなく「ソースを解析する」という言い回しを好む。「ソースが言葉である」なんて事は脳内ですら成立したためしがないから、「読める」コードなんか自分でも書ける訳もなく、必然的に無駄なコメントだらけの残念なコードを書いてしまうことになる。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-4401796125196922823?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/4401796125196922823/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_30.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4401796125196922823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4401796125196922823'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_30.html' title='技術者と英語：「読める」だけで嬉しい三つの事'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-33674557136671297</id><published>2011-06-27T23:36:00.002+09:00</published><updated>2012-01-04T21:57:24.809+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>java の static メソッドの mocking</title><content type='html'>しばらく .net 案件とかやってた間に、いつの間にか Java でもstatic メソッドに mocking が適用できるようになっていたらしい。&lt;br /&gt;&lt;br /&gt;ググってみると、今のところ &lt;a href="http://code.google.com/p/powermock/"&gt;PowerMock&lt;/a&gt; と &lt;a href="http://code.google.com/p/jmockit/"&gt;JMockit&lt;/a&gt; が、どうやら使えそうな感じ。&lt;br /&gt;&lt;br /&gt;前に Java をやっていた頃、mocking には jMock（いわゆる「流れるようなインターフェイス」が何とも素敵な奴だったのだが）を使っていたが、この jMock の制約のせいで java では static メソッドは迂回もすり替えもできないと諦めていた(&lt;code&gt;final&lt;/code&gt; 外しはあったが)。&lt;br /&gt;&lt;br /&gt;考えてみれば、.net の Mole も TypeMock も instrumentation を使っていたわけだけど、Java だって 5.0 からは instrumentation があったんだから、とっくにできていて不思議はなかった。&lt;br /&gt;&lt;br /&gt;しかし、どっちを使えば良いか悩む。&lt;br /&gt;&lt;br /&gt;つうか、昔と同じく jMock を使うという選択肢も捨てきれないから、3択になる。いや、PowerMock は EasyMock か Mockito と組み合わせるからもっと選択肢が増える（jMock との組み合わせもできないことないらしいが、ちょっと不安）。&lt;br /&gt;&lt;br /&gt;カバレッジツールとの相性とか、微妙な使い勝手の優劣とかもあるだろうし、急いで決めねばならない状況ではあるんだけど、拙速な決断は危ない。&lt;br /&gt;&lt;br /&gt;うーん、もっと早く気づいていればなあ…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-33674557136671297?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/33674557136671297/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/java-static-mocking.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/33674557136671297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/33674557136671297'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/java-static-mocking.html' title='java の static メソッドの mocking'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2704874719827591014</id><published>2011-06-24T04:29:00.003+09:00</published><updated>2011-11-03T21:51:18.706+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開発インフラ'/><title type='text'>Fedora 15/Jenkins/Maven3/Subversion/Helios</title><content type='html'>&lt;p&gt;空きマシンに入れていた Fedora 12を Fedora 15 Lovelock に入れ替えて、自宅環境の筆頭開発マシンに昇格させ、ついでにその他開発ツールもセッティングした。その作業の超ザックリメモ。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Helios:&lt;/span&gt;Fedora の「ソフトウェアの追加と削除」から GUIでインストール。Fedora 12の時は Galileo だったが、Fedora 15 では Helios (Eclipse 3.6)になっていた。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Maven 3:&lt;/span&gt;&lt;a href="http://maven.apache.org/download.html"&gt;apache のダウンロードサイト&lt;/a&gt;からバイナリを落としてきて適当に展開。README.txtを見ながら適当に設定、"mvn --version" で 3.0.3 が入ったことを確認。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Subversion:&lt;/span&gt;これも「ソフトウェアの追加と削除」でインストール。バージョン 1.6.16 が入ってきた。"svnadmin create" で適当にリポジトリを作っておく。差し当たり file://でアクセスするだけなので、これ以上の設定は保留。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;m2eclipse:&lt;/span&gt;Helios の「新規ソフトウェアのインストール...」で、更新サイトに[&lt;a href="http://m2eclipse.sonatype.org/sites/m2e"&gt;このURL&lt;/a&gt;]を指定してインストール。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Subclipse:&lt;/span&gt;Helios の「新規ソフトウェアのインストール...」で、更新サイトに[&lt;a href="http://subclipse.tigris.org/update_1.6.x"&gt;このURL&lt;/a&gt;]を指定して、Subclipse, Client Adapter, JavaHLを選択してインストール。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Jenkins:&lt;/span&gt; [&lt;a href="http://pkg.jenkins-ci.org/redhat/"&gt;ここ&lt;/a&gt;]を見てインストール。"sudo /etc/init.d/jenkins start"で起動し、ブラウザで localhost:8080 を開いて確認。で、とりあえず stop しておく。&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;テスト用プロジェクト作成:&lt;/span&gt;&lt;ul&gt;&lt;li&gt;Helios に戻る。&lt;/li&gt;&lt;li&gt;maven-archetype-quickstart を指定して新規 Maven Projectを作成。&lt;/li&gt;&lt;li&gt;pom.xml で JUnit のバージョンを4.8.2に変更して、依存性を更新。&lt;/li&gt;&lt;li&gt;App.java を書き換える&lt;pre class="prettyprint"&gt;public class App {&lt;br /&gt;    public String getMessage() {&lt;br /&gt;        return "Hello World!";&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;AppTestを書き換える&lt;pre class="prettyprint"&gt;public class AppTest {&lt;br /&gt;   @Test&lt;br /&gt;      public void testGetMessage() {&lt;br /&gt;      String message = new App().getMessage();&lt;br /&gt;      Assert.assertEquals("Good-Bye World!", message);&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Maven package を実行して、テストでビルドが失敗するのを確認。&lt;/li&gt;&lt;li&gt;上で作ったリポジトリを指定して"プロジェクトの共用"を実行し、適当にファイルを選んでバージョン管理に追加して、敢えてテスト失敗版をコミット。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Jenkins に Jobを追加:&lt;/span&gt;&lt;ul&gt;&lt;li&gt;"java -jar /usr/lib/jenkins/jenkins.war"で起動する。(init.d/jenkins startだと、file:// で SVNリポジトリにアクセスできなかったので、とりあえず war を直接起動。)&lt;/li&gt;&lt;li&gt;ブラウザから開いて、[Manage Jenkins]/[Configure System] から、右のように Maven の設定 → Install Automatically をアンチェックして、上でインストールした Maven のパスをMAVEN_HOMEに指定。&lt;/li&gt;&lt;li&gt;Jenkins の[New Job] で [Build a maven2/3 project] を選択。"Source Code Management" で Subversion を選択し、上で作ったリポジトリを指定。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Build 確認:&lt;/span&gt;&lt;ul&gt;&lt;li&gt;[Build Now] を実行し、テストでビルドが失敗している事を確認。&lt;/li&gt;&lt;li&gt;Helios に戻ってテスト・メソッドの"Good-Bye"をHelloに変えて、SVNコミット。&lt;/li&gt;&lt;li&gt;再び[Build Now] でビルド。今度はテストを含むビルドが成功している事を確認。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight:bold;"&gt;TODO&lt;/span&gt;&lt;ul&gt;&lt;li&gt;svn+ssh でのリポジトリアクセス&lt;/li&gt;&lt;li&gt;サービス化&lt;/li&gt;&lt;li&gt;Trac の導入とSVNとの連携&lt;/li&gt;&lt;li&gt;SVNコミットをトリガーとする自動ビルド&lt;/li&gt;&lt;li&gt;FishEye導入&lt;/li&gt;&lt;li&gt;Emma 導入&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2704874719827591014?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2704874719827591014/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/fedora-15jenkinsmaven3subversionhelios.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2704874719827591014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2704874719827591014'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/fedora-15jenkinsmaven3subversionhelios.html' title='Fedora 15/Jenkins/Maven3/Subversion/Helios'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2326193731877058906</id><published>2011-06-21T15:49:00.004+09:00</published><updated>2011-07-02T00:25:07.439+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>アジャイルの資格</title><content type='html'>アジャイル関連の資格について調べてみた。&lt;br /&gt;&lt;br /&gt;アジャイルと認定資格って、なんとなく相容れないイメージで、開発者の間でも物議を醸しているらしいが、最近は結構、動きが活発になってきている。&lt;br /&gt;&lt;br /&gt;まあ他の資格と同じで、保有しているからといって実務能力があるって事にはならないだろうが、少なくとも会話が成立するレベルの語彙を持っている事の表明くらいにはなると思う。もちろん実践で成功している人なら、我流に偏らないお墨付きの正統な知識も持っているという事になり、鬼に金棒で言う事が無い。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;span style="font-size:larger;color:white;"&gt;◆ Scrum Alliance: 認定スクラムマスタ 等&lt;/span&gt;&lt;br /&gt;すでに日本でも取得者が増え始めている、&lt;a href="http://www.scrumalliance.org/pages/scrum_certification"&gt;Scrum Alliance&lt;/a&gt; の認定資格。&lt;br /&gt;&lt;br /&gt;トレーニングコースに参加する必要があり、日本開催時の受講体験記をネットでも散見する。ただ、これが結構高い。ざっと検索したところ、同時通訳付きで20万、通訳なしで15万といったところか。会社の金ではなく個人で受けるとすると、ちょっとした決断が必要になる。&lt;br /&gt;&lt;br /&gt;なんか昔のイメージだと、お金を払って2日間の講習に座ってるだけで取れるって感じだったけど、調べてみると、今は一応、インターネット経由の試験で知識を証明する必要があるらしい。&lt;br /&gt;&lt;br /&gt;ちなみに Master 以外には、ProductOwner, Developer, Professional, Trainer, Coach といったものがある。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;color:white;"&gt;◆ Scrum.org:  Professional Scrum Master 等&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.scrum.org/assessments/"&gt;URLはここ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Professional Scrum Master I (Fundamental) :&lt;/span&gt;&lt;br /&gt;トレーニング・コースも提供されているが必須ではなく、自信があればいきなりネット試験を受験してもよく、そこで 85%とれば合格らしい。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Professional Scrum Master II (Intermediate):&lt;/span&gt;&lt;br /&gt;これもネット試験だが、小論文もあるらしい。費用もやや高額。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Professional Scrum Developer:&lt;/span&gt;&lt;br /&gt;これはコース受講と試験の両方が要るらしいが、ただトレーニング・コースの方は欧米中心の開催。アジアでは今のところインドだけっぽい。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Professional Scrum Product Owner:&lt;/span&gt;&lt;br /&gt;これもコース受講とネット試験。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;color:white;"&gt;◆ PMI: PMI-Agile Certified Practitioner&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;先月、Pilot Programが始まったばかりの &lt;a href="http://www.pmi.org/Certification/New-PMI-Agile-Certification/PMI-Agile-Certification-Pilot-Program.aspx&lt;br /&gt;"&gt;PMIのアジャイル認定試験&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;以前、PMP の勉強をしていたとき、使っていた問題集でも参考書でも、道路の延伸工事プロジェクトだとか、小売業の店舗拡大プロジェクトだとか、予想外にソフトウェア開発と離れた設問ばかりで、PMBOKってそう言うものだったのかと、ちょっと驚いた。&lt;br /&gt;&lt;br /&gt;でも、同じ PMI の資格でも、PMI-Agile のFAQを見ると、馴染みのあるアジャイル開発の用語ばかりで、ソフトウェア開発者としてちょっとテンションが上がってくる。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;color:white;"&gt;◆ ICAgile: &lt;/span&gt;&lt;br /&gt;ユースケースで有名なコーバーンとかが創立した&lt;a href="http://www.icagile.com/"&gt;、ICAgile &lt;/a&gt;なる組織でも、認定試験を提供する計画らしい。&lt;br /&gt;&lt;br /&gt;組織自体が発足したてで、試験などはまだまだ形になっていないようだけど、&lt;a href="http://www.infoq.com/jp/news/2010/08/agile-cert"&gt;この記事&lt;/a&gt;を読む限り、結構おもしろそうではある。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2326193731877058906?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2326193731877058906/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_21.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2326193731877058906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2326193731877058906'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_21.html' title='アジャイルの資格'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6772144490294191231</id><published>2011-06-21T02:58:00.004+09:00</published><updated>2011-11-03T16:59:41.638+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Java のスレッドプール</title><content type='html'>&lt;p&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0321485890/yasuabe1984-22/ref=nosim"&gt;More Effective C#&lt;/a&gt;』の item 11 に、"&lt;span style="color:white;"&gt;Use the Thread Pool Instead of Creating Threads&lt;/span&gt;"というのがある。new で スレッドを生成するのではなく、.Net で提供されるプールを使えと。&lt;/p&gt;&lt;p&gt;で、昨日『&lt;a href="http://amazon.co.jp/o/ASIN/0321356683/yasuabe1984-22/ref=nosim"&gt;Effective Java (2nd edition)&lt;/a&gt;』を調べていると、item 68 で、ThreadPoolExecutor が紹介されていたので、ちょっと試してみた。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;以下のような状況を想定する。&lt;ul&gt;&lt;li&gt;クライアントが Socket をつなぐと、サーバは ServerSocket で accept()して、1から10までの整数乱数を 1000個返す。&lt;/li&gt;&lt;li&gt;クライアントはその整数を一つずつ読み取り、幾ばくかの処理時間を要する何らかの処理を行う。ここでは、読み込んだ整数をミリ秒の時間間隔と捉えて、その分だけ sleep() させるようなコードを書く事にした。&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;クライアントは以下のようなコード。&lt;pre class="prettyprint"&gt;public class Receiver {&lt;br /&gt;&lt;br /&gt;   private static final short LISTEN_PORT = 3434;&lt;br /&gt;   private static final int CORE＿SIZE = 1;&lt;br /&gt;   private static final int MAX_SIZE = 100;&lt;br /&gt;   private static final int KEEP_ALIVE = 10;&lt;br /&gt;&lt;br /&gt;   private static final ExecutorService pool = &lt;br /&gt;      new ThreadPoolExecutor(&lt;br /&gt;         CORE＿SIZE, MAX_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, &lt;br /&gt;         new LinkedBlockingQueue&lt;Runnable&gt;());&lt;br /&gt;&lt;br /&gt;   public static void main(String[] args) throws IOException {&lt;br /&gt;      Socket socket = new Socket("localhost", LISTEN_PORT);&lt;br /&gt;      DataInputStream in = new DataInputStream(socket.getInputStream());&lt;br /&gt;&lt;br /&gt;      long start = System.nanoTime();&lt;br /&gt;      for (int i = 0; i &lt; 1000; ++i) test(in.readInt());&lt;br /&gt;      System.out.println((System.nanoTime() - start) / 1000000000.0);&lt;br /&gt;&lt;br /&gt;      in.close();&lt;br /&gt;      socket.close();&lt;br /&gt;  &lt;br /&gt;      pool.shutdown();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static void executeTimeConsumingProcess(int interval) {&lt;br /&gt;      try {&lt;br /&gt;         TimeUnit.MILLISECONDS.sleep(interval);&lt;br /&gt;      } catch (Exception e) {}&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static void test(int interval) throws IOException {&lt;br /&gt;       //ここを書き換えて比較する&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;で、この test() メソッドの中身を変えて、①逐次実行（並列なし）、②スレッドを生成する方式、③スレッドプールを使う方式で比較してみる。（サーバー側は、DataOutputStream で整数を返すようなコードになるが、ほぼ自明なので省略。）&lt;/p&gt;&lt;p&gt;① まず、並列処理をしない逐次実行のパターン&lt;pre class="prettyprint"&gt;private static void test(int interval) throws IOException {&lt;br /&gt;   executeTimeConsumingProcess(interval);&lt;br /&gt;}&lt;/pre&gt;実行時間は、約 5.6秒と出た。平均 5ms の処理が1000回なので、だいたい想定どおりの結果。&lt;/p&gt;&lt;p&gt;② 次に、スレッドを生成するパターン。&lt;pre class="prettyprint"&gt;private static void test(final int interval) throws IOException {&lt;br /&gt;   new Thread(new Runnable() {&lt;br /&gt;      @Override public void run() {&lt;br /&gt;         executeTimeConsumingProcess(interval);  &lt;br /&gt;      }&lt;br /&gt;   }).start();&lt;br /&gt;}&lt;/pre&gt;これは約 0.14秒と出た。当然ながら、逐次実行よりは大幅に速い。&lt;/p&gt;&lt;p&gt;③ 最後に、スレッドプールを使うパターン。&lt;pre class="prettyprint"&gt;private static void test(final int interval) throws IOException {&lt;br /&gt;   pool.execute(new Runnable() {&lt;br /&gt;      @Override public void run() {&lt;br /&gt;         executeTimeConsumingProcess(interval);&lt;br /&gt;      }&lt;br /&gt;   });&lt;br /&gt;}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;結果は約 0.028秒で、スレッド生成の5倍のスピードが得られた。やっぱり、それなりにパフォーマンスは良いらしい。&lt;/p&gt;&lt;p&gt;====&lt;/p&gt;&lt;p&gt;プールの初期サイズ、最大サイズなどを調整すると、若干値が変わってくる。実務で使うときは、実行環境に応じて調整できるような仕組みを作っておくと良いかもしれない。&lt;/p&gt;&lt;p&gt;ThreadPoolExecutor よりさらに手軽に使えるスレッドプールが、Executors の newCashedThreadPool() や newFixedThreadPool() などのメソッドで得られるが、一応試してみたところ、ThreadPoolExecutor を直に使うより、若干遅かった（倍くらいの所要時間）。もちろん、簡易な分、調整は利かない。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6772144490294191231?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6772144490294191231/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/java.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6772144490294191231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6772144490294191231'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/java.html' title='Java のスレッドプール'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8811041647063049941</id><published>2011-06-20T10:36:00.004+09:00</published><updated>2011-07-02T00:32:42.192+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Effective Java からperformance 関連項目</title><content type='html'>以下、『&lt;a href="http://amazon.co.jp/o/ASIN/0321356683/yasuabe1984-22/ref=nosim"&gt;Effective Java (2nd Edition)&lt;/a&gt;』 から、パフォーマンスに関係する項目。&lt;br /&gt;&lt;br /&gt;&lt;div style="font-size:smaller;"&gt;&lt;span style="color:red;"&gt;赤&lt;/span&gt;：パフォーマンスに特に関係する項目&lt;br /&gt;&lt;span style="color:orange;"&gt;橙&lt;/span&gt;：パフォーマンスに割と関係する項目&lt;br /&gt;&lt;span style="color:yellow;"&gt;黄&lt;/span&gt;：パフォーマンスに一部だけ関係する項目&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 1&lt;/span&gt;: Consider static factory methods instead of constructors&lt;/span&gt;&lt;br /&gt;オブジェクトの生成が抑えられるという static factory methods の利点について、instance-controlled class というキーワードで記述されている。Flyweight パターン（GoF）的に活用するとパフォーマンス向上に効果あり。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 5&lt;/span&gt;: Avoid creating unnecessary objects&lt;/span&gt;&lt;br /&gt;「immutable なオブジェクトは常に再利用しよう」とか、「boxing / unboxing による暗黙のオブジェクト生成に気をつけよう」などといった注意喚起。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 6&lt;/span&gt;: Eliminate obsolete object references&lt;/span&gt;&lt;br /&gt;メモリリーク対策として紹介されているが、オブジェクトへの参照を常に null out することは、無駄に内部品質（すなわちコーディングの生産性）を損なうバッド・プラクティスとされている。null 代入するなら、メモリリークを起こし易い場所に見当を付けて集中的に行うべき。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 7&lt;/span&gt;: Avoid finalizers&lt;/span&gt;&lt;br /&gt;デストラクタ感覚で使うのは止めましょうという話だが、往々にして期待通りに動かないし、そもそも必要性からして疑わしい。さらに深刻なパフォーマンス劣化さえもたらしうるとの記述がある。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 9&lt;/span&gt;: Always override hashCode() when you override equals&lt;/span&gt;&lt;br /&gt;極端な例だが、hashCode()で定数を返したりなんかすると、リニアなアクセス時間になって、本来 のHashXXX の パフォーマンスが得られないって話。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 15&lt;/span&gt;: Minimize mutability&lt;/span&gt;&lt;br /&gt;クラスを定義する際には、できるだけ immutable にして行こうという、今ではかなり普及したプラクティス。パフォーマンスとの関連でいえば、無駄なオブジェクト生成を抑えられるという利点と、値が変わる度に新規インスタンスが必要になるという欠点の、両面があるので注意。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 48&lt;/span&gt;: Avoid float and double if exact answers are required&lt;/span&gt;&lt;br /&gt;業務アプリのプログラマには常識的な話。ただ、あるデータ項目について、どの程度正確な値が求められているか、必ずしも自明ではない。BigDecimal で精度をとるかプリミティブ型でパフォーマンスをとるか、やはり要件によりけり。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 49&lt;/span&gt;: Prefer primitive types to boxed primitives&lt;/span&gt;&lt;br /&gt;Integer や Long などを無自覚に使うと、暗黙の boxing / unboxing で深刻にパフォーマンスが落ちうると言う話。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 50&lt;/span&gt;: Avoid strings where other types are more appropriate&lt;/span&gt;&lt;br /&gt;特にパフォーマンスへの言及は無いが、普通に考えればわかるとおり、本来それ専用の型定義で表現されるべきデータ構造を、下手に文字列なんかで扱ったりすると、内部品質にもパフォーマンスにも悪影響がある。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 51&lt;/span&gt;: Beware the performance of string concatenation&lt;/span&gt;&lt;br /&gt;まあ常識。StringBuilder を使いましょうと。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 53&lt;/span&gt;: Prefer interfaces to reflection&lt;/span&gt;&lt;br /&gt;普通のメソッド呼び出しより reflection の方が遅いという普通の話。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 54&lt;/span&gt;: Use native methods judiciously&lt;/span&gt;&lt;br /&gt;昔と違って  JVM が大幅に速くなった今では、JNI経由の native メソッド使用は、期待するほど効果がないという話。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 55&lt;/span&gt;: Optimize judiciously&lt;/span&gt;&lt;br /&gt;「未熟な最適化は諸悪の根源」という Knuth の言葉など、今よりもメモリが小さくCPUが遅くてパフォーマンスが難問だった時代から受け継がれる先人の警句を引用して、やみくもなコード最適化／パフォーマンス・チューニングについて警告している。このブログでも書いてきた（&lt;a href="http://yasutech.blogspot.com/2011/06/codecomplete.html"&gt;これ&lt;/a&gt;とか&lt;a href="http://yasutech.blogspot.com/2011/06/blog-post_17.html"&gt;これ&lt;/a&gt;）。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 57&lt;/span&gt;: Use exceptions only for exceptional conditions&lt;/span&gt;&lt;br /&gt;Exception をループ境界の判定などの制御フローに使ったりするのは、本来の使い方から逸脱しているだけでなく、パフォーマンスにも悪影響がある。まあ、そこまでバカな事する人なんか見たことないけど。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 66&lt;/span&gt;: Synchronize access to shared mutable data&lt;/span&gt;&lt;br /&gt;「アトミックなデータならば、パフォーマンス向上のための同期コード省略が可能」という迷信を批判。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 67&lt;/span&gt;: Avoid excessive synchronization&lt;/span&gt;&lt;br /&gt;同期コードによる待ちが増えると、並行性の機会が奪われたりしてパフォーマンスが上がらないという普通の話。synchronize ブロックから alien method を呼ばないとか、synchronize ブロックを小さく留めるとかヒントが書かれているけど、まあ普通はそれほど簡単にいかないので、工夫のしどころではある。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 68&lt;/span&gt;: Prefer executors and tasks to threads&lt;/span&gt;&lt;br /&gt;スレッドプールが標準APIで提供されているので活用すべし。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:orange;"&gt;Item 69&lt;/span&gt;: Prefer concurrency utilities to wait and notify&lt;/span&gt;&lt;br /&gt;高パフォーマンスな concurrent collection の紹介など、java.util.concurrent パッケージ活用のすすめ。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:red;"&gt;Item 71&lt;/span&gt;: Use lazy initialization judiciously&lt;/span&gt;&lt;br /&gt;パフォーマンスに良かれと思って lazy initialization を書いても、大抵は逆効果だから止めておけと。どうしても必要なら、static field には lazy initialization class イディオム、instance field には double-check イディオムを使うこと。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;color:white;"&gt;&lt;span style="color:yellow;"&gt;Item 75&lt;/span&gt;: Consider using a custom serialized form&lt;/span&gt;&lt;br /&gt;デフォルトのシリアライズ形式は、ロジカルなデータ形式に着目したカスタムのシリアライズより、パフォーマンスが悪い事が多い。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8811041647063049941?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8811041647063049941/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/effective-java-performance.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8811041647063049941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8811041647063049941'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/effective-java-performance.html' title='Effective Java からperformance 関連項目'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8680002768754173053</id><published>2011-06-19T01:34:00.003+09:00</published><updated>2011-06-22T18:08:40.295+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><title type='text'>CodeComplete からパレートの法則など</title><content type='html'>『&lt;a href="http://amazon.co.jp/o/ASIN/4894712288/yasuabe1984-22/ref=nosim"&gt;リファクタリング&lt;/a&gt;』第2章 の「リファクタリングとパフォーマンス」を読んでいたら、Steve McConnell の『&lt;a href="http://amazon.co.jp/o/ASIN/4891004568/yasuabe1984-22/ref=nosim"&gt;Code Complete （下巻）&lt;/a&gt;』への参照があった。&lt;br /&gt;&lt;br /&gt;以下、「25章 コードチューニング戦略」から抜粋。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;パレートの法則：&lt;/span&gt;&lt;br /&gt;成果の&lt;span style="color:white;"&gt;80%&lt;/span&gt;は作業の&lt;span style="color:white;"&gt;20%&lt;/span&gt;から得られる&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Barry Boehm：&lt;/span&gt;&lt;br /&gt;&lt;span style="color:white;"&gt;20%&lt;/span&gt;のルーチンがプログラムの実行時間の&lt;span style="color:white;"&gt;80%&lt;/span&gt;を消費&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Donald Knuth：&lt;/span&gt;&lt;br /&gt;プログラムの&lt;span style="color:white;"&gt;4%未満&lt;/span&gt;がプログラムの実行時間の&lt;span style="color:white;"&gt;50%&lt;/span&gt;を占める&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jon Bentley：&lt;/span&gt;&lt;br /&gt;あるプログラムで、&lt;span style="color:white;"&gt;0.5%&lt;/span&gt;の行が実行時間の&lt;span style="color:white;"&gt;80%&lt;/span&gt;を占めていた&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Steve McConell：&lt;/span&gt;&lt;br /&gt;あるプログラムで、&lt;span style="color:white;"&gt;1%未満&lt;/span&gt;のコードが実行時間の&lt;span style="color:white;"&gt;90%&lt;/span&gt;を占めていた&lt;br /&gt;&lt;br /&gt;まあ、数字は異なるが言ってる意味は一緒で、要するにパフォーマンスに影響を及ぼしている部分はプログラム中のかなりちっちゃい部分だって事。まあ、アプリケーションのパフォーマンス改善の経験者には、割と常識かと。&lt;br /&gt;&lt;br /&gt;「25章 コードチューニング戦略」では、この他に「コードを書くそばから最適化すべきだ」という稚拙な戦略についても、バッサリ斬っている。これは以前の自分の&lt;a href="http://yasutech.blogspot.com/2011/06/blog-post_17.html"&gt;ポスト&lt;/a&gt;でも同じような事を書いた。&lt;br /&gt;&lt;br /&gt;また、チューニングを段階的に繰り返して効果を累積させる戦術を、さかんに奨励している。ただし当然ながら、それをやるには、それ相応の内部品質＝コード保守性が維持されていなければならない。例えば、パフォーマンスと引換えに内部品質が落ちるような箇所に関して、これを局所化するようなリファクタリングを併用しつつ、コードチューニングを積み重ねるというやり方が必要になると思われる。&lt;br /&gt;&lt;br /&gt;あと、コード・チューニングはパフォーマンス改善策の一部であって、実は、アーキテクチャやデータ構造によるパフォーマンスへの影響に比べたら意外と大したことない場合が多いとも言っている。当たり前のことだけど結構大事だと思う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8680002768754173053?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8680002768754173053/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/codecomplete.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8680002768754173053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8680002768754173053'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/codecomplete.html' title='CodeComplete からパレートの法則など'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3752213833902267946</id><published>2011-06-18T03:03:00.007+09:00</published><updated>2011-06-22T17:32:38.937+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><title type='text'>保守性とイマドキの開発</title><content type='html'>「ソースを綺麗にしてコードの&lt;span style="font-weight:bold;"&gt;保守性&lt;/span&gt;を高めよう」なんて事は誰もが言うし、「規約を作って静的チェックツールにかけよう」とか、「UnitTest を書いてリファクタリングも奨励しよう」なんて感じで話が進む事もあるけど、いざとなるとグズりだす怪しからんヤツらが実に多い。&lt;br /&gt;&lt;br /&gt;スケジュールがきついからとか、コスト面の制約で人が足りないからとか言うのが、お約束のエクスキューズなんだけど、うーん、だからこそなんだがなあ・・・&lt;br /&gt;&lt;br /&gt;で、ちょっとコードの保守性について、特に、それが大事なのは何故なのかという点を中心に考えてみる。&lt;br /&gt;&lt;br /&gt;＝＝＝＝&lt;br /&gt;実はまず、「保守性」ってネーミングが、そもそも良くなかったりする。語の使用の歴史的経緯から見ても、どうしても納品後の保守フェーズに係る品質要素という印象が拭えない。&lt;span style="font-size:smaller;"&gt;最も適切と思われる&lt;span style="color:white;"&gt;内部品質&lt;/span&gt;は意外と知られていないし、&lt;span style="color:white;"&gt;可読性&lt;/span&gt;だと読むだけみたいだし、「綺麗なソース」とか「健康なソース」では情緒的過ぎて説得力に欠ける。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ここで「保守性」を、開発者の素朴な観点から言い換えると、&lt;span style="font-weight:bold;"&gt;「保守作業の生産性」&lt;/span&gt;って事になる。&lt;span style="font-size:smaller;"&gt;ISO 9126の分類は、論点が違うのでここでは割愛&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;この生産性が低ければ、当該の保守作業にもその分だけ時間とお金が掛かったりするわけだけど、じゃあ、その保守作業とは何だっただろうか。&lt;br /&gt;&lt;br /&gt;再び開発者観点で素朴に考えると、「既存ソースを読んで意図と構造を理解し、追加・書き換え・削除等の編集を施す」、さらに短くは&lt;span style="font-weight:bold;"&gt;「ソースを読んで編集する」&lt;/span&gt;という、それだけの事だとわかる。&lt;br /&gt;&lt;br /&gt;で、これを踏まえて言い直すと、「保守作業の生産性」とは&lt;span style="font-weight:bold;"&gt;「ソースを読んで編集する作業の生産性」&lt;/span&gt;という事になる。…が、はて？こんなのは今時、保守フェーズに限定された作業なんかでは全然ない。&lt;br /&gt;&lt;br /&gt;極論すれば、6ヶ月の開発期間における最初の10分くらいから、「ソースを読んで編集する作業」は早くも発生し始めるし、反復型の開発なら第二イテレーション以降は大部分がその意味で「保守作業」になる。&lt;br /&gt;&lt;br /&gt;「動いてるコードはイジらない」的な昔の開発風景ならともかく、既存コードを編集しながら成長させる現代の開発では、「保守性」はプロジェクト全期間に渡る重大ファクターであり、開発初期から「実装生産性」そのものに漸近していく。&lt;br /&gt;&lt;br /&gt;なわけだから、正しくは「スケジュールがキツいし人も足りない」-&gt; 「ならば生産性を上げよう」-&gt; 「つまりソースを改善して保守性を上げよう」と考えなければならない。これの逆をやってるから、各反復で負のスパイラルを誘発し、ドツボにハマっていく。&lt;br /&gt;&lt;br /&gt;=＝＝＝&lt;br /&gt;というのが、コード保守性に関する不見識への、差し当たりの抗議。&lt;br /&gt;&lt;br /&gt;「そもそも保守性の高いコードとは何か」と、「保守性向上作業（リファクタ等）の工数はどうしてくれるんだ」という2つの事項についても説明が必要だが、別の機会にする。&lt;br /&gt;&lt;br /&gt;まあ現場では、こうして理詰めで説明しても、心理的・組織的圧力で生産性を考慮しないままなし崩しに開発が進んでいってしまう事は往々にしてあるんだよなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3752213833902267946?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3752213833902267946/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_18.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3752213833902267946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3752213833902267946'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_18.html' title='保守性とイマドキの開発'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7479951662375013300</id><published>2011-06-17T16:27:00.004+09:00</published><updated>2011-06-18T02:18:49.876+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><title type='text'>コード最適化の個人的三原則</title><content type='html'>最近、アプリケーションのパフォーマンス・チューニングやコード最適化ついて、自分の考えを開陳する機会が何度かあった。&lt;br /&gt;&lt;br /&gt;足し合わせて要約すると、以下のような感じになる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆コードを直す前後に計る&lt;/span&gt;&lt;br /&gt;コード最適化に当たっては、修正を加えるに先立って、まず現時点の速度やその他のパフォーマンス指標を計測し、プロファイラ等を用いてボトルネックを突き止める。しかる後に、該当コードをピンポイントで修正し、それから再度パフォーマンスを計り直し、修正前と比べて効果を確認する（効果が無ければ元に戻す）。&lt;br /&gt;&lt;br /&gt;…というのが、まあ、常識的な流れだが、実際の現場では意外とちゃんとできていない。&lt;br /&gt;&lt;br /&gt;場当たり的な思いつきのパフォーマンス改善策を、システム全体のソースコードにバラまいて内部品質を下げてしまい、パフォーマンスチューニング改善作業そのものを停滞させてしまう場面がかなりよくある（これはまた、別の機会に詳述したい）。&lt;br /&gt;&lt;br /&gt;カンに頼ったやみくもな対処は止めて、とにかく実測で把握する事がまずは必須。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆数値目標を立てる&lt;/span&gt;&lt;br /&gt;まあパフォーマンス向上というか、ほとんど何にでも一般的に当てはまる仕事の基本とも言える事だから、まあ、あまり説明がいらない気がする。&lt;br /&gt;&lt;br /&gt;ところが、実際の現場では「とにかく速く」なんてお題目の下で作業が行われる事が結構多い。&lt;br /&gt;&lt;br /&gt;こういうのは、要するに精神論・根性論みたいなものだから、そういったスローガンのもとでの作業は、無駄にプレッシャーが増加するだけで結局はあまりうまく行かない。&lt;br /&gt;&lt;br /&gt;効果の薄い小手先の対応をせいぜいガンバッテみたりはするけど、具体的な目標を立てておけば決断できたはずの本来的な抜本対策が、なんとなく見過ごされたり、あるいは見てみぬふりをされたりする。&lt;span style="font-size:smaller;"&gt;（目標の立て方にもいろいろあるが、詳しく立ち入るのは別の機会にする。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;具体的な測定可能な目標を立てることが肝要。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:larger;font-weight:bold;" &gt;◆最初から継続的に計る&lt;/span&gt;&lt;br /&gt;これも「何事も早めに確認して早めに対応するのがよろしい」という、パフォーマンス話に限らず人の営みのほとんど全域に当てはまりそうなプラクティス。&lt;br /&gt;&lt;br /&gt;まあ、リスク管理の基本中の基本でもあるはずなんだけど、なぜかシステム開発に限ってはなおざりにされている。かなり多くのプロジェクトで、パフォーマンスに関するテストや最適化を開発期間の一番最後にもってきて、関係者一同、毎度頭を抱えることになる。&lt;br /&gt;&lt;br /&gt;開発初期から、継続的に計測する仕組みを作って監視するのが大切。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;という３点について、自分としては、かなり当たり前の言わずもがなの事だと感じているが、いろんな反応があった。単なる同意だったり、なるほどと感心されたり、わかってはいるけどウチじゃ難しいんだよなって感じの苦笑いだったり。&lt;br /&gt;&lt;br /&gt;まあ、各現場でそれぞれ文化や事情があるからなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7479951662375013300?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7479951662375013300/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_17.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7479951662375013300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7479951662375013300'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_17.html' title='コード最適化の個人的三原則'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8809648653090529235</id><published>2011-06-13T03:37:00.003+09:00</published><updated>2011-06-13T04:01:42.178+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Scrum + XP</title><content type='html'>国内外のいくつかのIT技術系サイトから、RSS 経由で配信される記事をいつも読んでいるけど、この数年、Agile系記事の中での XP 関連の話題がめっきり少ない。&lt;br /&gt;&lt;br /&gt;と言っても XP が陳腐化したのではなくて、XP のプラクティス群が、その根底にあった価値観と一緒に既に広く普及し、実績を上げ、評価を確立し、換骨奪胎した形でこの業界に取り込まれて、いまさら extreme (究極)なんてキーワードで語られる必要が無くなったって事なのだと思う。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:smaller;" &gt;もちろん、XP の導入に挫折した残念な技術者たちが、プロジェクトの失敗の原因を自分たちの力不足ではなく、XP それ自体に帰結させて、「やっぱ、XP なんかダメだね」なんて言ってるような、底辺な現場も少なくないだろうけど。&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;で、少なくなった XP の話題の代わりに、スクラム関連の記事が多くなってきていて、たまに Lean と Kanban の話題が上がってくる以外は、ほとんどスクラムの話ばかりになっている。&lt;br /&gt;&lt;br /&gt;また、ちょうど一年くらい前に、マイクロソフトのプリセールス技術者から、Team Foundation Server の導入事例について話を伺う機会があったが、そこでも開発プロセスは Scrum を採用していると聞いた。&lt;br /&gt;&lt;br /&gt;そんな昨今だけど、XP でアジャイルに入ってきた人が、スクラム導入のために XP のプラクティスを捨てたり、XP的の価値観を矯正したりする必要はほとんどない模様。&lt;br /&gt;&lt;br /&gt;XP はプラクティス に着目していて、一方、スクラムは組織と管理に着目していて、両者の対象範囲は意外と重ならなかったりする。重なっている部分も無くはないが、同じ事を言っているだけだったりする。&lt;br /&gt;&lt;br /&gt;どうやら、スクラムという枠組み＝フレームワークの中で、XP のプラクティスを実践していくというのが、正しい方向なのだと思う。というか今にして思うと、それぞれを単体で導入・実施するより、スクラム＋XP の組み合わせの方が、大抵の開発現場ではむしろ摩擦が少なかったような気がする。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8809648653090529235?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8809648653090529235/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/scrum-xp.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8809648653090529235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8809648653090529235'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/scrum-xp.html' title='Scrum + XP'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7834774536840731158</id><published>2011-06-12T03:40:00.002+09:00</published><updated>2011-06-12T03:48:18.577+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='業界'/><title type='text'>このギャラ、損か得か？</title><content type='html'>開発案件のギャラを比べるとき、単純にどっちが得でどっちが損か比較するのは意外と難しかったりする。&lt;br /&gt;&lt;br /&gt;難しい理由は、案件の内容だとか契約条件だとかいろいろあるが、今日は、契約条件に含まれる清算方式の違いを解消して比較する方法を考えてみる。&lt;br /&gt;&lt;br /&gt;&lt;div style="border:1px dashed orange;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;例１）&lt;/span&gt;&lt;br /&gt;見込み稼働時間数が &lt;span style="font-weight: bold;"&gt;月240h&lt;/span&gt; の半炎上プロジェクトで、&lt;span style="font-weight: bold;"&gt;140h〜180h上下割60万&lt;/span&gt;の条件がついたとする。これと等価な&lt;span style="font-weight: bold;"&gt;単金固定&lt;/span&gt;プロジェクトのギャラはいくらか？&lt;/div&gt;&lt;div style="border:1px dashed skyblue;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;答え：&lt;/span&gt;&lt;br /&gt;60万 + 60万 ÷ 180h ×（240h−180h） = &lt;span style="text-decoration:underline;"&gt;80万&lt;/span&gt;&lt;/div&gt;言い換えると、これまで 140h〜180h上下割60万で仕事を受けてきた技術者が、見込み月240h の単金固定案件を受けるとすると、80万もらわないと割に合わないということになる。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border:1px dashed orange;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;例２）&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;単金固定72万&lt;/span&gt;の案件の引き合いがあって、プロジェクト内容を聴いたらとっくにデスマ化していて稼働&lt;span style="font-weight: bold;"&gt;300h&lt;/span&gt;に達している。これを&lt;span style="font-weight: bold;"&gt;140h〜200h上下割&lt;/span&gt;に換算するといくらになるか。&lt;/div&gt;&lt;div style="border:1px dashed skyblue;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;答え：&lt;/span&gt;&lt;br /&gt;x + x ÷ 200h ×（300h−200h） = 72万&lt;br /&gt;これを解いて、x = 48万。&lt;/div&gt;このご時世、72万なら悪くないと思うかもしれないが、稼働時間によっては、上下割換算で40万台のしょっぱい案件になり得るとわかる。（ちなみに、この例を上限180hで換算すると43万2千円）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;比較用に標準的な条件を設定して、複数案件を比較するという手もある。例えば「162h の時給換算」とか。&lt;span style="font-size:85%;"&gt;（行政機関の年間営業日243日を採用し、これを12ヶ月で割ると、一月あたりの勤務日数は20.25日となり、これに8時間を書けると162時間となる。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border:1px dashed orange;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;例３)&lt;/span&gt;&lt;br /&gt;他の条件（通勤、やりがい等）が同じとすると、得なのはどれか。&lt;br /&gt;① 60万単金固定 (想定220h)&lt;br /&gt;② 57万(140-200) (想定220h)&lt;br /&gt;③ 55万(140-180) (想定220h)&lt;br /&gt;④ 54万(140-180) (想定200h)&lt;/div&gt;&lt;div style="border:1px dashed skyblue;padding:3px 6px 3px 6px;"&gt;&lt;span style="font-weight: bold;"&gt;答え：&lt;/span&gt;&lt;br /&gt;① 60万 ÷ 220h × 162h =&lt;span style="font-weight: bold;"&gt;44.1818万&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;② 57万 × (1 + 20h／200h）=62.7万&lt;br /&gt;　 62.7万 ÷ 220h × 162h =&lt;span style="font-weight: bold;"&gt;46.17万&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;③ 55万 × (1 + 40h／180h）=67.2222万&lt;br /&gt;　 67.2222万 ÷ 220h × 162h =&lt;span style="font-weight: bold;"&gt;49.5万&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;④ 54万 × (1 + 20h／180h）=60万&lt;br /&gt;　 60万 ÷ 200h × 162h =&lt;span style="font-weight: bold;"&gt;48.6万&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;得な順に、③→④→②→①　となる。&lt;/div&gt;&lt;br /&gt;①、②、③は清算方式の違いによって、見掛け上の単金と受け取り額の順序が逆転し、従って損得も逆転する。&lt;br /&gt;①と④では、受け取り額が同じだけど、稼働時間の違いにより、損得が逆転する。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;こんな感じで、案件を比較できる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;（理想的には、8時間働いた後に追加で働く1時間と、12時間働いた後に&lt;/span&gt;&lt;span style="font-size:85%;"&gt;追加で&lt;/span&gt;&lt;span style="font-size:85%;"&gt;働く1時間では、同じ1時間でも価値が違うので、これを考慮する変換方式にする必要があるが、かなり複雑になる。）&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;換算方式を工夫すれば、他の要素も取り込んで標準化して比較できる。特に、通勤にかかる時間は、実は交通費以上に結構大きく影響する。往復30分と3時間では、実質的に失う時間が大きく違うので、比較するには一工夫必要になる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7834774536840731158?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7834774536840731158/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_12.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7834774536840731158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7834774536840731158'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post_12.html' title='このギャラ、損か得か？'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6944436191062034700</id><published>2011-06-11T06:54:00.008+09:00</published><updated>2012-01-04T21:57:34.016+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>なぜ UnitTestが生産性を上げるか</title><content type='html'>&lt;a href="http://yasutech.blogspot.com/2011/06/unittest.html"&gt;前回&lt;/a&gt;、UnitTest の必要性について書き始めて、どうやらコーディングの生産性向上らしいってとこまで来た。今回はその続き。&lt;br /&gt;&lt;br /&gt;＝＝＝＝&lt;br /&gt;UnitTest はコーディングの生産性を高める。&lt;br /&gt;&lt;br /&gt;・・・というのは少し大雑把で、より正確には、高い生産性を得るために最も重要な条件の成立に、UnitTest が不可欠であると言う事になる。&lt;br /&gt;&lt;br /&gt;で、その条件とはすなわち「内部品質が高い」と言う事である。&lt;br /&gt;&lt;br /&gt;この内部品質を高める事により、「ソースを読む」、「書き足す」、「書き直す」、「間違いを探す」と言った、コーディングの大部分を構成する作業に要する時間を大幅に削減できる。内部品質が高まるほど、コーディングの所要時間が下がり、生産性が上がってくる。&lt;br /&gt;&lt;br /&gt;では、なぜ UnitTest が内部品質の向上に寄与するのか？&lt;br /&gt;&lt;br /&gt;これは、UnitTest が内部品質向上作業の生産性を高めるからなのだけど、この「内部品質向上作業」とは、ザックリ言うとリファクタリングの事である。&lt;br /&gt;&lt;br /&gt;この&lt;a href="http://c2.com/xp/RefactorMercilessly.html"&gt;リファクタリングを徹底的に（Mercilessly）に行う&lt;/a&gt;事により、高度な生産性を実現できるような、高いㇾベルの内部品質に初めて到達できる。ここで UnitTest は、リファクタリング作業それ自体の生産性を高めるために（同時にリスクを下げるために）利用される。&lt;br /&gt;&lt;br /&gt;これ以上の説明は不要な気がしないでもないが、なぜ UnitTest によってリファクタリング作業の効率性が高まるかというと、コード修正による「意図せざる事象」をもっとも効率よく検出できるからと言える。&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://yasutech.blogspot.com/2010/07/functional-test-unit-test.html"&gt;前にも書いた&lt;/a&gt;が、UnitTest とは「doing the right things（正しい動作をしている事）」ではなく、「"doing things right"（正しく動作している事）」を検証するものである。ここで「正しく」とは、「意図した通り」という意味なわけで、つまり UnitTestとは「意図せざる事象」を発見する仕組みという事になる。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;リファクタリングという作業は、極論すれば仕様なんて知らなくても良いとうホワイトボックスの中身だけに着目した作業と言える。また、プログラムの成長に伴い、随時（常時）、実施していくものなので、必然的に反復作業となる。&lt;br /&gt;&lt;br /&gt;従って、外観の振る舞いを変えずにソースコード修正を繰り返すリファクタリングという作業に当たっては、自動化ホワイトボックステストである UnitTest が最適なプラクティスということになる。&lt;span style="font-size:85%;"&gt;FunctionalTest でも結果的に「意図しない動作」を検出できないでもないが、直接性において UnitTest に比べて劣る。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ちなみに、そもそも JUnit を用いた UnitTest が広く一般に認知されたのは、ファウラーの&lt;a href="http://amazon.co.jp/o/ASIN/4894712288/yasuabe1984-22/ref=nosim"&gt;リファクタ本&lt;/a&gt;で紹介されたのが契機だったりするので、歴史的にも UnitTest は リファクタリング と密接に関連付けられたプラクティスだと言える。&lt;span style="font-size:85%;"&gt;（JUnit を使う事が UnitTest であるとは必ずしも言えないが）&lt;/span&gt;。&lt;br /&gt;&lt;br /&gt;以上、コーディング生産性向上と UnitTest の関係についてだいたい説明したが、振り返ってまとめると、以下のようになる。&lt;br /&gt;&lt;div style="background-color:navy;padding:5px 0px 5px 10px;"&gt;UnitTest を充分書く&lt;br /&gt; ↓&lt;br /&gt;リファクタリングの生産性が高まる&lt;br /&gt; ↓&lt;br /&gt;内部品質が向上する&lt;br /&gt; ↓&lt;br /&gt;短い時間で正しいコーディングが簡単にできるようになってくる&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;これは、以下のように逆に書くこともできる&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color:navy;padding:5px 0px 5px 10px;"&gt;UnitTest を書かない&lt;br /&gt; ↓&lt;br /&gt;リファクタリングできない&lt;br /&gt; ↓&lt;br /&gt;内部品質が低下する&lt;br /&gt; ↓&lt;br /&gt;頭をかきむしりながら長時間かけてるのにバギーなコード&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;実際の現場では、逆に書いた版のプロジェクトが、未だに多いんだよなあ。&lt;br /&gt;&lt;br /&gt;UnitTest をしないからリファクタできないパターンと、リファクタリングをしない（或いはそもそも知らない）から、UnitTestの必要性が分からないってパターンの両方考えられるが、どっちにしても低レベルすぎる。&lt;br /&gt;&lt;br /&gt;といったわけで、内部品質の劣悪なソースコードと UnitTest の不履行との間には高い相関があるわけだけど、内部品質だけじゃなく外部品質、つまりバグやらパフォーマンス劣化やらにも巡り巡って因果関係が及んでいたりする。&lt;br /&gt;そのうちこれも書こうと思う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6944436191062034700?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6944436191062034700/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/unittest_11.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6944436191062034700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6944436191062034700'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/unittest_11.html' title='なぜ UnitTestが生産性を上げるか'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8764255687289390464</id><published>2011-06-11T06:54:00.003+09:00</published><updated>2012-01-04T21:57:47.419+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>なぜ UnitTest が必要か</title><content type='html'>以前、2種類の品質、&lt;a href="http://yasutech.blogspot.com/2011/01/blog-post_27.html"&gt;製品品質とコード品質&lt;/a&gt;について対比した。&lt;br /&gt;また &lt;a href="http://yasutech.blogspot.com/2010/07/functional-test-unit-test.html"&gt;FunctionalTest と UnitTest&lt;/a&gt; についても違いを比べた。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://yasutech.blogspot.com/2011/06/blog-post.html"&gt;前回&lt;/a&gt;は、製品品質の保証のためには、FunctionalTest が必要であることを説明したが、それらを踏まえて、今回は UnitTest の必要性とは何かを、考えてみる。&lt;br /&gt;&lt;br /&gt;=＝＝＝&lt;br /&gt;UnitTest を書く理由、得られる効用について考えると、テストって語が含まれてるぐらいだから、品質向上のためじゃなかろうかと最初は思う。&lt;br /&gt;&lt;br /&gt;でも違う。仕様通りに動くかどうかといった製品品質（外部品質）の検証なら、前回書いたように、UnitTest ではなく FunctionalTest の出番になる。また製品品質ではなくソースコード品質（内部品質）の検証だとしても、静的チェックツールがふさわしい。どちらの意味の品質についても、UnitTest の出番ではない。&lt;br /&gt;&lt;br /&gt;品質じゃないとしたら、何だろう。UnitTest といえば、自動化テストなわけだから、つまり生産性向上？&lt;br /&gt;&lt;br /&gt;うん、生産性の向上である事は間違ってなさそうだけど、でも何の生産性か。ソフトウェア開発にはいろんな作業が含まれるが・・・&lt;br /&gt;&lt;br /&gt;ならば、直訳で「単体テスト」だから、単体テストの生産性の向上？&lt;br /&gt;&lt;br /&gt;うーん、いわゆる「単体テスト」、つまり旧来のウォーターフォール・モデルで言うような、&lt;span style="color:skyblue"&gt;「一個のモジュールが、後工程の結合テストを実施するに足る品質を満たしているかどうか検証する作業」&lt;/span&gt;という意味なら、やっぱり違ってるだろう。&lt;br /&gt;&lt;br /&gt;「単体→結合」の観点で見た場合に、そこで単体に要求されている品質は、単体レベルの機能要求がブラックボックス的にで満たされていればそれで良い訳で、これを検証するのは FunctionalTest という事になる。&lt;span style="font-size:85%;"&gt;繰り返しになるが、UnitTest は品質（機能・非機能要求の充足）、つまり"doing the right things"は検証しない&lt;/span&gt;。&lt;br /&gt;&lt;br /&gt;単体テストじゃないし、設計でもなさそうだし、そんじゃ、コーディングの生産性か・・・&lt;br /&gt;&lt;br /&gt;まあ、結局そういうことになる。&lt;br /&gt;&lt;br /&gt;がしかし、そもそもテストを書くという追加作業をしてるのに、生産性が上がるのはなぜだろう。それにコーディングといってもいろいろあるし、どの局面の何のコーディングだろう。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;長くなったので、&lt;a href="http://yasutech.blogspot.com/2011/06/unittest_11.html"&gt;次に続く&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8764255687289390464?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8764255687289390464/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/unittest.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8764255687289390464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8764255687289390464'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/unittest.html' title='なぜ UnitTest が必要か'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2419895268051133353</id><published>2011-06-08T03:19:00.007+09:00</published><updated>2012-01-04T21:57:59.769+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>FunctionalTest の必要性</title><content type='html'>以前、&lt;a href="http://yasutech.blogspot.com/2010/07/functional-test-unit-test.html"&gt; UnitTest と FunctionalTest と の違い&lt;/a&gt;について、「コードが正しく書かれている事」のテストと、「コードが正しく動いている事」のテストとして対比した。&lt;br /&gt;&lt;br /&gt;今日は、前者の FunctionalTest について例を上げて説明し、その必要性について考えてみる。&lt;br /&gt;&lt;br /&gt;例えば、こんな問いがあるとする。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: navy;color:snow;"&gt;数字を受け取って平方根を返すプログラムを書いた。&lt;br /&gt;ところが、平方根ではなくて二乗が返されるというバグが出た。&lt;br /&gt;さて、どんなテストを書いておけば、これを防げたか。&lt;/div&gt;&lt;br /&gt;最近 xUnit や TDD を始めたばかりの人なら、「xUnit で UnitTest を書いてカバレッジを 100%にしておけばよかったんじゃない？」なんて考えるかも知れない。&lt;br /&gt;&lt;br /&gt;だけど、xUnit の実践経験がそこそこある人なら、それじゃ十分ではないとすぐ分かると思う。&lt;br /&gt;&lt;br /&gt;これが単なるコーディングミス、つまり「正しく仕様を理解した上でのコードの書き間違い」によってのみ起因するバグならば、例えば 4 から 2が得られる事を確かめるアサーションがテストコード中にあるはずなので、誤りはすぐに検出される。この場合は、上の答えでもあながち間違いではない。&lt;br /&gt;&lt;br /&gt;ところが、同じバグは単なるコーディングミスによるのではなく、「誤った仕様理解の下での意図通りのコーディング」によっても生じてくる。&lt;br /&gt;&lt;br /&gt;例えば何かの拍子で、プログラマが平方根と二乗を勘違いして取り違えていた場合、本体コードに二乗の計算が書かれるのみならず、テストコードにも 4 から16を返すアサーションが書かれてしまうので、バグは検出されない。&lt;br /&gt;&lt;br /&gt;平方根と二乗の勘違いなんて何だか馬鹿馬鹿しい例だが、実際のシステム開発のドメイン（問題領域）は、普通はもっと複雑だから、こうした認識ズレがバグの原因に占める割合は非常に多い。&lt;span style="font-size:85%;"&gt;（また、上のような概念Aと概念Bの取り違えの他にも、仕様の見落としや失念、変更の連絡ミスなど、様々な事が認識ズレの原因になる。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;一般に、「要求されている仕様」と「実装者の認識」のズレから生じたバグは、テストコードにも同じ誤認を織り込んで書かれてしまっているため、本体のコーディングと連動して生産された UnitTest によっては検出できない。&lt;br /&gt;&lt;br /&gt;この種のバクを防ぐためには、仕様を理解し責任を持っている人が作業に介在しなければならない。&lt;br /&gt;&lt;br /&gt;仕様担当者がプログラマが書いたテスト仕様書をレビューしたり、仕様担当者自身がテスト仕様書を作ったりといった形で、「わかってる人」の意識をくぐり抜ける必要がある。上の例では、「平方根を返す」という要件を定義した人が、テスト仕様書に「4 ならば 2」という「条件 ---&gt; 結果」のペアが含まれている事を確認していなければならない。&lt;br /&gt;&lt;br /&gt;つまり最初の問いの答案としては、仕様が分かっている人にレビューされた仕様ベースのテスト、つまり FunctionalTest が必要ということになる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;（ちなみに、テスト仕様書の作成はコーディング前でも良いし、またテスト実施に自動化ツールを使ってもいい。ただし、ソースコードベースの DeveloperTestとは視点が全然違うことに注意する必要がある。例えば、網羅率はコードカバレッジではなく、仕様から起こしたテスト項目の実施率となる。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;=＝＝＝&lt;br /&gt;といったような事は実はかなり基本的な事項なんだけど、かなり多くの底辺現場では理解されていない。で、「コードカバレッジが100%に近づいているのにバグが減らない。って事は、xUnitや TDD は役に立たないって事になるんじゃね？」なんて、アホな論理がまかり通るようになる。やれやれ…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2419895268051133353?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2419895268051133353/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2419895268051133353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2419895268051133353'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/06/blog-post.html' title='FunctionalTest の必要性'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-4812922323726209409</id><published>2011-05-31T02:43:00.003+09:00</published><updated>2011-05-31T02:54:34.303+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='非RDB'/><title type='text'>Hadoop</title><content type='html'>今日、初対面の技術者との会話の中で、ハドゥープという単語が出てきた。最初よく聞き取れず、「はぁ？ハヌですか？ハドブ？」なんて聞き返してしまった。恥ずかしい。&lt;br /&gt;&lt;br /&gt;帰宅して、ヤマ勘で Hadoop とタイプしてググってみると、ちゃんとスペルが合ってたらしく、それっぽいのがたくさん引っかかってくる。その中に、&lt;a href="http://hadoop.apache.org/"&gt;Apache Hadoop&lt;/a&gt; とかいうのがある。うん、なんか知らないけどこれだろ、これ。&lt;br /&gt;&lt;br /&gt;つうか、どこの馬の骨とも知れないマイナー製品かと思ったら、れっきとした &lt;a href="http://www.apache.org/"&gt;ASF&lt;/a&gt; の Top Level Project らしい。YouTubeでも、&lt;a href="http://www.youtube.com/results?search_query=hadoop"&gt;たくさん動画がある&lt;/a&gt;。&lt;br /&gt;&lt;span style="font-size:85%;"&gt;※ちなみに、「ハデュープ（敢えて五十音にマッピングすると）」って感じで発音してる欧米人も多い。&lt;/span&gt;&lt;br /&gt;簡単に言うと、分散コンピューティング環境上で稼働する大量データ処理フレームワークで、分散ファイルシステム、分散DB、MapReduce の Java 実装なんかが含まれているらしい。Google の既存製品やプログラミングモデルに影響を受けているとの事。&lt;br /&gt;&lt;br /&gt;下の動画が、紹介レベルとしては能くまとまってる感じ。（ただし音声は滅茶苦茶に酷いが）&lt;br /&gt;&lt;iframe src="http://www.youtube.com/embed/Aq0x2z69syM" allowfullscreen="" frameborder="0" height="349" width="425"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;しかし、こんな有名で面白そうなのを知らなかったのか、俺…。&lt;br /&gt;&lt;br /&gt;まあ 2年以上、仕事としては Java から離れていたわけだけど、&lt;br /&gt;うーん、やっぱブランクかなあ…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-4812922323726209409?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/4812922323726209409/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/05/hadoop.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4812922323726209409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/4812922323726209409'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/05/hadoop.html' title='Hadoop'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/Aq0x2z69syM/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8567875288429713175</id><published>2011-05-29T02:58:00.005+09:00</published><updated>2011-07-02T00:45:46.241+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DomainModel'/><title type='text'>ユビキタス言語のベースの言語</title><content type='html'>ドメイン駆動開発（DDD）を謳っている開発案件が、なんだか最近出始めてきたらしい。今日は、このDDDの中での最重要プラクティスのうちの一つである「ユビキタス言語」について思案してみる。&lt;br /&gt;&lt;br /&gt;ちょうど一年くらい前、日本のソフトウェア開発現場でも、せめて&lt;a href="http://yasutech.blogspot.com/2010/06/blog-post.html"&gt;ユースケースだけでも英語化されるといいなあ&lt;/a&gt;、という思いを書いた。そこで、「ほとんどの日本の現場では、&lt;span style="color:white;"&gt;日本語による要件定義&lt;/span&gt;と&lt;span style="color:white;"&gt;英語ベースの実装作業&lt;/span&gt;との間のどこかに&lt;span style="color:white;"&gt;日本語⇔英語のギャップ&lt;/span&gt;が横たわっていて、これがオブジェクト指向開発の効果的な流れを阻害しているが、要件定義側、特にユースケースの段階で英語化してしまえば、この不経済がかなり解消できると思われる」という事を述べた。&lt;br /&gt;&lt;br /&gt;個人的には英語→日本語のギャップが、実はかなり昔から、オブジェクト指向分析やドメイン・モデリングの普及や実施において大きな阻害要因になっていたのではないかと常々思っていたが、意外と取り沙汰される事がない。必然的に問題として認識しようもない英語圏ならばともかく、日本の開発現場では、一応気にはなっている技術者もきっと少なくないはずなんだけど。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;さて DDD においては、業務の世界と開発の世界の狭間に、ユビキタス言語---つまりドメイン専門家とのコミュニケーションにおいても、プログラミング言語を用いたコーディングにおいても、常に一貫して使用する事を求められる共通言語---が策定される事になっていて、これが肝だったりする。&lt;br /&gt;&lt;br /&gt;で自分が思うに、このユビキタス言語についても、ユースケースと同じ理屈で英語ベースにしてしまってはどうかと。&lt;br /&gt;&lt;br /&gt;この英語ベースのユビキタス言語の語彙を用いて、クライアントや業務SEと対話し、ドメインモデルの各要素に名前を与え、プログラム中のクラスやメソッドに識別子を与えるようにすれば、無駄なギャップが解消され、少なくとも英語圏ではほぼ自動的に実現されるレベルの一貫性・直接性に、ちょっとは近づけるのではないかと思う。※1&lt;br /&gt;&lt;br /&gt;もちろん、言語の差異の吸収という非英語圏特有の負担を押し付けられてしまっているわけだから、Eric Evans らが考えるオリジナルのユビキタス言語からはちょっと変質してしまうかもしれない。英語の使用により、業務屋にとってもプログラマにとっても、多かれ少なかれユビキタス言語の「難易度」は高まるとは思う。&lt;br /&gt;&lt;br /&gt;それでもやっぱり、開発工程全体のどこかで必ず生じるこのギャップを、結局はどこかで吸収せざるを得ないならば、開発序盤、あるいは「上流工程」で英語化してしまうのが一番経済的って気がする。&lt;br /&gt;&lt;br /&gt;もちろん顧客によっても、事情は大きく変わるに違いない。社内公用語を英語にするような動きのある顧客では、さして抵抗も強くないはず（楽天だけじゃなく、最近は結構増えてきている）。逆に、余りにも一般教養レベルが低いような層の顧客だと、ワンクッションとしての業務SEを置いて、英和変換させるなどの策を講じないと難しいかもしれない。&lt;br /&gt;&lt;br /&gt;あと、単なるユースケースの英語化と違って、ユビキタス言語の場合は文書だけじゃなく会話でも使うだろうから、カタカナ英語を日本語の助詞や助動詞でくっつけたような変な会議風景が現出するかもしれない（完全英語化すれば別だけど）。&lt;br /&gt;&lt;br /&gt;まあ、日本語と英語のどちらをユビキタス言語のベースに採用するにせよ、「どっちを選んだときに、どんな作業や問題が発生するか（DDD関連の洋書には普通書かれていない）」について、予めよくよく考えておく事が、DDD導入にあたっては大きなポイントになってくるんじゃないだろうか。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;※1 あまりにも無学なPGばかりが集まる底辺プロジェクトだと、JavaやC＃等の高水準OOPLが英語ベースであることすら認識されていない事が多い。彼らにとってはプログラミング・コードなんて、記号の羅列としか認識されていないから、そもそもドメインの語彙とか分析とか殆ど関係ない。従ってもちろん DDD も大して意味が無い。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8567875288429713175?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8567875288429713175/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/05/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8567875288429713175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8567875288429713175'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/05/blog-post.html' title='ユビキタス言語のベースの言語'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3298534805498958160</id><published>2011-05-28T01:02:00.002+09:00</published><updated>2011-05-29T15:38:24.587+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE'/><title type='text'>FedoraCore12 + JBoss6.0 + Helios</title><content type='html'>久しぶりにJava案件をやることになりそうなので、自宅環境を準備。だいぶ前に FedoraCore12 を入れたマシンがあったので、これを使うことにする。&lt;br /&gt;&lt;br /&gt;FedoraCoreメニューの「ソフトウェアの追加と削除」に Eclipseがあったのでインストールしてみたが、これは一世代前の Galileo だったので、アンインストールして Helios を入れ直すことにした。と言っても、Eclipse 本家サイトから java EE開発用のバイナリを落として、単に /usr/local/eclipse/下に展開しただけで、特に難しい作業は無し。&lt;br /&gt;&lt;br /&gt;で、一応Webアプリという事で、アプリケーションサーバが必要になるが、とりあえず JBoss の6.0 を入れることにした。JBossサイトの&lt;a href="http://docs.jboss.org/jbossas/docs/Installation_Guide/beta500/html-single/index.html#binary_installation"&gt;インストールの説明&lt;/a&gt;に従ってしばし簡単な作業をしてから、run.sh で起動して正しくインストールされ起動する事を、ログとブラウザで確認。&lt;br /&gt;&lt;br /&gt;次に Eclipse との連携を準備。Eclipse の Servers ビューで新規追加しようとしたら、Server Adapter が JBoss5.0 までしかなくて一瞬戸惑ったが、JBoss5.0 のアダプタでも&lt;a href="http://community.jboss.org/thread/148575"&gt;問題なくJBoss６.0を動かせるという話&lt;/a&gt;があったので、とりあえず信用してJBoss5.0でサーバを追加。ところが、起動してみるとrun.sh からの起動では出ていなかった例外がスタックトレースされている。&lt;pre style="background-color:blue;overflow:auto;"&gt;20:56:53,101 ERROR [AbstractKernelController] Error installing to Instantiated: name=PostEjbJarMetadataDeployer state=Described: java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;&lt;br /&gt;    at org.jboss.metadata.annotation.creator.AbstractResourceProcessor.createResourceEnvRef(AbstractResourceProcessor.java:394) [:2.0.0.Alpha24]&lt;br /&gt;    at org.jboss.metadata.annotation.creator.AbstractResourceProcessor.process(AbstractResourceProcessor.java:237) [:2.0.0.Alpha24]&lt;br /&gt;…略&lt;/pre&gt;&lt;br /&gt;ググってみると、同じ現象について&lt;a href="http://community.jboss.org/thread/160526"&gt;とあるサイト&lt;/a&gt;で議論されていた。これを参考にプラグインのjar（JBoss 6.0 対応の Server adapterらしい）をダウンロードして（&lt;a href="http://www.cs.hs-rm.de/~knauf/public/eclipse/plugins/"&gt;ここから&lt;/a&gt;）eclipse/plugin下に展開。さっき作った JBossサーバを一旦削除してからEclipseを再起動し、再び Server ビューから新規作成を始めると、今度はJBoss6.0が選択肢に含まれている。これを指定して再作成。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-e8CcIvT50DE/Td_GAAeDkeI/AAAAAAAAAPc/aFgXSs7Ishs/s1600/Screenshot-New%2BServer20110527-1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 190px; height: 320px;" src="http://1.bp.blogspot.com/-e8CcIvT50DE/Td_GAAeDkeI/AAAAAAAAAPc/aFgXSs7Ishs/s320/Screenshot-New%2BServer20110527-1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5611421364155290082" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;おもむろにスタートボタンを押すと今度はエラー無しに起動する。念のため、適当に Dynamic Web Application を作成し、適当なtest.jsp を追加してデプロイ。ちゃんと表示される事を確認。&lt;br /&gt;&lt;br /&gt;とりあえず、準備できた。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3298534805498958160?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3298534805498958160/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/05/fedoracore12-jboss60-helios.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3298534805498958160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3298534805498958160'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/05/fedoracore12-jboss60-helios.html' title='FedoraCore12 + JBoss6.0 + Helios'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-e8CcIvT50DE/Td_GAAeDkeI/AAAAAAAAAPc/aFgXSs7Ishs/s72-c/Screenshot-New%2BServer20110527-1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8778927483279928190</id><published>2011-02-01T21:11:00.004+09:00</published><updated>2012-01-04T21:58:15.931+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>Test Double の「Double」とは</title><content type='html'>プログラマにとって「double」と言えば、まず第一に倍精度浮動小数点数のことだろうけど、&lt;a href="http://xunitpatterns.com/Test%20Double%20Patterns.html"&gt;Test Double&lt;/a&gt; の「double」はどうか。&lt;br /&gt;&lt;br /&gt;昨今の開発で、まともにテスト駆動が成立するレベルのテストコード、つまり &lt;a href="http://xunitpatterns.com/Test%20Smells.html"&gt;TestSmell&lt;/a&gt; が一定以下に抑制された &lt;a href="http://c2.com/cgi/wiki?DeveloperTest"&gt;DeveloperTest &lt;/a&gt;を書いていくためには、かなり多くの場面で Test Double パターンが必要になる。今日びのプログラマにとっては、Stub、Mock、Fake、Spy 等を含む Test Double と言われる一群のテストパターンを自在に使いこなす事は、必須技術の一つと言えるんじゃないかと思う。&lt;br /&gt;&lt;br /&gt;個人的な話になるが、実は自分は、この Double の意味を知らないまま、長い間「Test Double」という言葉を使っていた。深く考える訳でもなく、何となく「Test」を動詞、「Double」を副詞と認識して「二重にテストする」なんて意味かなと思っていたが、TestDouble が意味する手法と一致しなくて、ずっと気持ち悪かった。&lt;br /&gt;&lt;br /&gt;ある時、何気なくネットの辞書を引いてみたら、ちゃんと答えがあった。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ejje.weblio.jp/content/double"&gt;Weblio の英和辞書&lt;/a&gt;ではこんな感じ&lt;br /&gt;&lt;pre style="border:1px dashed snow;padding:5px 5px 5px 5px;"&gt;【名詞】3.b【映画】&lt;br /&gt;代役，替え玉 〔for〕.&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.oxfordadvancedlearnersdictionary.com/dictionary/double_4"&gt;英英辞書の OALD&lt;/a&gt; ではこんな感じ&lt;br /&gt;&lt;pre style="border:1px dashed snow;padding:5px 5px 5px 5px;"&gt;NOUN PERSON/THING [countable] &lt;br /&gt; an actor who replaces another actor in a film/movie &lt;br /&gt; to do dangerous or other special things&lt;/pre&gt;&lt;br /&gt;まず、Double を副詞と考えていたのが、そもそも間違いで、本当は映画用語の名詞。Double が副詞でないということは「Test」は動詞ではありえず、したがって「Test Double」で名詞+名詞の複合名詞、つまり「テストの替え玉」という意味になる。&lt;br /&gt;&lt;br /&gt;やっぱ辞書はこまめに引かないといかんな。&lt;br /&gt;&lt;br /&gt;※OALD は 非英語ネイティブ向けの英英辞書としては、かなり良い感じ。ネット版だけじゃなく、リアルの辞書もよくできてる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8778927483279928190?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8778927483279928190/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/02/test-double-double.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8778927483279928190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8778927483279928190'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/02/test-double-double.html' title='Test Double の「Double」とは'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-1967612127922278029</id><published>2011-02-01T04:18:00.003+09:00</published><updated>2011-02-02T03:17:35.713+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>底辺プロジェクトの DoNotCatchGeneralExceptionTypes</title><content type='html'>&lt;a href="http://yasutech.blogspot.com/2011/01/c_30.html"&gt;前回&lt;/a&gt;普通で当たり前な例外処理コーディングについて書いたとき、同様のやり方が FxCop の開発者のブログ記事でも推奨されている事に触れた。実は、その記事の本来の趣旨は、例外を基底クラスの Exception型 で catch しようとする無知な輩を啓蒙するというものだった。&lt;br /&gt;&lt;br /&gt;今回は、その事について考えてみる。ちょっとクドクドとネチっこく考えてみる。&lt;br /&gt;&lt;br /&gt;＊以下、いちいち「例外を基底クラスの Exception型 で catch する」と書くのは面倒なので「基底キャッチ」と呼ぶ。&lt;br /&gt;&lt;br /&gt;=＝＝＝&lt;br /&gt;その記事で、件の開発者は以下のように告白している。&lt;br /&gt;&lt;br /&gt;&lt;div style="border:1px dashed snow;padding:3px 3px 3px 3px;"&gt;There are actually far too many &lt;code&gt;catch (Exception)&lt;/code&gt; blocks in FxCop itself and it has caused us a great deal of grief. We’re working on removing them and I’m confident it will help us to deliver better software!&lt;/div&gt;&lt;br /&gt;「実は、FxCop のソース自体に基底キャッチが濫用されていて酷い目にあったが、それを取り除いていくことで結局良いソフトウェアになった」と言う話。で、その教訓を踏まえて、基底キャッチがいかにダメな事なのか、基底キャッチ容認派への反論も交えて詳説している。&lt;br /&gt;&lt;br /&gt;当の FxCop 開発者がそんな真似をしていたなんて意外だが、記事自体がもう4年半も前のものである事を考えると、相当に古い昔話なんだろうし、まあそんなものかと。でも、この記事やその他の同内容の言説のおかげで、基底キャッチが是か非かなんて問題を今さら蒸し返すような人は、少なくとも英語圏には少ないんじゃないかと思う。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;ところが、未だに日本の底辺プロジェクトでは、基底キャッチで例外をもみ消して、「臭い物に蓋」よろしく無かった事にしてしまう手法が、当たり前のように日夜実践されている。しかも「教科書通りに行かないプロの現場で禁じ手を使いこなしてる俺って、やっぱプロだぜ！」てな感じで、一部の底辺プログラマが得意気な感じだったりもする。&lt;br /&gt;&lt;br /&gt;そんなドン底の世界では、こんな事がもっともらしく力説される。&lt;br /&gt;&lt;br /&gt;「うちのアプリは何があっても落とさないポリシーだから、どんな例外だろうとスルーは容認できない。防止も予測もできず、従って対処法の分からない未知の例外もあるだろうが、そう言うのはもみ消してでも続行させるしか手はない。それがうちの流儀なんだから仕方がない。」&lt;br /&gt;&lt;br /&gt;で、全ての例外を漏らさないために、基底キャッチが導入されるというわけだが、まずそもそも、そんな想定外で正体不明な例外をもみ消したあと、アプリがまともに動くってどうして保証するんだろう？ DBに不正データを作ったり、誰かの給料を間違って計算したり、外部のサービスに不正なリクエストを送ったりしないと言えるのかと。そんなの技術以前に、論理的に矛盾してるし、言える訳がない。&lt;br /&gt;&lt;br /&gt;そもそも顧客は何て言ってるんだろう。 「Null参照でアプリが落ちると嫌だから、取引先の公開サービスに不正リクエストを送っても良いから、動作続行させてください」なんて、言った人がいるんだろうか。でなければ、実行を続ける事で不測の重大事態が起きないと限らない事を伏せたまま、うちのアプリは落ちませんとだけ、顧客に説明している事になるわけで、それこそ大問題のはず。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;エンドユーザの使用中には自分のアプリは落ちてほしくない。落ちるのは嫌だ。落ちるべきでない。それに敢えて異議を唱える訳ではない。が、だからと言ってアプリの誤動作の方がマシと言う事にもならない。だとしたら、いかに未知の例外によりアプリが停止する状況を極少化していくか、それしかないはず。&lt;br /&gt;&lt;br /&gt;もうほとんど結論が出ているが、その前にもう少しだけ底辺プログラマの声に耳を傾けてみると、たいていこんな事を言っている。「発生し得る全ての例外の型をキャッチしていたら、いくつ catch ブロックがあっても足りない。現実的でない。」&lt;br /&gt;&lt;br /&gt;この主張の駄目な点を指摘すると、以下の2つになる。&lt;br /&gt;&lt;br /&gt;第一に、キャッチすべき例外が何か分かっていない。前回書いたフツーの例外処理の作法を分かっていれば、「全ての例外を…」なんて発想にはならない。発生の条件が既知であり、対象法がわかっている例外だけがキャッチする意味がある訳で、それ以外はキャッチせずにスルーしろと言っている。&lt;br /&gt;&lt;br /&gt;第二は、第一のダメな点の原因でもあるのだが、やはりこれも「アプリを停止させるくらいなら、もみ消してしまいたい」という強迫観念に憑かれているという点。「アプリは停止できない」 → 「どんな例外もスルーできない」 → 「例外は須くキャッチすべき」という思考パターンだが、これが間違っているのは上で説明した。&lt;br /&gt;&lt;br /&gt;予見できて対処できるものをキャッチするという、これこそ正に現実的としか言えない話しか、最初から誰もしていない。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;これだけ言っても、まだ次のような言い分で食い下がる人もいる。&lt;br /&gt;&lt;br /&gt;「そんな風に例外をスルーしてばかりいたら、その度にアプリが停止して、顧客がいちいち再起動する状況が頻発するから大問題になる。」&lt;br /&gt;&lt;br /&gt;そんなの、例外とか catch の作法以前に、単に納品できる品質に至っていないという馬鹿な話でしかないんだが、実はこの辺りに問題の本質がある。&lt;br /&gt;&lt;br /&gt;つまり、スルーした場合のアプリ停止にしても、もみ消した場合の不正動作にしても、それらは結果として出てきた現象なのでって、まず先んじて発生した未知の例外状況が、そもそもの原因としてある。&lt;br /&gt;&lt;br /&gt;で、この「想定漏れ」や「考慮漏れ」、「テストから漏れたコーディングミス」などを含む原因側に働きかける事こそが、抜本対応と言えるわけだが、正にここにおいて、「例外スルー」と「例外もみ消し」は決定的に正反対の効果を見せてくる。&lt;br /&gt;&lt;br /&gt;潔く例外をスルーする事は、結果としてアプリを落とす事になっても、結局は未知の例外状況の発生を減らしていく事になる。理由は、開発中に発見しやすく、従って現行犯的に処置できるため、もっとも効率がいいから。&lt;br /&gt;&lt;br /&gt;一方、例外をもみ消す事とは、潜在バグを温存し溜め込んでいく行為に他ならない。健全な開発作業に当然含まれるはずの、意図しなかったのコードや想定から漏れていた条件を&lt;span style="font-weight:bold;"&gt;発見&lt;/span&gt;し、意図通りに直したり想定内に置き直していく営みが台無しになる。せっかく開発中に潰せたかもしれない未知の挙動を握りつぶして、客先まで不安定要因を持ち込んでしまっているわけだから、救いようがない。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;かなりの極論になるが、突き詰めると、こういう選択になる。&lt;br /&gt;&lt;br /&gt;数年に一回、未知の例外により停止するものの、その他は誤動作もない安定したアプリと、停止だけはしないが、年中不安定な動作を続けながら、しばしば深刻な誤動作をしでかし、しかもその障害解析が極めて困難なアプリとで、どちらが良いか？&lt;br /&gt;&lt;br /&gt;使う側にとっても、作る側にとっても、どちらにとっても答えは決まってると思うんだが。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;まあ、普通のプログラマは、分かり切った事なのに、ずいぶんくどいなあと思うかもしれない。自分だって「例外のもみ消しは、結局は品質落とすよね。」の一言で済む話だと、正直思ってた。そうした普通の感覚が成立しないどん底プロジェクトにいつ巻き込まれるか分からないから不景気って恐ろしい。&lt;br /&gt;&lt;br /&gt;※ 私見だが、最初から checked と unchecked が峻別される Java の業界では比較的少なく、どちらかというと.NET 業界に多く見られる気がする。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-1967612127922278029?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/1967612127922278029/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/02/donotcatchgeneralexceptiontypes.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1967612127922278029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/1967612127922278029'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/02/donotcatchgeneralexceptiontypes.html' title='底辺プロジェクトの DoNotCatchGeneralExceptionTypes'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-8354764846017463735</id><published>2011-01-30T15:20:00.002+09:00</published><updated>2011-06-22T19:43:15.495+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C＃での例外処理コードの基本</title><content type='html'>C＃コーディングで例外をどう扱うか。&lt;br /&gt;&lt;br /&gt;普通はこうなる。&lt;br /&gt;&lt;pre&gt;&amp;lt;A.防止可能か？&amp;gt;&lt;br /&gt;  ├─(yes)─→ [B.防止するコードを書く]&lt;br /&gt; (no)&lt;br /&gt;  └→&amp;lt;C.予見可能か？&amp;gt;&lt;br /&gt;       ├─(yes)─→ [D. catch して処理するコードを書く]&lt;br /&gt;      (no)&lt;br /&gt;        ↓&lt;br /&gt;     [E. スルー]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;A. 防止可能か？&lt;/span&gt;&lt;br /&gt;例えば、「パラメータで null を渡されたら ArgumentNullException を投げる」ってドキュメントに書いてあったり、ソースコード上自明もの（バグも含む）だったり、例外発生の条件が分かっていて、そうならないようなコードを書ける場合は、防止可能と言う事になる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;B.防止するコード&lt;/span&gt;&lt;br /&gt;A を満たす場合に、例外を発生させないようにコーディングする。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;C.予見可能か？&lt;/span&gt;&lt;br /&gt;防止できず、つまり実行するまで分からないが、状況によっては発生する事が分かっている例外状況を、「予見可能である」とする。例えば、ファイルを開くときの FileNotFoundException など。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;D. catch して処理するコード&lt;/span&gt;&lt;br /&gt;C で可能性が認められた例外については、catch してハンドリングするコードを書く。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;E. スルー&lt;/span&gt;&lt;br /&gt;防止も予見もできないものについては、復旧処理のしようも無いので、無理にアプリを動かし続けて誤動作による事態悪化を招くより、スルーしてアプリが停止するに任せる。書いてもせいぜい、AppDomain の UnhandleException イベントくらい。&lt;br /&gt;&lt;br /&gt;この手順は、以下の URL で FxCop の開発者が詳説していたりもする。&lt;br /&gt;http://blogs.msdn.com/b/codeanalysis/archive/2006/06/14/631923.aspx&lt;br /&gt;&lt;br /&gt;まあ、普通のプログラマにとっては、いつも実践している通りの、言われるまでもない当たり前のコーディングじゃないだろうか。今更感満載で、「他にやり様あったっけ？ないでしょ？」てな感じになっちゃうと思う。&lt;br /&gt;&lt;br /&gt;で、これを踏まえた上で、例えば、メソッドの API リファレンスに例外が沢山書いてあったらどうしようとか、catch 節もちゃんとテストしましょうだとか、finally を活用しましょうとか、いろいろな細かい事が生じてくる。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;というのが、普通に計算機科学を勉強して、普通にプログラミングを習得して、普通にC＃を書いてる人の自然なコーディングプラクティスだと思うのだけど、底辺プロジェクトでは、この基本フローの段階で物言いがつく事がある。&lt;br /&gt;&lt;br /&gt;曰く&lt;br /&gt;「うちのアプリは何があっても落とさないポリシーだから、E のスルーは容認できない。未知の例外はもみ消して無かった事にするのが我々の流儀である。」と。&lt;br /&gt;&lt;br /&gt;・・・いや、それ、マジで言ってんのかと。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://yasutech.blogspot.com/2011/02/donotcatchgeneralexceptiontypes.html"&gt;次は、これについて考えてみる。&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-8354764846017463735?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/8354764846017463735/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/c_30.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8354764846017463735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/8354764846017463735'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/c_30.html' title='C＃での例外処理コードの基本'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2802456182855636023</id><published>2011-01-29T17:06:00.003+09:00</published><updated>2011-01-29T22:07:39.759+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><title type='text'>パターンカタログの私的ランキング（TOP 20）</title><content type='html'>1位から10位までは&lt;a href="http://yasutech.blogspot.com/2011/01/blog-post_29.html"&gt;前回&lt;/a&gt;書いた、独断と偏見によるパターンのランキングを、20位まで続けてみる。&lt;br /&gt;&lt;br /&gt;1位 GOFのパターン (100.0)&lt;br /&gt;2位 PoEAA (89.6)&lt;br /&gt;3位 Effective Java (86.4)&lt;br /&gt;4位 CodeSmell (85.3)&lt;br /&gt;5位 xUnitパターン (82.8)&lt;br /&gt;6位 アンチパターン (81.3)&lt;br /&gt;7位 POSA (79.1)&lt;br /&gt;8位 Effective C# (77.9)&lt;br /&gt;9位 アナパタ (69.5)&lt;br /&gt;10位 Enterprise Integration Patterns (67.7)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;11位 Implementation Patterns&lt;/span&gt;&lt;br /&gt;ベック の smalltalk イディオムの古典 &lt;a href="http://amazon.co.jp/o/ASIN/013476904X/yasuabe1984-22/ref=nosim"&gt;SBPP&lt;/a&gt; をベースに、言語を Java に代えて内容を調整したもの。個人的にはもっと普及しても良いと思うのだが。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;67.4&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;12位 Portland Pattern Repository / Wiki Wiki Web&lt;/span&gt;&lt;br /&gt;元祖 &lt;a href="http://c2.com/cgi/wiki"&gt;wikiwikiサイト&lt;/a&gt;。カタログとしてはイマイチ使いにくいが、有名人たちの過去の議論が読めたりして、意外とおもしろい。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;1&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;64.9&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;13位 『パターン言語』&lt;/span&gt;&lt;br /&gt;PLoP のパターンの選集、『&lt;a href="http://amazon.co.jp/o/ASIN/4797314397/yasuabe1984-22/ref=nosim"&gt;プログラムデザインのためのパターン言語&lt;/a&gt;』に掲載のパターン。ここでも挙げている他のパターン集に含まれているものが多い。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;64.1&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;14位 Patterns for Effective Usecases&lt;/span&gt;&lt;br /&gt;同名の&lt;a href="http://amazon.co.jp/o/ASIN/0201721848/yasuabe1984-22/ref=nosim"&gt;書籍&lt;/a&gt;より。ユースケース・ライティングの記念碑的傑作『&lt;a href="http://amazon.co.jp/o/ASIN/0201702258/yasuabe1984-22/ref=nosim"&gt;Writing Effective Use Cases&lt;/a&gt;』に書いてある内容の焼き直しがほとんどだが、パターン仕立てになっているのが良い。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;1&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;63.5&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;15位 SOA Patterns&lt;/span&gt;&lt;br /&gt;ネットで見られる良質な SOA のパターン集だが、不勉強にも、最近まで気づかなかった。これはいい感じ。 → [&lt;a href="http://www.soapatterns.org/masterlist_c.php"&gt;URL&lt;/a&gt;]&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;63.4&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;16位 Core J2EE Patterns&lt;/span&gt;&lt;br /&gt;Java EE x が J2EE だった昔のエンタープライズ・アプリのパターン集。今、読み返しても、意外と古くさい感じはしない。→[&lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/"&gt;URL&lt;/a&gt;]&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;63.4&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;17位 Patterns for Test-Driven Development&lt;/span&gt;&lt;br /&gt;ベックの傑作『&lt;a href="http://amazon.co.jp/o/ASIN/0321146530/yasuabe1984-22/ref=nosim"&gt;Test-Driven Development&lt;/a&gt;』の PART３。TDD のためのパターン集が収められている。&lt;br /&gt;&lt;br /&gt;これに限らずベックのパターン集は、パターンやプラクティスや単なる基本用語が、境界がよくわからないまま並列に解説されていて、カタログとしてはどうかと思うが、不思議と違和感無く読めて面白い。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;63.1&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;18位 コプリエンのイディオム本&lt;/span&gt;&lt;br /&gt;イディオム・カタログの発祥とも言われている『&lt;a href="http://amazon.co.jp/o/ASIN/4894715295/yasuabe1984-22/ref=nosim"&gt;C++プログラミングの筋と定石 &lt;/a&gt;』より。かなり古い本だが、これにもアンチ・イディオムが載っていて、当時の書評でもこれが重要って事で指摘されていた。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;61.7&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;19位 Workflow Patterns&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.workflowpatterns.com/patterns/"&gt;workflowpatterns.com&lt;/a&gt;で紹介されている、ワークフローのパターン。通常、パターンというと問題に対する解の事を指すが、これはどちらかというと解というより問題の方の定形って感じ。このうちの基本的なパターンは BPM の試験でも問われる。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;61.6&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;20位 Data Model Patterns&lt;/span&gt;&lt;br /&gt;アナパタでも参照されている分析レベルのモデリングの古典、『&lt;a href="http://amazon.co.jp/o/ASIN/0932633293/yasuabe1984-22/ref=nosim"&gt;Data Model Patterns: Conventions of Thought&lt;/a&gt;』より。アナパタ同様、これも図法がとっつきにくいが、自分でUMLなどを使って分かり易い図に起こすと理解が進む。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;59.3&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;★ ついてでに20位圏外&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/013476904X/yasuabe1984-22/ref=nosim"&gt;Smalltalk Best Practice Patterns&lt;/a&gt;』&lt;/span&gt; (58.2)&lt;br /&gt;言わずと知れた smalltalk イディオムの古典的名著。いろんな記事とか本とかから引用されていて教養的価値が高いけど、差し当たり仕事では smalltalk を使わない事もあり圏外。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;Enterprise Solution Patterns&lt;/span&gt; (57.8)&lt;br /&gt;ちょっと古いが、良く体系化されている。なのに何故かイライラする。理由は不明→[&lt;a href="http://msdn.microsoft.com/en-us/library/ff647095.aspx"&gt;URL&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;Effective C++&lt;/span&gt; (55.7)&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0321334876/yasuabe1984-22/ref=nosim"&gt;Effective C++: 55 Specific Ways to Improve Your Programs and Designs&lt;/a&gt;』&lt;br /&gt;Effective ナントカの C++版。最近、C++の案件やってないなあ・・・&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;Ajax パターン&lt;/span&gt; (53.7)&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0596101805/yasuabe1984-22/ref=nosim"&gt;Ajax Design Patterns&lt;/a&gt;』&lt;br /&gt;文字通りAjax のパターン。Ajax そのものの勉強にもなる。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;J２EEアンチパターン&lt;/span&gt; (46.8)&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/4822281981/yasuabe1984-22/ref=nosim"&gt;J2EEアンチパターン&lt;/a&gt;』&lt;br /&gt;この手のパターンは陳腐化しやすい。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;EJB Design Patterns&lt;/span&gt; (45.1)&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0471208310/yasuabe1984-22/ref=nosim"&gt;EJB Design Patterns: Advanced Patterns, Processes, and Idioms&lt;/a&gt;』&lt;br /&gt;これも Java の EoD 運動以前のものだから、さすがに古い。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;EJBアンチパターン&lt;/span&gt; (44.6)&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/4822281841/yasuabe1984-22/ref=nosim"&gt;EJBアンチパターン&lt;/a&gt;』&lt;br /&gt;これも EJB Design Patterns と同様古い。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:white;"&gt;AOPパターン&lt;/span&gt; （43.3）&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/1930110936/yasuabe1984-22/ref=nosim"&gt;Aspectj in Action&lt;/a&gt;』に掲載されている AOPパターンと AspectJイディオム。そこそこ面白いが、まだ数も少なく未成熟。 &lt;br /&gt;&lt;br /&gt;以上、「物」と「事」でいうと、「物」的なパターンを特に選び、「事」性が強い リファクタリングやプラクティスは入れないことにした。&lt;br /&gt;&lt;br /&gt;今回のは洒落で作った私的な順位だけど、工夫すればもっと客観的な点数付けができると思う。そうしたらスキル評価の尺度として、開発要員のアサインや調達の際に、ちょっと使えるかも。&lt;br /&gt;&lt;br /&gt;つうか底辺プロジェクトでは、GoF すら覚束ない人が多数派なので、切なくなってくるが・・・&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2802456182855636023?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2802456182855636023/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/top-20.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2802456182855636023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2802456182855636023'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/top-20.html' title='パターンカタログの私的ランキング（TOP 20）'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-864856281922619550</id><published>2011-01-29T03:31:00.006+09:00</published><updated>2011-01-30T13:59:54.269+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><title type='text'>パターンカタログの私的ランキング（TOP１０）</title><content type='html'>パターン・カタログ＝GoFのデザパタだと思ってる人をたまに見かけるが、実は結構、他にもたくさんある。&lt;br /&gt;&lt;br /&gt;以下、勝手に作ったパターンカタログのランキング。飽くまでも私的で主観的な尺度でポイントを付けた。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;1位 GOFのデザパタ&lt;/span&gt;&lt;br /&gt;言わずと知れたデザインパターンのバイブル、『&lt;a href="http://amazon.co.jp/o/ASIN/4797311126/yasuabe1984-22/ref=nosim"&gt;オブジェクト指向における再利用のためのデザインパターン&lt;/a&gt;』掲載されている、２３のパターン。まずはこれが基本かと。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;100.0&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;2位 PoEAA&lt;/span&gt; &lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/4798105538/yasuabe1984-22/ref=nosim"&gt;エンタープライズ アプリケーションアーキテクチャパターン&lt;/a&gt;』に掲載されている、いわゆる PoEAA （&lt;span style="font-weight:bold;"&gt;P&lt;/span&gt;atterns &lt;span style="font-weight:bold;"&gt;P&lt;/span&gt;atterns &lt;span style="font-weight:bold;"&gt;o&lt;/span&gt;f &lt;span style="font-weight:bold;"&gt;E&lt;/span&gt;nterprise &lt;span style="font-weight:bold;"&gt;A&lt;/span&gt;pplication &lt;span style="font-weight:bold;"&gt;A&lt;/span&gt;rchitecture）。2000年代初頭までのオブジェクト指向システム開発の流れを総括した上で、現在に至るその後の展望を示したパターンの金字塔。さすがに、もうそろそろ、若干の陳腐化が見られなくもないが。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;89.6&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;3位 Effective Java&lt;/span&gt; &lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0321356683/yasuabe1984-22/ref=nosim"&gt;Effective Java (2nd Edition)&lt;/a&gt;』掲載の Javaコーディングイディオム。Java プログラマは必携・必読かと。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;86.4&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;4位 CodeSmell&lt;/span&gt;&lt;br /&gt;ファウラーの『&lt;a href="http://amazon.co.jp/o/ASIN/4894712288/yasuabe1984-22/ref=nosim"&gt;リファクタリング本&lt;/a&gt;』に載っているアンチパターン。リファクタリング手法そのものより、むしろこっちの方が重要だと思う。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;85.3&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;4位 xUnitパターン&lt;/span&gt; &lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0131495054/yasuabe1984-22/ref=nosim"&gt;xUnit Test Patterns&lt;/a&gt;』で紹介されている UnitTesting のパターン。&lt;a href="http://xunitpatterns.com/"&gt;XUnitPatterns.com&lt;/a&gt;でも閲覧可能。これもアンチパターンの部分が重要。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;82.8&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;6位 アンチパターン&lt;/span&gt;&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0471197130/yasuabe1984-22/ref=nosim"&gt;AntiPatterns&lt;/a&gt;』掲載の、定番のアンチパターン集。ちょっと古いが、コーディングや設計に止まらず、プロジェクト管理などにも渡る広めのスコープをカバー。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;81.3&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;6位 POSA&lt;/span&gt;&lt;br /&gt;ブッシュマンの『&lt;a href="http://amazon.co.jp/o/ASIN/4764902834/yasuabe1984-22/ref=nosim"&gt;POSA本&lt;/a&gt;』(Pattern Oriented Software Architecture)に載ってる、アーキテクチャパターンの古典。1巻しか和訳されていないので余り知られていないが、&lt;a href="http://amazon.co.jp/o/ASIN/0471606952/yasuabe1984-22/ref=nosim"&gt;２巻&lt;/a&gt;も&lt;a href="http://amazon.co.jp/o/ASIN/0470845252/yasuabe1984-22/ref=nosim"&gt;３巻&lt;/a&gt;もある。いや、確か５巻くらいまであったかもしれない。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;79.1&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;8位 Effective C#&lt;/span&gt; &lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0321658701/yasuabe1984-22/ref=nosim"&gt;Effective C#&lt;/a&gt;』と『&lt;a href="http://amazon.co.jp/o/ASIN/0321485890/yasuabe1984-22/ref=nosim"&gt;More Effective C#&lt;/a&gt;』に掲載の C#のイディオム。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;77.9&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;9位 アナパタ&lt;/span&gt;&lt;br /&gt;ファウラーによる分析レベルのパターン集の古典『&lt;a href="http://amazon.co.jp/o/ASIN/4894716933/yasuabe1984-22/ref=nosim"&gt;アナリシスパターン&lt;/a&gt;』。モデルの図法が若干とっつきにくい。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;2&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;5&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;69.5&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-size:120%;color:white;"&gt;10位 Enterprise Integration Patterns&lt;/span&gt;&lt;br /&gt;『&lt;a href="http://amazon.co.jp/o/ASIN/0321200683/yasuabe1984-22/ref=nosim"&gt;Enterprise Integration Patterns&lt;/a&gt;』掲載のパターン。意外と知られていないが、ここで導入された図法、グレゴールグラムも含めて、EI 界隈では金字塔と言われるパターン集。SOA、ESBをやる人はほぼ必須知識に近いかと。&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:85%;"&gt;&lt;tr&gt;&lt;th width="60px" style="text-align:center;"&gt;実用度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;有名度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;使い勝手&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;教養度&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;面白さ&lt;/th&gt;&lt;th width="60px" style="text-align:center;"&gt;ポイント&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;3&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;4&lt;/td&gt;&lt;td style="text-align:right;padding-right:5px;"&gt;67.7&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://yasutech.blogspot.com/2011/01/top-20.html"&gt;→TOP20へ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;★ 補足&lt;/span&gt;&lt;br /&gt;上記のとおり、五つの評価軸について5段階評価して、ポイントに集計してランクをつけてみた。&lt;br /&gt;&lt;br /&gt;・実用度は、仕事で役に立つかという観点。個人的な職歴によるバイアスがかかっている。したがって、仕事では使わない smalltalk や最近現場では使っていないC++に関連するものは、点が低かったりする。&lt;br /&gt;&lt;br /&gt;・有名度は、各種の記事や著作から引用されてているのを目にしたり、同僚との会話の中に出てくる事が多いもの。これももちろん私的な環境に依存する。&lt;br /&gt;&lt;br /&gt;・使い勝手は、主にカタログとしての質。書式・体裁や、粒度、識別し易さなど。またダイアグラムやサンプルコード、パターン間のナビゲーションなども。&lt;br /&gt;&lt;br /&gt;・教養度は、他のパターンが前提的な知識として要求していたり、このパターンを知っていると他のパターンを理解し易いというもの。&lt;br /&gt;&lt;br /&gt;・面白さは、文字通り面白いという事。知的好奇心を刺激されたり、可能性が開けていく感覚があったり、思わぬ気付きがあって興奮したりとか、そういうやつ。&lt;br /&gt;&lt;br /&gt;評価軸自体にも、実用度に５点、有名度に３点、使い勝手に３点、教養度に２点、面白さに１点と言うように重みを付けた。&lt;br /&gt;&lt;br /&gt;点の集計は、一応技術者らしくフィボナッチスケールを応用してみた。１～５の点数をフィボナッチをもとにした数列｛21, 27, 34, 44, 55｝に変換して総合点を集計し、オール５だったときに100になるように調整した。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-864856281922619550?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/864856281922619550/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_29.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/864856281922619550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/864856281922619550'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_29.html' title='パターンカタログの私的ランキング（TOP１０）'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-5764723024340646131</id><published>2011-01-27T00:28:00.005+09:00</published><updated>2011-01-27T00:44:17.016+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><title type='text'>ソフトウェア品質の対概念</title><content type='html'>プロがで自分の職能分野の事柄を wikipedia で調べる事となると、何となく気恥ずかしさを感じないでもないが、たまに良い事が書いてあってちょっと嬉しい時がある。&lt;br /&gt;&lt;br /&gt;「&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%93%81%E8%B3%AA"&gt;ソフトウェア品質&lt;/a&gt;（&lt;a href="http://en.wikipedia.org/wiki/Software_quality"&gt;Software_quality&lt;/a&gt;）」で調べると、ちゃんと「&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%93%81%E8%B3%AA#.E3.82.BD.E3.83.95.E3.83.88.E3.82.A6.E3.82.A7.E3.82.A2.E8.A3.BD.E5.93.81.E5.93.81.E8.B3.AA"&gt;ソフトウェア製品品質&lt;/a&gt;（&lt;a href="http://en.wikipedia.org/wiki/Software_quality#Software_product_quality"&gt;Software_product_quality&lt;/a&gt;）」と「&lt;a href="http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%93%81%E8%B3%AA#.E3.82.BD.E3.83.BC.E3.82.B9.E3.82.B3.E3.83.BC.E3.83.89.E5.93.81.E8.B3.AA"&gt;ソースコード品質&lt;/a&gt;(&lt;a href="http://en.wikipedia.org/wiki/Software_quality#Source_code_quality"&gt;Source_code_quality&lt;/a&gt;)」に分けて書いてあった。&lt;br /&gt;&lt;br /&gt;ソフトウェアに関しては、一般的な意味での品質ーーーつまり「日本の精密機械の品質は・・・」なんて言うときの「品質」とは別の、もう一つの品質があるという事が、実はわりと普通の考え方なのだという証言が一つ得られた事になり、少しほっとした。更に少し調べると、ISO/IEC 9126-1:2001でも「内部品質」という形で定義されているらしい。不勉強だった。&lt;br /&gt;&lt;br /&gt;とは言っても、この二つの品質が互いに異なる別物だという考え方は、まだソフトウェア開発業界で常識となるには至っていないように見える。&lt;br /&gt;&lt;br /&gt;開発中の製品の品質について会議なんかで議論すると、こっちが後者の意味で話しているのに、しかも、どういう意味での「品質」か、ちゃんと前置きしてから語っているはずなのに、いつの間にか前者の話に流れて行ったりする。終いには「”品質”の話をしてるんだから、コードとか関係なくね？」みたいに返してくるから、こっちも「だ～か～ら～」みたいになってくる。&lt;br /&gt;&lt;br /&gt;大雑把に言うと、製品品質は売上に関わり、ソースコード品質は費用に関わる。つまり、製品品質は使う側の生産性を左右し、ソースコード品質は作る側の生産性を左右する。あるいは、製品品質の問題は消費者側で顕在化し、ソースコード品質の問題は生産者側で顕在化するとも言える。&lt;br /&gt;&lt;br /&gt;ある意味正反対の概念が、「品質向上」などと言ったスローガンの下で一緒くたに扱われるから、品質管理会議が何だか噛み合わない。いっそ別の言葉でもあれば良いんだけど、日本語でも英語でも適切な言葉が見当たらない。&lt;br /&gt;&lt;br /&gt;「今話している「品質」はソースコード品質の意味での「品質」なわけで、つまり（略）」みたいな面倒くさい断りを入れずに済む状況は、当分なくなりそうにない。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-5764723024340646131?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/5764723024340646131/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_27.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5764723024340646131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/5764723024340646131'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_27.html' title='ソフトウェア品質の対概念'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2935007646275259202</id><published>2011-01-26T00:14:00.002+09:00</published><updated>2011-06-22T18:22:27.116+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>リファクタリングの因果ループ</title><content type='html'>リファクタリングの効果をシステム・シンキングで考えてみる&lt;br /&gt;&lt;br /&gt;まず、もっとも近視眼的に原因 → 結果を考えるとこうなる。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_l6frM3dxqMU/TT7UMzYYKpI/AAAAAAAAAPA/IpN7RR7DcFI/s1600/refactor-sth1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 240px; height: 60px;" src="http://4.bp.blogspot.com/_l6frM3dxqMU/TT7UMzYYKpI/AAAAAAAAAPA/IpN7RR7DcFI/s320/refactor-sth1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5566119505892485778" /&gt;&lt;/a&gt;&lt;br /&gt;＋記号は、原因側の増加・強化が、結果側にプラスの効果をもたらす事を意味する。反対に、原因側の減少・弱化は、結果側にマイナスの効果を与える。－記号ならば、原因側の増加・強化が、結果側にとってのマイナスとなる。&lt;br /&gt;&lt;br /&gt;つまり、上図ではリファクタリングの実施が開発工数の増加をもたらす事を表している。逆に言うと、重複やらスパゲティコードやらの放置も、直接的には工数を減少させるとも言っている。&lt;br /&gt;&lt;br /&gt;これに、「ソースの体質」（ソースコードの読み易さ、書き易さ、使い易さ）と開発作業における「余裕」を付け加えて、因果関係のループを作ると以下の用になる。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_l6frM3dxqMU/TT7UNNROQGI/AAAAAAAAAPI/oD9rJJ4fs-Y/s1600/refactor-sth2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 260px; height: 140px;" src="http://3.bp.blogspot.com/_l6frM3dxqMU/TT7UNNROQGI/AAAAAAAAAPI/oD9rJJ4fs-Y/s320/refactor-sth2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5566119512841797730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;要するに、短期的には工数増加をもたらすリファクタリングが、ループを繰り返すに連れて効力を増して、次第に工数を減少させていく様子を表しているが、これを説明してみたい。&lt;br /&gt;&lt;br /&gt;解説のため、二つのループに分けると下図のようになる。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_l6frM3dxqMU/TT7UNa_7VSI/AAAAAAAAAPQ/Q2Opf3rDsqg/s1600/refactor-sth3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 280px; height: 280px;" src="http://1.bp.blogspot.com/_l6frM3dxqMU/TT7UNa_7VSI/AAAAAAAAAPQ/Q2Opf3rDsqg/s320/refactor-sth3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5566119516527351074" /&gt;&lt;/a&gt;&lt;br /&gt;上のループは－が一個（奇数個）なので、バランス・フィードバック・ループになる。&lt;br /&gt;&lt;br /&gt;つまり「リファクタする」→「工数増える」→「余裕が減る」→「リファクタさぼる」→「工数減る」→「余裕がでる」→「またリファクタする」→「・・・」という感じで、一周ずつ反転しながら繰り返して、適当な均衡点に落ち着いて行こうとする。&lt;br /&gt;&lt;br /&gt;下のループは－が二個（偶数個）なので、拡張フィードバック・ループになる。&lt;br /&gt;&lt;br /&gt;この場合、「リファクタする」→「ソースが改善される」→「だんだん工数が減ってくる」→「余裕が出る」→「もっとリファクタする」→「もっとソースが改善される」→「さらに工数が減ってくる」→「・・・」という自己強化的な繰り返しになる。&lt;br /&gt;&lt;br /&gt;ただしソースの体質改善が開発工数に影響を与える際、遅延（上図のコンデンサー記号）を生ずるのが一般的なので、ループの勢いは最初は弱い場合が多い。&lt;br /&gt;&lt;br /&gt;とは言っても、ループの効果は一方向的に増強されるのみなので、「リファクタ実施 → 工数増加」と言う短期的な効果を、いずれ結局は追い越す事になる。&lt;br /&gt;&lt;br /&gt;というのが、システム・シンキングで理屈をつけたリファクタの効果。&lt;br /&gt;&lt;br /&gt;※実は、ループによる効果の増加を待てないような使い捨て度の高いシステムでは、リファクタしたところで却って費用対効果が良くない事も、同時に示唆していたりする。&lt;br /&gt;&lt;br /&gt;ちなみに、リファクタしない場合の悪循環は、「リファクタさぼる」→「体質悪化」→「じわじわと工数増大」→「余裕が減る」→「リファクタしようにもできない」→「もっと体質悪化」→「さらに工数増大」→ ・・・、と言った感じ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2935007646275259202?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2935007646275259202/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_26.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2935007646275259202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2935007646275259202'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_26.html' title='リファクタリングの因果ループ'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_l6frM3dxqMU/TT7UMzYYKpI/AAAAAAAAAPA/IpN7RR7DcFI/s72-c/refactor-sth1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3581604145274969796</id><published>2011-01-25T01:01:00.002+09:00</published><updated>2012-01-04T21:59:20.546+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>GUI コードのUnitTest の例</title><content type='html'>こんな感じのしょうもないフォームがあるとする。DataGridView があり、A列と B列は数値を入力できる列で、C列は A - B の計算結果を表示する。&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_l6frM3dxqMU/TT2Y1PMkFWI/AAAAAAAAAO4/xXmK451M9eE/s1600/20110124-01.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 236px; height: 158px;" src="http://4.bp.blogspot.com/_l6frM3dxqMU/TT2Y1PMkFWI/AAAAAAAAAO4/xXmK451M9eE/s320/20110124-01.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5565772754879518050" /&gt;&lt;/a&gt;さて、このフォームには、C列の値が負のとき赤で表示するという振る舞いがあるが、果たしてこれをテスト駆動で書けるだろうか？TDD に慣れた人なら、普通にテストファーストで書くだろうけど、ハナからできないと決め付けてる人も意外と多い。そんな人が考えるテストはこんな感じ。&lt;ul&gt;&lt;li&gt;アプリケーションを起動する。&lt;/li&gt;&lt;li&gt;A列、B列に値を入力する。&lt;/li&gt;&lt;li&gt;C列の前景色が変わったことを確認する。&lt;/li&gt;&lt;/ul&gt;まあ普通の手動の動作確認と同じだけど、これを自動化テストコードとしては書けないから UnitTest は無理と言う。実際にはそういったテストコードも書けないことはないが、TDD の UnitTest ではそんなのは書く必要ないし、第一、テストの観点も目的も手法も違ってるから、むしろ書いてはいけない。&lt;a href="http://yasutech.blogspot.com/2011/01/gui-unittest_23.html"&gt;前に書いた HumbleView の作法&lt;/a&gt;でやると、例えばこんな風になる。&lt;pre class="prettyprint"&gt;[TestFixture]&lt;br /&gt;public class Form2PresenterTest&lt;br /&gt;{&lt;br /&gt;    public Form2Presenter presenter;&lt;br /&gt;    public Mock&amp;lt;IForm2&amp;gt; mock;&lt;br /&gt;&lt;br /&gt;    [SetUp]&lt;br /&gt;    public void SetUp()&lt;br /&gt;    {&lt;br /&gt;        this.mock = new Mock&amp;lt;IForm2&amp;gt;();&lt;br /&gt;        var view = mock.Object;&lt;br /&gt;        this.presenter = new Form2Presenter(view);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void SelectStyle_Plus()&lt;br /&gt;    {&lt;br /&gt;        TestSelectStyle(10, 5, CellStyle.NonNegative);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void SelectStyle_Zero()&lt;br /&gt;    {&lt;br /&gt;        TestSelectStyle(10, 10, CellStyle.NonNegative);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void SelectStyle_Minus()&lt;br /&gt;    {&lt;br /&gt;        TestSelectStyle(10, 20, CellStyle.Negative);&lt;br /&gt;    }&lt;br /&gt;    public void TestSelectStyle(int a, int b, CellStyle style)&lt;br /&gt;    {&lt;br /&gt;        //arrange&lt;br /&gt;        var rowData = this.presenter.RowDataAt(0);&lt;br /&gt;        rowData.A = a;&lt;br /&gt;        rowData.B = b;&lt;br /&gt;        //act&lt;br /&gt;        this.presenter.Update(0);&lt;br /&gt;        //assert&lt;br /&gt;        mock.Verify(v =&amp;gt; v.SetGridStyle(2, 0, style));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;見ての通り、Update()メソッドで行のインデクス（簡単のため0固定とした）を受け取った Presenter が、更新された A 列とB列の値に基づいてスタイルを選んで、セルの位置とともにビューに返すという流れになる。これを満たす IForm2 と Presenter のコードはこんな感じ&lt;pre class="prettyprint"&gt;public interface IForm2&lt;br /&gt;{&lt;br /&gt;    //･･･略･･･&lt;br /&gt;    void GridDataSource(List&lt;RowData&gt; list);&lt;br /&gt;    void SetGridStyle(int col, int row, CellStyle styleId);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Form2Presenter&lt;br /&gt;{&lt;br /&gt;    //･･･略･･･&lt;br /&gt;    public void Update(int rowIndex)&lt;br /&gt;    {&lt;br /&gt;        var rowData = this.list[rowIndex];&lt;br /&gt;        var cellStyle = rowData.C &lt; 0 ? &lt;br /&gt;                CellStyle.Negative : CellStyle.NonNegative;&lt;br /&gt;&lt;br /&gt;        this.view.SetGridStyle(2, rowIndex, cellStyle);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;やり方はいくつかあるが、ここでは色を System.Drawing.Color で直接指定する代わりに、列挙値 CellStyle を定めて使っている。この CellStyle 定数と実際にセルに設定する DataGridViewCellStyle オブジェクトのマッピングを保持しておくクラスも別途必要だが、自明なので省略。この辺りまで書くとテストも通る。後は、View と Presenter を関連付けるだけ。&lt;pre class="prettyprint"&gt;public partial class Form2 : Form, IForm2&lt;br /&gt;{&lt;br /&gt;    //…略…&lt;br /&gt;    private void dataGridView2_CellEndEdit(&lt;br /&gt;        object sender, DataGridViewCellEventArgs e)&lt;br /&gt;    {&lt;br /&gt;        this.presenter.Update(e.RowIndex);&lt;br /&gt;    }&lt;br /&gt;    public void SetGridStyle(int col, int row, CellStyle styleId)&lt;br /&gt;    {&lt;br /&gt;        this.dataGridView2[col, row].Style = CellStyleMap.StyleOf(styleId);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;前回と同様、View オブジェクト（Form2）は受身で丸投げなクラスで、余りテストの必要性が高くないほんの少量のコードを残して、その他の振る舞いのコードを Presenter に移した。こんな風に、一見いかにも GUI の最表層みたいな振る舞いでも、フォーム＝View を薄く薄くしていく事で、妥当な網羅性を備えた UnitTest が書けるようになる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3581604145274969796?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3581604145274969796/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest_25.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3581604145274969796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3581604145274969796'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest_25.html' title='GUI コードのUnitTest の例'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_l6frM3dxqMU/TT2Y1PMkFWI/AAAAAAAAAO4/xXmK451M9eE/s72-c/20110124-01.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2458408492418085530</id><published>2011-01-23T23:50:00.002+09:00</published><updated>2011-01-23T23:54:23.506+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>CIのプラクティス</title><content type='html'>以下、『&lt;a href="http://amazon.co.jp/o/ASIN/482228395X/yasuabe1984-22/ref=nosim"&gt;継続的インテグレーション入門&lt;/a&gt;』にのってるプラクティスのメモ&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;「始めよう」からのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;変更を起点としてビルドを実行する&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:120%;color:white;"&gt;「CIの紹介」からのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;頻繁にコードをコミットする&lt;/li&gt;&lt;li&gt;ビルドできないコードをコミットしない&lt;/li&gt;&lt;li&gt;ビルド失敗を速やかに修復する&lt;/li&gt;&lt;li&gt;開発者テストを自動化する&lt;/li&gt;&lt;li&gt;全てのテストとインスペクションを合格させる&lt;/li&gt;&lt;li&gt;プライベートビルドを実行する&lt;/li&gt;&lt;li&gt;ビルドが失敗したコードを取得しない&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;「変更を起点としたビルドの実行」からのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;ビルドを自動化する&lt;/li&gt;&lt;li&gt;コマンド１つでビルドを実行する&lt;/li&gt;&lt;li&gt;ビルドスクリプトをIDEから分離する&lt;/li&gt;&lt;li&gt;ソフトウェア資産を集中化する&lt;/li&gt;&lt;li&gt;一貫したディレクトリ構造を作成する&lt;/li&gt;&lt;li&gt;失敗しやすいビルドプロセスから始める&lt;/li&gt;&lt;li&gt;複数環境へのデプロイに対応する&lt;/li&gt;&lt;li&gt;インテグレーションビルドマシンを使用する&lt;/li&gt;&lt;li&gt;CIサーバを使う&lt;/li&gt;&lt;li&gt;手動インテグレーションビルドを実行する&lt;/li&gt;&lt;li&gt;短時間でビルドを実行する&lt;/li&gt;&lt;li&gt;段階的にビルドを実行する&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;継続的DBインテグレーションのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;DBインテグレーションを自動化する&lt;/li&gt;&lt;li&gt;ローカル環境でサンドボックスを使う&lt;/li&gt;&lt;li&gt;バージョン管理リポジトリを使ってDB資産を共有する&lt;/li&gt;&lt;li&gt;開発者にDBを変更する権限を与える&lt;/li&gt;&lt;li&gt;DBAを開発チームの一員にする&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;継続的テストのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;単体テストを自動化する&lt;/li&gt;&lt;li&gt;結合テストを自動化する&lt;/li&gt;&lt;li&gt;システムテストを自動化する&lt;/li&gt;&lt;li&gt;機能テストを自動化する&lt;/li&gt;&lt;li&gt;開発者テストを分類する&lt;/li&gt;&lt;li&gt;実行時間が短いテストを先に実行する&lt;/li&gt;&lt;li&gt;不具合に対してテストを書く&lt;/li&gt;&lt;li&gt;結合テストを再実行可能にする&lt;/li&gt;&lt;li&gt;一つのテストケースに一つのアサーションを書く&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;継続的インスペクションのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;コードの複雑度を下げる&lt;/li&gt;&lt;li&gt;継続的にデザインレビューを実施する&lt;/li&gt;&lt;li&gt;コード監査による組織標準の維持&lt;/li&gt;&lt;li&gt;コードの複製を減らす&lt;/li&gt;&lt;li&gt;コード網羅率を評価する&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;継続的デプロイのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;動作するソフトウェアを常にリリースできるようにする&lt;/li&gt;&lt;li&gt;リポジトリの資産にラベル付けをする&lt;/li&gt;&lt;li&gt;クリーンな環境を構築する&lt;/li&gt;&lt;li&gt;個々のビルドにラベルを付ける&lt;/li&gt;&lt;li&gt;全てのテストを実行する&lt;/li&gt;&lt;li&gt;ビルドフィードバックレポートを作成する&lt;/li&gt;&lt;li&gt;リリースのロールバックを可能にする&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:120%;color:white;"&gt;継続的フィードバックのプラクティス&lt;/span&gt;&lt;ul&gt;&lt;li&gt;継続的フィードバック手段を利用する&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2458408492418085530?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2458408492418085530/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/ci.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2458408492418085530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2458408492418085530'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/ci.html' title='CIのプラクティス'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-2633890763730867128</id><published>2011-01-23T01:38:00.005+09:00</published><updated>2012-01-04T21:59:48.600+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>GUI コードのUnitTest の基本形</title><content type='html'>こんなフォームがあるとする。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_l6frM3dxqMU/TTr-ExZ3fSI/AAAAAAAAAOw/dwo8dvqXE5U/s1600/20110122-01.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 216px; height: 77px;" src="http://3.bp.blogspot.com/_l6frM3dxqMU/TTr-ExZ3fSI/AAAAAAAAAOw/dwo8dvqXE5U/s400/20110122-01.PNG" border="0" alt="" id="BLOGGER_PHOTO_ID_5565039647504432418" /&gt;&lt;/a&gt;&lt;br /&gt;ツールボックスからコントロールを持ってきて置いただけの状態だが、これを&lt;div style="padding:0px 5px 0px 5px;border:1px dashed snow"&gt;右のボタンを押すとメッセージボックスが開いて、OK すると文字列"OK"、Cancel すると文字列"Cancel"が、左のテキストボックスに表示される&lt;/div&gt;ようにしたい。&lt;br /&gt;&lt;br /&gt;さて、この作業を TDD でやるとどうなるか。&lt;br /&gt;&lt;br /&gt;GUI アプリは UnitTest できないものと考えがちな人は、やはりここでもメッセージボックスに伴うユーザ・インタラクションを理由に UnitTest を諦める。&lt;br /&gt;&lt;br /&gt;実は、こういった場合の対処法は割と昔から研究されて、パターンとして広く知られているものも既にいくつかある。&lt;br /&gt;&lt;br /&gt;基本的な方針は、最小限のコードを残して、振る舞いに関する責務をテスタビリティの高い別のオブジェクトに移動してしまうというもの。&lt;br /&gt;&lt;br /&gt;そうやって、極薄にしたフォーム・コード（UnitTest はオプション）と、振る舞いを含む実質的な UI ロジック（カバレッジ100%）に分けることで UI 層全体としてのコード・カバレッジを満足のいくものにする。&lt;br /&gt;&lt;br /&gt;いろいろな変種パターンがあるが、さしあたり以下のように単純に実装してみる。&lt;ul&gt;&lt;li&gt;Form1 = view&lt;ul&gt;&lt;li&gt;あくまでも受動的に動くフォーム・クラス。&lt;/li&gt;&lt;li&gt;Presenter の指示により MessageBox を表示するものの、何も考えずに結果を Presenter に返すだけ。&lt;/li&gt;&lt;li&gt;イベントは Presenter に丸投げする。ただし無駄なパラメータは渡したりしない。また、フォーム上のコントロールのプロパティへのアクセッサを、必要最小限な分だけもつ。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Form1Presenter = presenter&lt;ul&gt;&lt;li&gt;次のような UI の振る舞いを担う。&lt;ul&gt;&lt;li&gt;View にメッセージボックスを表示させて、結果を受け取る。&lt;/li&gt;&lt;li&gt;受け取った結果に応じた文字列を View に表示させる。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;また、Presenter から Form1 へのアクセスは、以下のようなインターフェイスを通じて行う。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public interface IForm1&lt;br /&gt;{&lt;br /&gt;   string ResultText { get; set; }&lt;br /&gt;   bool AskOkOrCancel();&lt;br /&gt;}&lt;/pre&gt;※Presenter も interface を実装するような形にもできるが、オプション。&lt;br /&gt;&lt;br /&gt;まずは先にテストコードから&lt;br /&gt;&lt;pre class="prettyprint"&gt;[TestFixture]&lt;br /&gt;public class Form1PresenterTest&lt;br /&gt;{&lt;br /&gt;   private Form1Presenter presenter;&lt;br /&gt;   private Mock&amp;lt;IForm1&amp;gt; mock;&lt;br /&gt;&lt;br /&gt;   [SetUp]&lt;br /&gt;   public void SetUp()&lt;br /&gt;   {&lt;br /&gt;       this.mock = new Mock&amp;lt;IForm1&amp;gt;();&lt;br /&gt;       this.presenter = new Form1Presenter(mock.Object);&lt;br /&gt;   }&lt;br /&gt;   [Test]&lt;br /&gt;   public void HandleButtonClick_OK()&lt;br /&gt;   {&lt;br /&gt;       TestHandleButtonClick(true, "OK");&lt;br /&gt;   }&lt;br /&gt;   [Test]&lt;br /&gt;   public void HandleButtonClick_Cancel()&lt;br /&gt;   {&lt;br /&gt;       TestHandleButtonClick(false, "Cancel");&lt;br /&gt;   }&lt;br /&gt;   public void TestHandleButtonClick(bool isOk, string resultText)&lt;br /&gt;   {&lt;br /&gt;       //arrange&lt;br /&gt;       mock.Setup(v =&amp;gt; v.AskOkOrCancel()).Returns(isOk);&lt;br /&gt;       //act&lt;br /&gt;       presenter.HandleButtonClick();&lt;br /&gt;       //assert&lt;br /&gt;       mock.VerifySet(v =&amp;gt; v.ResultText = resultText);&lt;br /&gt;   }&lt;br /&gt;}&lt;/iform1&gt;&lt;/iform1&gt;&lt;/pre&gt;&lt;span class="Apple-style-span" &gt;※モックはMoqを使った&lt;/span&gt;&lt;ul&gt;&lt;li&gt;ビューに聞いてこさせたユーザの意図（isOk）に応じて、期待通りの文字列（resultText）が選択され、ビューに設定されることを検証している。&lt;/li&gt;&lt;li&gt;見ての通り MessegeBox もコントロール･オブジェクトも関係ないコードになっている。&lt;/li&gt;&lt;li&gt;実際には、いっぺんにテスト・コードを書いてしまわないで、ちょこっとテストを書いては本体コードを書くというような形になる。&lt;/li&gt;&lt;/ul&gt;で、その本体コードは以下&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class Form1Presenter&lt;br /&gt;{&lt;br /&gt;   private readonly IForm1 view;&lt;br /&gt;   public Form1Presenter(IForm1 view)&lt;br /&gt;   {&lt;br /&gt;       this.view = view;&lt;br /&gt;   }&lt;br /&gt;   public void HandleButtonClick()&lt;br /&gt;   {&lt;br /&gt;       this.view.ResultText =&lt;br /&gt;           this.view.AskOkOrCancel() ? "OK": "Cancel";&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;ここまで書けば取りあえずテストが通る。あと残ったのは、放置していた Form1 を含む Presenter との連携コード。&lt;br /&gt;&lt;br /&gt;こんな感じでフォームを実装する。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public partial class Form1 : Form, IForm1&lt;br /&gt;{&lt;br /&gt;   private Form1Presenter presenter;&lt;br /&gt;&lt;br /&gt;   public Form1()&lt;br /&gt;   {&lt;br /&gt;       InitializeComponent();&lt;br /&gt;   }&lt;br /&gt;   public bool AskOkOrCancel()&lt;br /&gt;   {&lt;br /&gt;       return DialogResult.OK == MessageBox.Show(&lt;br /&gt;           "OK or Cancel", "", MessageBoxButtons.OKCancel);&lt;br /&gt;   }&lt;br /&gt;   public string ResultText&lt;br /&gt;   {&lt;br /&gt;       get { return this.textBox1.Text; }&lt;br /&gt;       set { this.textBox1.Text = value; }&lt;br /&gt;   }&lt;br /&gt;   internal void Attach(Form1Presenter presenter)&lt;br /&gt;   {&lt;br /&gt;       this.presenter = presenter;&lt;br /&gt;   }&lt;br /&gt;   private void button1_Click(object sender, EventArgs e)&lt;br /&gt;   {&lt;br /&gt;       this.presenter.HandleButtonClick();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;span style="font-size:smaller;"&gt;この他、フォームを表示するところ（Program.csあたり）で、view を Presenter と関連付けるコードが必要だが割愛。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;こんな風に、実フォームでは MessageBox.Show() 等のユーザ・インタラクションと、コントロールへの必要最小限のアクセッサのみを書く。&lt;br /&gt;&lt;br /&gt;なんだか、もとのお題が小さすぎるから、コードを切り出したにもかかわらずフォームのコードが増えてしまっているが、実際の業務要件を満たすようなフォームだと、イベント・ハンドラに全部書くようなスタイルよりスッキリしたコードに、ちゃんとなる。&lt;br /&gt;&lt;br /&gt;こうしたフォーム・コードは、コード量も多くならないし更新の度合いも少ないし、テストの必要性はそれほど高くない。UnitTest を省略していい部分だと思うが、どうしても DeveloperTest を書きたければ TypeMock か Moleを使えばいい。後付でも問題ないし、テスト・コードも極簡単なものですむ。&lt;br /&gt;&lt;br /&gt;さらにフォームのコードを少なくするやり方もあるが、次の機会に。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-2633890763730867128?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/2633890763730867128/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest_23.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2633890763730867128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/2633890763730867128'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest_23.html' title='GUI コードのUnitTest の基本形'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_l6frM3dxqMU/TTr-ExZ3fSI/AAAAAAAAAOw/dwo8dvqXE5U/s72-c/20110122-01.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-3375952553312847646</id><published>2011-01-20T00:31:00.003+09:00</published><updated>2012-01-04T22:00:36.113+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTest'/><title type='text'>GUI アプリのフォームの UnitTest</title><content type='html'>UI 層のオブジェクトの UnitTest は簡単じゃない。&lt;br /&gt;それは否定しない。&lt;br /&gt;&lt;br /&gt;ただ、確かに一定の難易度があるにはあるけど、それを何とかする工夫が、かなり昔から研究され、いくつかはパターンとして提唱されて既にかなり広く知れ渡っている。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_l6frM3dxqMU/TTcC3lhYYOI/AAAAAAAAAOo/4Iv6vlQ_31Y/s1600/HumbleView2.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 199px;" src="http://4.bp.blogspot.com/_l6frM3dxqMU/TTcC3lhYYOI/AAAAAAAAAOo/4Iv6vlQ_31Y/s400/HumbleView2.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5563919018627719394" /&gt;&lt;/a&gt;&lt;br /&gt;それにも関わらず、巷の底辺プロジェクトでは、未だに「&lt;span style="color:yellow;"&gt;GUI 層に関しては専用の UI テスト・ツールでも使わない限り、UnitTest は不可能&lt;/span&gt;」なんて迷信が未だに根強い。（&lt;a href="http://yasutech.blogspot.com/2010/07/functional-test-unit-test.html"&gt;UI テスト・ツールを使ったテストを、UnitTest の代替物と考えている時点で駄目&lt;/a&gt;なんだが･･･）&lt;br /&gt;&lt;br /&gt;まあ、４・５年前までは雑誌とかでもそんな感じで言われてたし、未だにその頃の記事が技術系のサイトで閲覧できてたりするから、悪習が減らないのはそういった陳腐化した情報のせいもあるかもしれない。&lt;br /&gt;&lt;br /&gt;困った事には、そうした底辺プロジェクトでは何でもかんでも UI 要素のイベント・ハンドラ・コードに書いてフォームを巨大化させるのが常だから、全ソースの半分以上がフォームのコードだったりする。&lt;br /&gt;&lt;br /&gt;その上更に、大半の仕様変更がフォームにも影響を与えるものだったりするから、更新回数でいうとフォームのソースが 9割くらいにも達する。そういった、本来は最も UnitTest コードを書くべき部分でサボっておいて、大して変更頻度も高くない部分のカバレッジについて上がったの下がったの言ってるのを現場で見ていると、何とも切なくなってくる。&lt;br /&gt;&lt;br /&gt;取り合えず、まず基本はフォームのコードを分割する事。&lt;br /&gt;&lt;br /&gt;ユーザ･インタラクションや Windows のメッセージループが必要になる層（以下、View と呼ぶ）と、そうでない層に分ける。View をどこまで薄くするかという技法上の選択肢はあるが、とにかく薄くする。で、残りの部分について、View のインターフェイスに対しておもむろにモック･ツールを適用して、あとは普通に xUnit を使う。&lt;br /&gt;&lt;br /&gt;ここまででも UnitTest としては、そこそこの網羅率になる。更にカバレッジを完璧に仕上げたかったら isolation ツール（.net なら TypeMock や Moleなど）を使えば、View についても UnitTest が書けるが、これはオプションと考えて良いと思う。&lt;br /&gt;&lt;br /&gt;後で、実際のコード例を挙げてみる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-3375952553312847646?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/3375952553312847646/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3375952553312847646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/3375952553312847646'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/gui-unittest.html' title='GUI アプリのフォームの UnitTest'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_l6frM3dxqMU/TTcC3lhYYOI/AAAAAAAAAOo/4Iv6vlQ_31Y/s72-c/HumbleView2.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7693904062938597789</id><published>2011-01-18T20:45:00.002+09:00</published><updated>2011-01-20T00:55:48.440+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='品質'/><title type='text'>JSTQB認定テスト技術者資格試験のシラバス</title><content type='html'>去年の夏の終わり頃、&lt;a href="http://jstqb.jp/ "&gt;JSTQB&lt;/a&gt; という団体が認定するテスト技術者資格の試験を受けた。&lt;br /&gt;&lt;br /&gt;Foundation Levelという事で、上級者向けの Advanced Level (まだ始まっていない)とはおそらく違ってそれほどハードルは高くなく、プロならほとんどが受かる難易度だと思う。勉強の材料は、JSTQB のサイトで配布されているシラバスを使った。これをよく読めば大体受かるはず。&lt;br /&gt;&lt;br /&gt;実は、このシラバスがすごく良く出来ていて、受験者だけが読むのでは少しもったいない気がした。&lt;br /&gt;&lt;br /&gt;短い分量に、用語、基礎知識、各種テクニックから教訓まで、非常に上手くまとめられている。&lt;br /&gt;&lt;br /&gt;テスターはもちろんの事、開発者から PM、仕様担当者まで、広めの範囲の関係者一同で読み合わせて、認識を共有したりすると良いと思った。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7693904062938597789?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7693904062938597789/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/jstqb.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7693904062938597789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7693904062938597789'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/jstqb.html' title='JSTQB認定テスト技術者資格試験のシラバス'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7107410783244181541</id><published>2011-01-17T22:13:00.006+09:00</published><updated>2011-01-18T19:56:52.637+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti patterns'/><title type='text'>コピペ・プログラミングの善悪の境界</title><content type='html'>コピペ・プログラムは悪い事だと言われる。&lt;br /&gt;&lt;br /&gt;コピペ・プログラマは駄目人間だとも言われる。&lt;br /&gt;&lt;br /&gt;一方で、実際の現場ではコピペ・プログラミングは現実によく行われている。&lt;br /&gt;&lt;br /&gt;リーダが「追加が決まった例の機能は、コピペで済むからラッキーだね」なんて言って、PM と一緒に嬉しがったりする。&lt;br /&gt;&lt;br /&gt;当のプログラマも、「任務遂行のためならコピペも辞さない俺って、なんて冷徹なプロだろう」てな感じで、どこか得意げだったりする。&lt;br /&gt;&lt;br /&gt;どう言う事か？コピペは良いのか悪いのか。&lt;br /&gt;&lt;br /&gt;より正しく言うと、悪いのはコピペ自体ではなく、コピペにより生ずる重複コードの放置だと言える。古来より、共通コードはサブルーチン化すべしと言われてきたし、近年においても Merciless な Refactoring が強く推奨されている。&lt;br /&gt;&lt;br /&gt;要は、結果的に重複が解消されて、保守性が下がる事もリスクが増える事もなくなれば、コピペそのものは別にどうって事ない。&lt;br /&gt;&lt;br /&gt;もちろん現場の緊急事態においては、コピペ解消に要する数分～数十分を惜しんで保守性を犠牲にしリスクを高め、従って後になって無駄にコストばかり膨れ上がるという高利の負債を受け入れてもなお、一時も早くコミット／リリースせざるを得ない状況もある。&lt;br /&gt;&lt;br /&gt;しかしだからと言って、TODO コメントで重複コードである旨を表示して、後続のプログラマの注意を喚起するくらいの事ができないわけはない。&lt;br /&gt;&lt;br /&gt;それすらやらないという事こそ、もう言い逃れのできない不作為、無知、鈍感と言わざるを得ない。プログラムの仕事が分かってないという事になるのではないか。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;★まとめ&lt;/span&gt;&lt;ul&gt;&lt;li&gt;コピペしない ← OK&lt;/li&gt;&lt;li&gt;作業の流れで一旦コピペしても、重複は残さない ← OK&lt;/li&gt;&lt;li&gt;やむを得ず重複を残したが、他人が怪我しないように手は打った ← ギリOK&lt;/li&gt;&lt;li&gt;コピペでコードを重複させましたが、何か？ ← &lt;span style="color:red;"&gt;悪&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;★豆知識&lt;/span&gt;&lt;ul&gt;&lt;li&gt;かなり古い本だが『&lt;a href="http://amazon.co.jp/o/ASIN/0471197130/yasuabe1984-22/ref=nosim"&gt;AntiPatterns&lt;/a&gt;』でも、"Cut-And-Paste Programming"として、Clipboard Coding、Software Propagationといった別名と共に紹介されている。&lt;/li&gt;&lt;li&gt;『&lt;a href="http://www.amazon.co.jp/gp/product/0201485672?ie=UTF8&amp;tag=yasuabe1984-22&amp;linkCode=as2&amp;camp=247&amp;creative=1211&amp;creativeASIN=0201485672"&gt;Refactoring&lt;/a&gt;』 では、Code Smellのうちの"Code Duplication"として紹介されている。&lt;/li&gt;&lt;li&gt;以下、元祖 wikiwiki から&lt;ul&gt;&lt;li&gt;&lt;a href="http://c2.com/cgi/wiki?OnceAndOnlyOnce"&gt;OnceAndOnlyOnce&lt;/a&gt;：「書くべきコードは一度だけ、ただ一度きりのみ書きましょう」と言う、おそらく最も有名な重複防止の標語。&lt;/li&gt;&lt;li&gt;&lt;a href="http://c2.com/cgi/wiki?RefactorMercilessly"&gt;Refactoring Mercilessly&lt;/a&gt;：昔から XP で言われているプラクティス。特にコードの重複の解消を念頭においていると考えても良い。&lt;/li&gt;&lt;li&gt;&lt;a href="http://c2.com/cgi/wiki?DuplicatedCode"&gt;Duplicated Code&lt;/a&gt;：言わずと知れたコードの重複。&lt;a href="http://c2.com/cgi/wiki?CodeSmell"&gt;CodeSmell&lt;/a&gt;(駄目なコードの兆候)の最たるものとされている&lt;/li&gt;&lt;li&gt;&lt;a href="http://c2.com/cgi/wiki?CopyAndPasteProgramming"&gt;Copy And Paste Programming&lt;/a&gt;：ずばり今回のテーマ。冒頭で一応、プログラミング手法の一つとして中立的に紹介された後、なぜこれが駄目なのかと延々と批判が続く&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-7107410783244181541?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/7107410783244181541/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_17.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7107410783244181541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/7107410783244181541'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/blog-post_17.html' title='コピペ・プログラミングの善悪の境界'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-6039783816531317991</id><published>2011-01-16T23:59:00.006+09:00</published><updated>2011-06-09T10:41:55.139+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>アジャイル・ワナビーの観察 1</title><content type='html'>&lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt; は &lt;span style="font-weight: bold;"&gt;over&lt;/span&gt; を挟んで左辺と右辺を対置し、右辺より左辺に高い価値を置くという形式になっている。&lt;br /&gt;&lt;br /&gt;◆&lt;span style="color:red;"&gt;Individuals&lt;/span&gt; and &lt;span style="color:red;"&gt;interactions&lt;/span&gt; over &lt;span style="color:orange;"&gt;processes&lt;/span&gt; and &lt;span style="color:orange;"&gt;tools&lt;/span&gt;&lt;br /&gt;◆ &lt;span style="color:red;"&gt;Working software&lt;/span&gt; over &lt;span style="color:orange;"&gt;comprehensive documentation&lt;/span&gt;&lt;br /&gt;◆ &lt;span style="color:red;"&gt;Customer collaboration&lt;/span&gt; over &lt;span style="color:orange;"&gt;contract negotiation&lt;/span&gt;&lt;br /&gt;◆ &lt;span style="color:red;"&gt;Responding to change&lt;/span&gt; over &lt;span style="color:orange;"&gt;following a plan&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ただし原文を読むと分かるとおり、右辺の価値を認めた上で更に左辺の方がより重要だと言っているわけで、右辺を害悪や無価値なものと断じているわけではない。だから共にプラスの価値とした上での比較論、バランスの問題とも捉えられる。&lt;br /&gt;&lt;br /&gt;従って、右辺の重みを減らすなら、少なくともその効用が減少した分以上は、左辺に由来する効用によって補償されていなければならず、でなければプロジェクトに負の影響が生じてしまう。&lt;br /&gt;&lt;br /&gt;さてアジャイル開発者とは、投下したコストから得られる効用の比率が、右辺より左辺の方が高いと考える人であり、その具体的な手法を提示しているのが各アジャイル･プロセスといえるだろう。&lt;br /&gt;&lt;br /&gt;但し、その手法＝プラクティスは旧式の開発作法に比べ簡単だとは一概に言えず、それなりの知識と理解はもちろんの事、練習や工夫、或いは集中力が求められたりする（開発者としてはやり甲斐があるが）。&lt;br /&gt;&lt;br /&gt;ところが、よくあるワナビな現場やプロジェクトでは、左辺の効力を増加させるための努力によってではなく、単に右辺を等閑視する事によってアジャイル開発になる（＝生産性・品質が向上し変化に迅速に対応できる）なんて短絡的に勘違いしている人が未だに多い。&lt;br /&gt;&lt;br /&gt;以下、個別に見てみる。差し当たり、左辺に関するプラクティスの巧拙については割愛し、右辺がなおざりにされる状況だけを記述する。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:120%;font-weight: bold;color:white;"&gt;プロセスが閑却されるケース&lt;/span&gt;&lt;br /&gt;今時、ルールでガチガチに固めた単に監査のためだけにしかならないような重量プロセスもどうかと思うが、軽量プロセスって言葉もあるとおり、アジャイルだからといってプロセス不要って事にはなるわけがない。&lt;br /&gt;&lt;br /&gt;にも関わらず、なんちゃってアジャイルな現場では、この肝心のプロセスすら無視される。むしろ完全にその場しのぎの行き当たりばったりの仕事が「臨機応変」とさえ捉えられてしまう。&lt;br /&gt;&lt;br /&gt;で、たまに組織の上層部の思いつきで、「暫定」標準プロセスが適用されたりするが、長引くデスマの中で有耶無耶にされ、反省も（従って改善も）されないから、永遠に「下手の考え休むに似たり」の悪しきオリジナリティから卒業できない。&lt;br /&gt;&lt;br /&gt;反復型なのか非反復型なのかも判別できない、グダグダでノッペリした開発作業が、終わりの見えないまま続いたりする。&lt;br /&gt;&lt;br /&gt;（tools に関しては「ツールを減らせばアジャイルに近づく」的な勘違いは、特に見られない。但し、いわゆるアジャイル系･ツールの誤用・過信は非常に多い。これは、ここでのテーマと違うので割愛。）&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:120%;font-weight: bold;color:white;"&gt;文書が閑却されるケース&lt;/span&gt;&lt;br /&gt;文書の方が有効なコミュニケーション場面ですら、口頭＝喋りで全てを伝えたがる悪癖に染まった現場も多い。伝える側は、無駄な文書化の手間が省けたと最初は思うが、何度も別の相手に同じ事を伝えている事に気づいて、初めて愚策だったと悟る（鈍感な人は、それすらいつまでも気づかないが）。&lt;br /&gt;&lt;br /&gt;また、後のリファクタ・軌道修正が困難な箇所の設計すら個人の脳内で完結し、"Working software" が出来上がって来るまで他人のチェックが入らないため、後で一同頭をかきむしる事になるのもこのケース。（そもそもワナビな現場では、ユニットテストが後回しで、CIもロクに実現されていないから、そもそもアジャイルの意味での"Working software"と言えるのか疑問でもある。）&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:120%;font-weight: bold;color:white;"&gt;顧客交渉が閑却されるケース&lt;/span&gt;&lt;br /&gt;最低限の契約交渉すらないというのは、つまりプロジェクト初期においては単なる安請け合い、末期には単に怒った顧客の言いなりに過ぎないケースがほとんどで、「協働」の本来の姿とはかけ離れている。&lt;br /&gt;&lt;br /&gt;初期の交渉がテキトーだから、気が付いたときには既に顧客はイライラあるいは激怒し始めており、理性的にスコープを定める事ができなくなっていたりする。結局はプロジェクト外の上層部の長が出向いて、改めて不利な立場で交渉せざるを得ない羽目に陥る。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:120%;font-weight: bold;color:white;"&gt;計画が閑却されるケース&lt;/span&gt;&lt;br /&gt;ここまで記述してきたような、プロセスもなくスコープも定まっていないプロジェクトだと、従うべきプランなんて存在しようもなく、その場その時のアドホックな状況に反射的に反応しているだけとなる。&lt;br /&gt;&lt;br /&gt;一応、後の変更を前提とした暫定プランが策定されたりもするが、ノウハウの蓄積の無い未熟な現場では合理的判断の根拠も無く、単なる思考停止の所産だったりする。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;･･･というのが wannabe agile な現場でよく見かける愚行の一端。&lt;br /&gt;&lt;br /&gt;====&lt;br /&gt;&lt;a href="http://agilemanifesto.org/"&gt;http://agilemanifesto.org/&lt;/a&gt;を見ると 2001 とあるから、そろそろ10年になるらしい。&lt;br /&gt;&lt;br /&gt;既にアジャイル・プロセスを導入して成功している現場に定住している人から見ると、上述のような現場が未だにあることに驚くかもしれないが、一般的には意外と多い普通の状況だったりする。自分もリーマンショック以降、初めて知る事になったわけだが・・・。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7701765455905567301-6039783816531317991?l=yasutech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yasutech.blogspot.com/feeds/6039783816531317991/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://yasutech.blogspot.com/2011/01/1.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6039783816531317991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7701765455905567301/posts/default/6039783816531317991'/><link rel='alternate' type='text/html' href='http://yasutech.blogspot.com/2011/01/1.html' title='アジャイル・ワナビーの観察 1'/><author><name>xad</name><uri>http://www.blogger.com/profile/08236506946114465953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7701765455905567301.post-7821964352659681342</id><published>2011-01-16T04:39:00.003+09:00</published><updated>2011-01-16T05:17:40.700+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# のアンチイディオム</title><content type='html'>ソフトウェア開発の様々なテーマについて、それぞれパターンやイディオムやベストプラクティスがあるけど、まずはアンチパターンを避ける事が優先度が上で順序も先だと常々思う。&lt;br /&gt;&lt;br /&gt;というわけで、書いてはいけない C#コードを『&lt;a href="http://amazon.co.jp/o/ASIN/0321658701/yasuabe1984-22/ref=nosim"&gt;Effective C#&lt;/a&gt;』と『&lt;a href="http://amazon.co.jp/o/ASIN/0321485890/yasuabe1984-22/ref=nosim"&gt;More Effective C#&lt;/a&gt;』から抜粋してみた（"m"が付いた番号が "More"の方）。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 09: Avoid Conversion Operators in Your APIs&lt;/span&gt;&lt;ul&gt;&lt;li&gt;変換演算子の定義は避ける事。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 26: Avoid Returning References to Internal Class Objects&lt;/span&gt;&lt;ul&gt;&lt;li&gt;オブジェクトが保持している別のオブジェクトを外に晒すのは避ける事&lt;/li&gt;&lt;li&gt;特にコレクションなんかで、C#に限らず散々言われ続けてきた悪いコーディング&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 16: Avoid Creating Unnecessary Objects&lt;/span&gt;&lt;ul&gt;&lt;li&gt;無駄なオブジェクトの生成を避ける事&lt;/li&gt;&lt;li&gt;文字列の構築での string の使用 ⇒ StringBuilder を使う事&lt;/li&gt;&lt;li&gt;高頻度で呼ばれるメソッド内でのオブジェクト生成 ⇒ メンバ変数や定数への格上げを検討する事&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 32: Avoid ICloneable&lt;/span&gt;&lt;ul&gt;&lt;li&gt;ICloneableの実装は避ける事&lt;/li&gt;&lt;li&gt;パッと見の印象ほどには意外と使えないインターフェイスだったりする&lt;/li&gt;&lt;li&gt;どうしても使うときは、基底クラスでコピーコンストラクタを定義した上で、sealed クラスのみで使う事。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 33: Use the new Modifier Only to React to Base Class Updates&lt;/span&gt;&lt;ul&gt;&lt;li&gt;new モディファイアの使用は避ける事&lt;/li&gt;&lt;li&gt;外部のライブラリに含まれる基底クラスの変更により、それを継承している派生クラスで定義の衝突が生じるような稀なケースなどもあるが、そのときでもなるべく避ける事。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item 34: Avoid Overloading Methods Defined in Base Classes&lt;/span&gt;&lt;ul&gt;&lt;li&gt;基底クラスで宣言されたメソッドをオーバーロードするのは避ける事&lt;/li&gt;&lt;li&gt;こんなコードで、、、&lt;pre style="background-color:snow;color:black;padding-left:10px"&gt;class B1 {}&lt;br /&gt;class D1: B1 {}&lt;br /&gt;class B2 { void Foo(D1 p) {...} }&lt;br /&gt;class D2: B2 { void Foo(B1 p) {...} }&lt;/pre&gt;、、、D2.Foo() に D1 オブジェクトを渡すと、どっちが実行されるか意外と迷う。更に generics が絡むともっと面倒になる。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Item m07: Do Not Create Generic Specialization on Base Classes or Interfaces&lt;/span&gt;&lt;ul&gt;&lt;li&gt;generic メソッドを特化するオーバロードは避ける事&lt;/li&gt;&lt;li&gt;例えば以下のようなコードで、、、&lt;pre style="background-color:snow;color:black;padding-left:10px;"&gt;class Base {}&lt;br /&gt;class Derived : Base {}&lt;br /&gt;class Foo {&lt;br /&gt;   public static vo
