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

2012年6月5日火曜日

[Selenium 2] Try & Error集 2

バージョン2.21で「Could not load native events component」例外が発生する

確認バージョン:Selenium 2.21
ブラウザ:Firefox 9, 12
対処法:バージョン上げる ※2.22検証済

以前書いたマウスホバー実現方法のエントリで、
「現時点のSelenium最新バージョン2.21はFirefox12に対応していないようで動かず…」
と書きましたが、あの後Firefox9で試してみたら9でも例外発生しました。
発生した例外は以下。

org.openqa.selenium.InvalidElementStateException: Cannot perform native interaction: Could not load native events component.

発生元は以下。

上記以外でも発生するかもしれません。

発生原因は不明。きっとSeleniumのデグレでしょう。バージョン2.22にしたら解決。

「MoveTargetOutOfBoundsException」例外の対処法

確認バージョン:Selenium 2.18
ブラウザ:Firefox 9
対処法:事前にターゲットが見えるように座標やウィンドウサイズ調整する

ただリンクやボタンをクリックするだけといった何てこと無い処理で、時々以下例外が発生することがありました。

org.openqa.selenium.interactions.MoveTargetOutOfBoundsException: Element cannot be scrolled into view

ターゲットがウィンドウ領域外にある場合、見える位置まで自動スクロールしてから処理が実行されるのですが、どうも時々スクロールがうまくいかない場合がある模様。
スクロールが原因なのであれば、JavaScriptで座標調整したり、ウィンドウ最大化するなどして、予めターゲットが見えるような状態にしておけばよい。

※サイト・ページによっては、上記コードが働かない場合がありました。原因不明。

FirefoxのJavaScriptを無効化できない!

確認バージョン:Selenium 2.18, 2.21
ブラウザ:Firefox 9
対処法:不明

それっぽいメソッドがあったので使ってみたのですが、falseセットしても無効化できず。

OSやブラウザバージョンとか他にいろいろ設定して試してみてもダメだった。

[Selenium 2] Firefox起動時のポートロック待ち時間変更方法

試した環境

  • ブラウザ:Firefox 9
  • JDK 6
  • Selenium 2.18, 2.21, 2.22
  • Windows 7 64bit

ある日のこと、Seleniumテストケースを並行して数十個同時にスタートした時、以下の例外が発生した。

org.openqa.selenium.WebDriverException: Unable to bind to locking port 7054 within 45000 ms
…

調べてみると、どうもSeleniumはブラウザプロセス起動する時にTCP7054番ポートをロックするらしく、このポートのロックを一定時間待っても獲得できない場合に上記例外が発生する模様。ちなみにロックはプロセス起動したら開放されるっぽい。

この値はFirefoxBinaryクラスのtimeoutプロパティの値で、デフォルトでは45秒。変更したい場合は以下のように、タイムアウト値を設定したFirefoxBinaryオブジェクトをコンストラクタに渡せばよい。

同時にCapabilitiesオブジェクトも使いたいんだけど…

例えばプロキシを使用する場合は、以下のようにCapabilitiesを使用する訳ですが…

FirefoxDriverのコンストラクタには、FirefoxBinaryとCapabilitiesをパラメータとするものが用意されていません。どうしたらいいんでしょう。Help me...的な事を当初書いていたら、hutyaoさんからコメント欄にてご教示いただけました。ありがとうございます!
CapabilitiesオブジェクトにFirefoxBinaryを入れる

それと、プロキシ設定はCapabilitiesオブジェクトではなくFirefoxProfileでも指定可能だよってことも教えていただきました。

<非推奨>
FirefoxDriverのソースからメソッドコピペするというダッサイ方法
僕の頭ではこんな方法しか思いつきませんでした…

以下のimport文とメソッドをコピーし、適当なクラスに貼り付けてください。アクセス修飾子はprivateなので、適宜変更してください。

そしてFirefox起動ロジックは以下のような感じで。

僕は上記コピペメソッドや一連の生成ロジックはFactoryクラスに持たせています。

コピペなんてDRYの原則に反してるじゃねぇか!って方はSeleniumのソース弄ってください。僕としては、コピペ元はjarの中のソースなんで別にいいかなって思いますけど。

※繰り返しますが当節の方法は非推奨です。

2012年5月27日日曜日

[Selenium 2] Try & Error集

「window is null」例外対処法

確認バージョン:Selenium 2.2
ブラウザ:Firefox 4
対処法:バージョン上げる ※2.15以降検証済

見てお分かりの通り、かなり古いバージョンでのお話ですが…
コードを実行していたら、突然「window is null」的な例外が発生し、キャッチしてfinally節でWebDriver#close()してるのにブラウザ閉じないという現象に遭遇した。
残念ながら例外メッセージはメモが見つからなかったのでお見せできませんが(何分古いバージョンのお話なもので…)、以下みたいなのだったっけな…
Handling “Selenium (WebDriver) Exception: this.getWindow() is null” ~ Nishant Verma
org.openqa.selenium.WebDriverException: this.getWindow() is null

恐らくブラウザウィンドウの参照を見失ってアクセスできなくなったとかそんな感じの事なんでしょう。

発生原因は不明。ただ発生するページ・しないページがハッキリしていたので、ページ構造とかDOCTYPEとかが関係しているのかもしれない。
対処法は見つからず。ただバージョンを2.15に上げたら全く発生しなくなった。

リッチテキスト要素(iframe)スイッチ例外対処法

確認バージョン:Selenium 2.15・2.18
ブラウザ:Firefox 9
対処法:JavaScript使って入力

ブログの記事エディタのような所謂リッチテキストエディタへの文字入力で遭遇したトラブル。
エディタの実態はiframe要素だったので、定石に従って以下のように書いたら…例外発生。

発生した例外は確か以下(「確か」ですみません…)。
org.openqa.selenium.WebDriverException: Permission denied for to get property HTMLDocument.compatMode


発生原因は不明。「compatMode」とかあるので、これももしかしたらDOCTYPEが関係しているのかも(申し訳ないですが未検証)。
対処法は、JavaScriptでinnerHTMLプロパティセットするというNotスマートな方法しか見つからず。

ちなみにSeleniumバージョン2.2だと発生しませんでした。はいそうです、前述の「window is null」対処によるデグレです。

要素クリックでの「Permission denied」対処法

確認バージョン:Selenium 2.15・2.18
ブラウザ:Firefox 9
対処法1:リターンキー送出
対処法2:フォーカス(orマウスホバー)してからクリック ※効き目無い場合あり

ボタンやリンクを普通に「WebDriver#click()」したら発生。例外は前述のiframeのものと同じです。これも発生するページ・しないページはハッキリしていました。
対処法は以下の通り。

ちなみにこれもSeleniumバージョン2.2では発生しませんでした。


2012年5月6日日曜日

[Selenium 2]マウスホバーの実現方法

いい加減にSelenium2ネタを消化してきます。
今回はマウスホバーの実現方法です。ただ最初に断っておきますけど、ページの作りか何かの影響を受けているのか、ページによっては全くマウスホバーイベントが発生しない場合がありました。もし100%確実に成功させる方法をご存じの方がいましたらご教示ください!

試した環境

  • ブラウザ:Firefox 9
  • JDK 6
  • Selenium 2.18
  • Windows 7 64bit
SeleniumとFirefoxのバージョンはちょっと古めとなっていますが、多分バージョン11とかでも大丈夫だと思います。
このエントリ書く当たって自宅PC環境で試してみたんですけど、現時点のSelenium最新バージョン2.21はFirefox12に対応していないようで動かず…

Actionsオブジェクト使用する方法(ただし非推奨)

Actions#moveToElementで実現できます。できるんですけど…

これだとマウスホバーがキープされません。よって「マウスホバーで動的に表示されたメニューをクリック」したい場合、以下のコードではダメです。

正しくは以下のコードです。ホバーとクリックを間髪入れずに連続実行しています。

「正しくは」といったものの、上記はただ連続実行しているだけで結局ホバーキープはできていないので、厳密には正解ではありません。実際、ホバー後のクリックが間に合わずにエラーとなってしまったケースが多々ありました。
補足
もしかしたらActions#clickAndHold()使えばいいかもしれん(厳密にはマウスホバーではないけど)。けど前述の通り自宅環境だとSeleniumが動かないので試せない。

ホバーキープしたい場合はDefaultSeleniumかますのが確実

以下の方法だとホバーキープされました。

ただし、冒頭でも述べましたが、これだとそもそもマウスホバーイベントが全く発生しないケースが少ないですがありました。
あと、z-indexが正しく解釈されないのか、動的表示したメニューをクリックしたとき、メニューではなくその奥にある要素がクリックされてしまうということも。

何かSelenium WebDriverってまだまだバグが多いな…何か忘れたけどびっくりするようなデグレが発生してた事もあったような。

参考

2010年9月12日日曜日

ちょっとは暑さがマシになった夜のJava系小ネタ

Log4j、ログのローテートに失敗。原因はlog()メソッド?

プログラマとして社会に踏み出して5年目となる今年、ようやくLog4jを使用するシステムに巡り会えた(※1)。つっても、我々にはLoggerやAppender設計・製造する権限はなく、元請けが昨年製造・全社標準として採択されたjarを使わされるだけの立場なのだが。

言われた通りに組み込んで使用していると、不具合発生。ログファイルは1日ごとにローテーションする設定なのだが、日付が変わってもローテーションされず。さらに、出力済みのログファイルの中身を確認したところ、ある時刻までのログが全く出力されていない(その時刻以降は問題無く全て出力されているが)。

で、調べてみたら、以下の記事発見。java-jaの方でしょうかね。前述の通り日付ローテーションと言うことで、まさにこのAppender使っていた。原因はこいつか?別のAppenderに変更して試したところ…状況変わらず、暗礁空域へ…いや、待て。よくよく考えたら、標準ログ以外のログも出力する要件があり、いくつかのLoggerを自作していたのだが、自作の方はDailyだろうが何だろうが、ローテートに失敗したことは一度も無かった。ということで、不具合の原因はコンポーネント側にあると考えるのが順当だ。ということで、提供元に調査依頼を出した。

完全に我が社の責任範囲外の事象だが、そのコンポーネントのソースコードがjarと一緒に提供されていたので、ちょっと覗いてみた。…空のcatchブロックだらけじゃねぇか。例外殺しやがって、こりゃ発見遅れるわけだ、ったく…
正常にローテートされている自作Loggerと異なる部分を探してみる。すると、ログ出力するのに使用しているメソッドに違いが見られた。自作の方はinfo()とかdebug()とかログレベルの名称を冠したものを使用しているのだが、提供されたものはlog()メソッドを使用している。この違いが原因なのか?log()メソッドの部分をinfo()とかに替えて試してみたかったが、何かのクラスが足りなくてコンパイルできず、試行は断念…

Tomcat5.5にて、<jsp:useBean>タグでJasperException発生の原因

…Tomcatは5.0だったかもしれん…

過去最悪の仕事環境でのお話。JSP+サーブレットというアーキテクチャのシステム(Struts等のフレームワークは未使用)で、本番環境でのサーブレットコンテナは商用のあまり聞いた事のないやつ。そのサーブレットコンテナは、無償開発版といったものが無いので、皆サーバー環境でデバッグしていたのだが、リンク先記事にある通りコードがグダグダ。ステップ実行とかできないのは厳しすぎるので、ローカルにTomcat環境作ることにした。Javaのバージョンは我が社の案件にしては珍しく5.0だったので、Tomcatは5.5をチョイス。

環境構築して実行してみると…当節見出しの通りの不具合が発生。しかし、全ての<jsp:useBean>の箇所で発生するのではなく、決まったBeanでのみ発生している模様。これらBeanの共通点を探してみると…引数なしコンストラクタが定義されていないことが判明。

次に、JSPから変換されたJavaコードを確認してみた。<jsp:useBean>の箇所は、以下のロジックに変換されていた。
  1. 引数なしコンストラクタでBeanをインスタンス化
  2. setter・getterにて値の遣り取り
つまり、1.で未定義のコンストラクタが使用されて例外が飛んだっぽい。

JavaBeansの必要要件である「publicで引数なしのコンストラクタを実装」を行っていなかったために起こった悲劇であった。
コードレビューってやっぱ必要だよね。

正規表現メモ

範囲指定子の「-」。これ、括弧内([])の先頭か末尾に定義した場合、リテラルとして扱われる…ということを先月知りました。はぁ~…(自分に溜息)


※1
ちなみにJava5.0に巡り会うのには4年かかった。
人月計算とExcelとスーツの世界」はホント石橋を叩きすぎだ(それとも我が社の案件が極端なのか?)。

2010年2月15日月曜日

[Trac Lightning]静的HTMLの配置場所~さらば、J2SE 1.4日本語ドキュメント

以下フォルダに配置すれば、「http://{インストールURL}/{ファイル名}」でアクセスできる。
{Tracルート}\CollabNetSVN\httpd\htdocs

ちなみに上記フォルダには「Trac Lightningについて」ページが「index.html」として置いてあります。



現在の仕事では、上記フォルダにダウンロードしたJDK 1.4の日本語ドキュメントを置いています。
1.4の日本語ドキュメントは、Web上にはもういないんですよね…アーカイブページに置いてあるのは英語だし…

てか、いい加減1.5以上に携わりてぇよ!
新規開発案件なのに、今時Javaは1.4でブラウザはIE6って…

2009年12月12日土曜日

[Java]Calendarクラスは可変オブジェクト

StringやBigDecimalオブジェクトといった所謂『不変オブジェクト』を使っていて、「値が変わらない!」と嘆いたことは、大抵1度くらいは経験した事があると思う(ベテランになってもたま~にやってしまう…)。特に、C言語のポインタの例でよく出てくる、以下のように引数の値を変更する例。

メソッド呼出元の値をメソッド内で書き換えるという作りは宜しくないと思うので、この『不変オブジェクト』という概念はナイスだと思います。引数をメソッド内で弄り倒しても、呼出元の値は何の影響も受けない。
そういうわけで、不変オブジェクトに慣れてくると、何の躊躇も無しに引数をメソッド内で弄り倒してしまいがちです。しかし、『不変オブジェクト』と言われる以上、当然『可変オブジェクト』も存在します。この可変オブジェクトを不変オブジェクトと同じ感覚で弄り倒してしまうと、後で血ヘドを吐く事になりかねませんので、注意が必要です。はい、先月の僕がそうでした(いや、すぐに気付きましたけど…)。

先月の僕が遭遇した可変オブジェクト、それはCalendarクラスです。Calendarインスタンスを引数で渡し、引数と同じ年月・日付はその年月の月末日であるCalendarインスタンスを返すというメソッドを作成しました。初版のソースは以下。


ホント馬鹿です。正しくは以下でした。


不変オブジェクトと可変オブジェクトの見分け方は、そのインスタンスの値を弄くるメソッドの戻り値の有無で大体判別できると思いますが、どうなんでしょう。ていうかドキュメント読めって話ですが。

戻り値有り:不変オブジェクト
戻り値無し:可変オブジェクト


※「値を弄くる」ことができないのが不変オブジェクトなので、上の言い方は適切ではありませんが…

いやはや、前回のBigDecimalといい、4年目にして今更こんな事言っているようじゃ、やっぱり俺まだまだ初級だわ。細かい処理がラッピングされた、某フレームワークのライブラリでばかり組んできたので、基本が抜けてしまっている。フレームワークの功罪というやつか?(勉強不足と言われたら、返す言葉も無いですが…)

おまけというか個人的メモ

月末日付取得
getActualMaximumを利用。Calendar.DATEを引数に指定する事で、その年月が取り得る日付の最大値、つまりその年月の月末日付を返す。使い方は上の例を参照。
日付間日数取得
Calendarオブジェクトが内包しているDataオブジェクトを利用する。Date#getTime()で1970/1/1 00:00:00(GMT)からのミリ秒数を取得できるので、これの差分を日単位に変換すればよい。尚、Date#getTime()の戻り値long型。

[Java]BigDecimalクラス 小数値生成時の留意事項

指定した値のBigDecimalオブジェクトを生成する場合は、以下のようにコンストラクタの引数に値を指定するわけですが

小数値を指定する場合、以下のように数値で渡してしまうと、2進数で表現できない値の場合は誤差が発生してしまいます。

誤差発生を防止するには、文字列として渡さなければならない。

おまけというか個人的メモ

BigDecimal同士の値比較にはcompareToメソッドを使用する。
文字列で比較するequalsと異なり、compareToは値で比較するので、例えば10と10.0は等しいと見なされる。

2009年11月22日日曜日

スードラの下のバリア、プログラマの下のコーダー

現在社会人4年目、27歳。今のところプログラマとしてのキャリアのみで、SE経験を中々積む事ができておらず、自分の行く末を非常に危惧している。以前からのオフショア化の波に加えて、昨今のクラウドやSaaSの台頭により、プログラミング以下の仕事すらどんどん減少していく状況である。エンドユーザーとの交渉スキル等、SE経験で得られるスキル無しでは生き残れないだろうから。

うちの会社、SEのパイは一応あるにはあるのだけど…少ない。プライム案件で直接エンドユーザと遣り取り可能なポジションであれば尚更(大抵は、プライムであってもお客さんの情報システム部までしか接触できない模様)。さらにその少ないパイは、どうも社員の大半を占めるおっさんCOBOLerに優先して割り振っているみたいなんだよな。実際、上期の中間面談で「枠は無い」って言われたし、同期や1~2年上の先輩の様子見てても難しそう…。周りを蹴落とすぐらいの力がお前に無いからだ!と言われれば返す言葉も無いですが…ただ、一つ言い訳させて貰いますと、

若い社員にSE枠を付与

あぶれたおっさんCOBOLerはプログラマ枠へ

しかしこの人達、年功序列制度のせいで現在高給

さらに、オープン系言語等の再教育コストがかかる。
てか基本的に勉強する気がない。

追加コストを払ってまで、高給取りを単価の安いPGとして働かせるのは利益率悪すぎ

SE枠はおっさんで

…多分、こういう事情もあるのだと思います。
他には、僕はプログラマとしては(うちの会社の中では)かなり生産性が高いので、お客さんやプライムベンダのペースに振り回されるSEとしてより、プログラマのままとしておいた方が全体最適だ、というのもあるかもしれない。

はい、前述の通り、僕はプログラマとしては(うちの会社の中では)いい仕事してきたんです。また、SEが作ってきた仕様・スケジュールに対し「このA機能を先に作った方が、かくかくしかじかで効率いいと思いますよ」とか「B機能の○○ロジックは規模がでかいので、1機能として切り出して分業させた方がよいのでは?」等、周りに比べたら積極的に発言してきた方だと自負していますし。「これでもまだ足りないのか?」「相当パイが少ないのか?」とずっと思い悩んでいた最中、最近ふと疑心暗鬼に取り憑かれた。
「できる人間だからこそ、SE経験積ませて貰えないのでは?」と。

というのは、僕が新人の頃の新人歓迎会にて、つまり歓迎されてた時「できる人間はすぐ辞めるんだよね~」と言われたからだ。新人研修での成績がズバ抜けていたらしく、また入社前にソフトウェア開発技術者資格を取得済みだったこともあり、『できる人間』と見なされたらしい。「何でうち(の会社)来たの!?」ってのもあったな。もうホント度肝抜かれましたよ。新人歓迎会でそんなこと言うか!?
つまり、僕が思うに「いつ辞めるかしれない『できる人間』に、貴重なSE経験を積ませるのは勿体ない」という考えが根底にあるのではないかと。
完全なる僕の思い込みであれば、それは本当に会社に対して申し訳ございません!って話ですが、でもそういう思い込みが発生してしまっている時点で、会社を信頼できていない事が浮き彫りに…

ということで、そろそろ転職を考えないといけないのかなと思い始めている。まぁ、この大不況にSE経験無しが飛び出した所で仕事なんて見つかるわけないだろうから、すぐには動くつもりはないですが。ただ準備だけはしておこうと、最近、これまでの技術経歴の棚卸しをしました。で、それによって発覚した驚愕の事実。

「俺、Java初級じゃねぇか!」

よくよく考えたら、仕事ではオブジェクト指向プログラミング(以下、OOP)した記憶が無く、手続型ロジックしか経験無いことに気付いたんですよ。で、Javaプログラマの初級・中級の定義を調べてみたら、わんくまの方がこう言っています。
「Javaはコーディングができるという初級者と、プログラミングができるという中級者の間に大きな壁があります」
「…クラスを利用できる初級者とクラスを作れる中級者・上級者との間の壁…」

どうやら、OO使ってクラス設計してない内は初級だと。Javaで手続き書いているだけなら初級だと。そういう内はプログラマではなくコーダーだと。
はい、僕、クラス設計したことなく、手続き書いているだけの、コーダーです…

この3年半、様々なJava案件を行ったり来たりしてきたのだが、殆どの案件が「プログラミング不要!」「OO不要!」を謳っている内製向け商用フレームワークを適用した案件だった。OOPの概念は無く、ただ手続きを羅列していくだけの作業。UMLとかの『クラス図』を見た事がないという事実が、OO使ってない事を物語っている。ていうか、FWに依存する画面系はともかくとして、共通部品くらいはOOで作ればいいものを、設計担当者が悉くOOを使おうとせず(そもそも分かってない?)。部品のロジックパターン毎にクラス分割して多態性使って呼出部品切り替えればいいところを、分割単位はメソッド、呼出切替はif文…

フレームワーク特有のスキルはかなり身についたが、スキルって言っても『可能・不可能なこと』『向き・不向きなこと』は何かとか、あとは設定パラメータをどれだけ知ってるかってなもんで、とてもスキルなんて言える代物じゃない。それに何より、マイナー(※1)。上司は「マイナーだから競合相手がいなくて良い!」って言ってたけど…単純に情けない話だと思うし、それに繰り返すが『内製向け』FWなので、お客さんも徐々に内製にシフトしており、確実に発注減ってきてますよ!今年夏の現場なんか、詳細設計すらやらせてもらえなかったんですけど!
※1:懇親会とかで聞いてみるんですけど、まあ知ってる人いませんね。唯1人知ってた方は「使いにくい!」って仰ってました…

実務経験   :3年半
経験言語   :Java 約3年 ※但しOOP、クラス設計、5.0以上の経験無し
他は.NET系を少々
フレームワーク:それどこの?

何てこった、俺、空っぽじゃねぇか。市場価値なんて無いに等しい。SEはおろか、プログラマですらなく…スードラの更に下に実はバリア(アンタッチャブル)という最下層階級がある事を知った時並の悲しみ、と言ったら大袈裟だけど…

果たして俺は這い上がれるのだろうか?



そんな俺にも、やっと中級者へのステップアップのチャンスが。今月仕事はピュアJavaによる計算ライブラリの基本設計~単体テスト。基本設計にはクラス設計も含まれている。バージョンも初めての5.0。よっしゃ!計算ロジックは5パターンあり、全パターンで共通のロジックもあるので、これは継承と多態性の使い処だ。計算パターン毎にパラメータが異なるので、それらはそれぞれBeanクラス作って…といった感じで、今月はいつになく張り切って楽しんでいます。

ただなぁ…プロジェクト規約でクラス名を『ABCDX(0~9の連番)』とIDみたいにしなきゃいけないんですけど、その『0~9の連番』ってあるように、クラス数10個以下に抑えないといけないっぽいんですよ。前述の通り、計算パターンで5あり、それぞれのパラメータ用のBean作ったらもう在庫切れちゃうんですけど…『規約』というより『制約』だなこりゃ。全く。制約があって燃えるのは恋愛だけだっつーの。
あと単純に、Beanのクラス名がIDみたいな名前だと、分かりにくいったらありゃしない。『囚人クラス』と呼んでますよ。

ちなみに、JUnitも初めて仕事で使いました。やっぱり再テスト時は物凄く便利ですね。心置きなくリファクタしまくれる。けど、テストコードは単体テスト仕様書とは見なされない…

2009年11月3日火曜日

システム開発アンチパターン~旧バージョンのロジックを残すな!

『旧バージョンのロジックを残す』とはどういう事か、まあ大体想像つくと思いますが、一応説明させて頂きますと『新ロジックの側にコメント化して残す』という事です。
僕の会社の例では、以下に示すような定数CONST_Aの値を変更する場合(言語はJava)、

従来のロジックはコメント化し、その上に修正ID・修正者・修正日付等の情報をこれまたコメントで追加し、旧ロジックの下に新ロジックを追加します。


修正前後の差分がソースコードだけで確認できるので一見良さ気です。そのソースコードの修正が絶対に1回までしか発生しないのであれば、これでも良いでしょう。でも現実はそんな訳ありません。長い間メンテして何回も修正されていくと、以下のようにカオス化し、ソースコードが見にくく(醜く)なっていきます。

例ではただの定数宣言部でしたが、計算等を行っているような業務ロジック部分が例のような状態になっていたらもう最悪です。現バージョンのコードが旧ロジックの中に埋もれてしまい、ロジックの流れを追ったりするのに非常に邪魔になります。今年夏に担当した、当エントリを書くきっかけとなったシステムでは、ソースの総行数7000行中旧ロジック3000行という超大作がありましたよ。そのままだと現バージョンのロジック追うのが大変だったので、コメント行の色を深紅のバラ色に変更して追いましたよ。そしたら目がチカチカして堪りませんでしたよ。

今時、Subversion等のバージョン管理ツールという非常に便利な無償ツール使えば、ソースの修正履歴・差分の確認行えるので、旧ロジックは残さず排除すべきです。さらにRedmine等のプロジェクト管理ツール(厳密にはBTS)とバージョン管理ツール連携させれば、修正要件との紐付けもバッチリです。

ちなみに、そのシステムはバージョン管理ツール導入してたんですけどね。2007年にCVSを(遅っ!しかもSVNじゃないのかよ!)。弊害しか生み出さないこんな運用を、何で未だに行っているのか分からない(実際、担当したプログラマは全員が「間違ってる!」と言ってたし)。恐らく『修正IDでgrepして修正箇所を一括確認したい』要するに『楽して確認したい』というのが理由ではないかと僕は予想してました。

4年以上もこんな運用してきて誰も改善してこなかったのが非常に悲しい。いや、改善提案してきたけど通らなかっただけか?とにかく、僕は上司に改善を申し入れました。すると以下のの答えが返ってきました。
「ピンポイントでそのロジックの修正者、修正日付、修正理由を調べたい」
つまり『ソースコードからの修正要件の逆引きがしたい』という事のようです。うーん、結局『楽して確認したい』って事ですよね。ソースコード見るだけで修正要件確認したいと。一々修正台帳やCVSのコミットログからトレースしたくねえよと。そりゃそちら側としては楽で良いかもしれませんが、その為だけにソースコードを醜くし、修正難易度を上げ、それにより修正工数・デグレ発生度アップし、品質低下させるなんて、馬鹿げている。そもそも『ソースコードからの逆引き』なんて、多分バグった時の責任追及時に行うのでしょうけど、そんな機会しょっちゅうあるもんなんですかね?

やっぱり結局は『修正IDでgrepして一括確認』したいのが本音のような気がする。でもこのやり方では修正コメントに修正ID含めるの忘れた場合、確認漏れが発生してしまいます。ていうか実際にありました。しかもその修正が原因でデグレ発生してやがんの・・・。結局、修正箇所の確認は一つ一つバージョン比較して行うしかないと思います。そして確認の際は、前述の様にデグレが発生していないかも確認するため、修正した部分だけでなくメソッド単位で確認すべきだと僕は思います。

ただ、このシステムの場合メソッドの行数が数百~千行だという・・・

2009年9月6日日曜日

システム開発アンチパターン~メソッドのパラメータに配列使うな!

この秋の情報処理技術者試験ですが、「システムアーキテクト」試験を受験します。論文書かなきゃいけないので、ネタ探しにこれまで携わったプロジェクトに関しての個人メモを見返しました。えっと、1年目から愚痴ってるなぁ~(悲)。一部紹介しますと
  • 「ながら」仕事をする。音楽聞きながら、メッセンジャーしながら、2ch見ながら・・・。そういうことしながら仕事するギークがいるらしいが、それとは訳が違う。だって低品質だもの。
  • 残業時、夕食に出かけて1時間半近く戻ってこない。しかし我が社の勤怠制度では、休憩時間は見なしで固定45分(残業時は+30分)であり、5時間休憩しても休憩無しでもその時間で固定。当然、1時間以上夕食してても、その間の残業代はきっちり支払われる。ふざけんな!
  • 今時(当時2006年)、オープン系システムの開発&デバッグ端末でメモリ512MBってどういうこと?
  • 共通部品で「すべて置換」されたせいでデグレ発生。
...etc。
また殆どのプロジェクトにおいて、エビデンスの見てくれに無駄に手間を掛けさせることへの不満や、他人のソースコードの低品質に対する悪態をついています。今従事しているプロジェクトで苛つかされてるのと全く同じ嘆きもあり。

ちなみに、現在のプロジェクトのシステムは別の会社が作ったものであり、僕の会社作ではないです。余所でも同じ事をしているということは、結構やってしまいがちな事なのかな。であれば、同じ過ちを繰り返させないためにも、過ちによる悲しみを増やさない為にも、ここで一部ご紹介します。アンチパターン(やってはいけないこと)として。

メソッドのパラメータ数が多いからといって、パラメータにHashtableやString[]を使用してはいけない

※これはオブジェクト指向言語に関してです。
商品情報をDBに登録するメソッドがあり、登録値をパラメータとして渡すのですが、それの作りが以下のようになっていました。ちなみに言語はJavaです。

もうね、訳が分かりません。何番目に何が入っているかなんて分かりません。せめてインデックスを定数化しておけと。いや、そう言う問題じゃない。配列で渡しては駄目(ArrayList等も同様)。この他によく使われるのがHashtableなのですが、これも良くない。存在しないキーでget()しても、コンパイルエラーも実行時エラーも発生しないので。
折角オブジェクト指向言語使っているんだから、クラスの形で渡しましょう。これならメソッド名見ただけで何の値か分かる。


return値に関しても同様です。要するに、値の受け渡しにはクラスを使いましょうということです。

以上、超弩級低レベルな話でした。
もう一つどうしても紹介しておきたいことがあるのですが、それはまた別の機会に。