2010年7月17日土曜日

せっかくのJavaなんだから、せめて利点を生かそうよ

現在参画させてもらっている開発プロジェクトは、StrutsのWEBアプリケーション。前回、素晴らしいほどにJavaっぽくない、と言いましたが、なぜそう思ったのかというと、それはものすごく数多くあるクラス群の中で、「abstract」「Interface」で始まるクラスが一つもないから

つまり、全部がStrutsが提供する基底クラスを継承したクラスか、ただのクラスのみ。それこそ、CとかPerlとかのCGIでよくね?という感じ。考え方が、「オブジェクト指向」ではなくて「共通関数指向」とでも言うべきか。
だからなのか何なのか、ビックリするぐらい冗長で、たとえば同じ処理でもPCからのリクエストをさばくActionクラスと、モバイルからのリクエストをさばくActionクラスがほぼ同じコードで2つ、存在している。
そんな感じで、各リクエスト処理の数×2(PC&モバイル)のクラスがズラズラ!っと並んでいるわけである。
よくもまぁ、こんな長くて同じ内容のコードを大量に作って不思議に思わなかったもんだ。死ぬほどメンテしにくい、っつうかデグレ頻発すると思うんだけど…。

と愚痴っていてもしょうがないので、まさか他にそんなプロジェクトはないよね、と思いつつ、これが何かの役に立てばと思いながら「こんなときは、とりあえず抽象クラスにまとめちゃえば?」という例を。

まとめる前(悪い例)


たとえばほとんど同じような処理をしている「PcReqAction」(A)と「MobileReqAction」(B)があったとして、この冗長な2つのコードを何とかしたい場合を考えてみます。(網掛け太字の部分だけが違う)


(A)PcReqActionの内容


//Actionクラスを継承して、PcReqActionクラスを宣言
public final class PcReqAction extends Action{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest req,
HttpServletResponse res) {

ExActionForm eaf = (ExActionForm)form;
//beanから値を取得したりする処理を記述
int val = eaf.getValue();

//データベースに接続したりしてみる
DataBaseUtil db = DataBaseUtil.getDB();

//データ検索など、ロジックを実行する
MyLogic logic = MyLogic.getInstance();
int ret = logic.execMyLogic(db,val);

//PC固有の処理
execSomething(ret);

//データベース接続を終了したり
db.close();

//遷移先を指定
return (mapping.findForward("success"));
}
}



そして同じような、

(B)MobileReqActionの内容


public final class MobileReqAction extends Action{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest req,
HttpServletResponse res) {

ExActionForm eaf = (ExActionForm)form;
//beanから値を取得したりする処理を記述
int val = eaf.getValue();

//データベースに接続したりしてみる
DataBaseUtil db = DataBaseUtil.getDB();

//データ検索など、ロジックを実行する
MyLogic logic = MyLogic.getInstance();
int ret = logic.execMyLogic(db,val);

//モバイル固有の処理
execAnything(ret);

//データベース接続を終了したり
db.close();

//遷移先を指定
return (mapping.findForward("success"));
}
}




冗談だと思ったでしょう?
「いやいや、ここまでまったく同じようなのなんてあるの?」と思われるでしょうが、あったんです、実際。
(Actionクラスの中にアレコレ書いちゃってたりExeption拾ったりしていないのはこの際、流してください)
さてこれを、Abstractなクラス(C)を使って書いてみましょう。

Abstractでまとめた後(上記よりは良い例)


(C)AbstraceReqActionの内容

public abstract class AbstractReqAction extends Action{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest req,
HttpServletResponse res) {

ExActionForm eaf = (ExActionForm)form;
//beanから値を取得したりする処理を記述
int val = eaf.getValue();

//データベースに接続したりしてみる
DataBaseUtil db = DataBaseUtil.getDB();

//データ検索など、ロジックを実行する
MyLogic logic = MyLogic.getInstance();
int ret = logic.execMyLogic(db,val);

//PC/モバイル固有の処理→抽象メソッド
execPeculiarFunction(ret);

//データベース接続を終了したり
db.close();

//遷移先を指定
return (mapping.findForward("success"));
}


//子クラスにやらせる処理。具体的な内容は子クラスに記載。
abstract void execPeculiarFunction(int arg){};
abstract void execPeculiarFunction(int arg);
}



書き直した(A)PcReqActionの内容

public class PcReqAction extends AbstractReqAction{
public void execPeculiarFunction(int arg){
//PC固有の処理を記述
}

}



書き直した(B)MobileReqActionの内容

public class MobileReqAction extends AbstractReqAction{
public void execPeculiarFunction(int arg){
//モバイル固有の処理を記述
}

}




いやはや、(A)も(B)も随分とスッキリしましたねぇ。そしてこれで、いわゆるDB云々やらの共通処理は1つにまとまったので、メンテもやりやすくなりました。
さらに例えば今後、スマートフォン固有の処理が必要だ!となったら、同じように抽象クラスを継承して専用クラスを作り、スマートフォンに固有の処理だけ書けばよくなります。
Javaやってる人にはくだらなすぎる内容でしたが、きっと世のプロジェクトの1%ぐらいには意外と役立つ内容なんじゃなかろうか、と期待しつつ、投稿してみます。


あと、ボク自身も決してオブジェクト指向が得意なわけではないけど、以前同僚が「コードを書いててif文が出てきたら、そこはクラス化出来る可能性がある」と言われて、それが意外と今でも役立ってたりします。

誰かの何かの参考になれば幸い。


あと、「いや、オマエもそれ、オカシイってww」というツッコミも大歓迎(というか教えてくださいお願いします)。

2010年7月8日木曜日

大相撲名古屋場所の視聴率が気になる

一連の野球賭博問題を受けて、NHKが大相撲名古屋場所の生中継をしないことに決定したそうですが、ダイジェスト版は平日、土日とも午後6時台に30分程度放送するとのこと。

これは、ダイジェスト版の視聴率が凄いことになりそうですね。

「希少性は欲求を生む」というのはマーケティングでも基本ですが、まさしく今回は、毎日毎日(悪い情報とはいえ)大相撲のニュースを浴びせられ、さぁ、取り組みは行うが中継はしない。でもちょっとだけダイジェストは流すよ、という、この上なく希少性を煽るパターン。こうなったら、普段見てない人だって見ちゃう可能性が高い。
なんなら、会場に行ってtwitterで実況したら結構な数のフォローがつくことでしょうね(笑)


ボクはほとんど相撲には興味がないのですが、ぜひこの機会に業界全体で体質を改善し、真面目に頑張って名古屋場所に出場する力士の方々には(逆に視聴率が上がるであろう)このタイミングでしっかりと普段の稽古の成果を発揮してもらい、相撲の良さ、というものを感じさせてくれれば嬉しいですね。

個人的には、もう組織の上の方にいる執行部(?)を取っ払って、貴乃花親方に仕切りなおしてもらいたい。

久々のJavaコーディン・・・グ・・・?

まぁ、ホントに稀に見る放置プレイである。いや、まぁそんなもんなのか?しかし、システムの構成も登場人物も使い方もわからないし、説明もない。
聞けば返ってくるが、聞かないと何の説明もない。忙しいのはわかるけど、一通り30分程度でいいので流しの説明ぐらいあるもんなんじゃあなかろうか、というのは世知辛い受託開発プロジェクトの現場では甘い考えなのか。

とりあえずそんなことはどうでもいいとして、要するに唯一メンテナンスされ続けているというDBの設計書とソース、実際に動く開発環境の画面とにらめっこしながら、どんな登場人物がいて、何をするシステムなのか、ということを読み解いていくわけです。むくむくと胸の底から湧き上がってくる不毛さを押さえつけながら。

今回のWEBシステムはStrutsベースのServlet。最近ではWEBアプリというと大抵PHPですが、このシステムは生まれてから長いので、Servletで引っ張り続けているようです。

それもどうでもいいとして、パッケージの一覧もクラス図もないのでソースを読むわけですが、素晴らしいほどにJavaっぽくない。

今日、夕方になってようやく追いかけ始めたソースは、247行目で if(hoge) と評価が入り、これに対応する else が出てくるのが 777行目。それも、正常な処理とエラー処理の切り分けだけって・・・

Exception投げればよくね?

さらに中ではif文がガンガン、ネストしていて読みにくい・・・(泣)

というか、ひとつのクラスで「777行目」が出てきている時点で、Javaな人は驚かれることかと思います。せめてクラスを分ければ、もうちょっと読みやすくなりそうなんだけど、一瞬、Javaであることを忘れます。

ただ、逆に言うと「手続き型」な流れで書かれている分、5年ぶりにペンを執った、いや、キーボードを叩いた(?)ボクとしては、あちこちクラスを追いかけまわさないで済むので実は逆にありがたかったりする、という効用を発見。

最終的に、要件を満たした機能がバグなく動けばOKな世界ではあるから、メンテナンスがしやすければソースが美しいかどうかはこの際、関係ない。

今日は読んだだけだったけど、明日からいよいよ書く予定。
なんかワクワクする。

2010年7月1日木曜日

心機一転、初日。の、トラブル

やっと会社員という形態を卒業しました。
晴れて今日からフリーランス。

今日は早速、週2日ほどお邪魔する新しい現場に朝9時から出社して、貸与いただいた開発用PCのセットアップ。
新しい現場とはいえ、同僚が長くいる開発プロジェクトなので、その人にサーバーのアドレスや手順などをもらって進める予定。だったが、その彼、およびプロジェクトのリーダーが朝から本番トラブルでまったく手が空かず。
結果、午前中は放置プレイ。まぁ、仕方ない。よくあることさ。

出来るところから始めようと、以下を実施。
(1)IP Messagerのインストール
(2)メールの設定
(3)既にインストール済の環境確認(誰かの名残りっぽい)
 →Eclipse
 →Apache
 →Tomcat
 →PostgreSQL


(1)IP Messagerのインストール
インストーラを使って入れようとするも、「Program Filesにコピーをできない」とエラー終了。む。この環境ちょっと怪しい?
仕方ないのでexeを直接起動して、スタートアップフォルダにショートカットを手で作成してセットアップ。

とりあえずこれで同僚とメッセできるようになったものの、しばらくするとその同僚から「おまんにメッセが送れんのじゃがの」と口頭連絡。一度こちらから送ると双方向通信が可能に。ファイアウォールでポートを開けきれてない感じ。うむむ。怪しい。


(2)メールの設定
同僚が、テンパってる合間にメールサーバーの情報をくれたのでOutlook Express(最も嫌いなメーラー)をセットアップ。受信はできたが送信できず。どうやら認証が必要なSMTPだったようで、その設定を試しにしてみたら無事送信もOK。誰も教えてくれない環境だと、知っている人が見たら1分で終わることが10分も20分もかかる。嗚呼。

(3)Eclipse
もともとインストールされているEclipse(europa)を試しに起動しようとすると、スプラッシュが一瞬表示されるだけで落ちる。
ぬ?
VMが複数バージョンインストールされているわけでもないから、起動の仕方に迷っているわけでもなさそうだ。一応、VMを指定してコマンドラインから起動してみると、「JVM terminated. Exit code=-1」。
昔とった杵柄で、eclipse.iniを編集しようと思ったら、今度は「このファイルは別プロセスで使用されているため上書き禁止です」とか言われる。別プロセスって誰?タスクマネジャーで見てもEclipse(=Java)プロセスはいないから、このファイルを掴んでるやつなんていないはずなんだか…。いろいろ見てると、自分で作ったファイル以外は全部、削除もファイルの移動もできない。
ファイルの所有者が、もともとこのPCを使っていた人のもの??という推論のもと、同僚から現場のリーダーにお願いしてもらってもとの人のアカウントを教えてもらいログオン。
が、削除も移動もできず、状況変わらず。
というか、このアカウント、右クリックメニューの数が圧倒的に少なく、とても普通ではない。

結局、現場リーダーから、「あれ?なぜか管理者権限がない?」ということで原因判明。圧倒的に弱いユーザーになっていたため、Cドライブの(マイドキュメント以外の)中身に対して何もできなかったようだ。

その人のアカウント、自分のアカウントにも管理者権限をつけてもらい、ようやくeclipseのセットアップを開始。やはり起動せず。あらためてeclipse.iniからメモリ関連の行を削除し、起動。
ただ、日本語化プラグイン(Pleiades)を入れるも、日本語化できず(-clean起動したけど)。
もう、気にせず突破。英語?読める読める!


次に、Apacheの設定を確認するために、まずはネットワーク系の設定をするためipconfigでIPアドレス確認・・・と、コマンドプロンプトでipconfigを叩くと


'ipconfig' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。


試しに、netstat とかも打ってみるが、結果は同じ。

ハッハッハ。そんなバカな。
で、環境変数を確認すると、PATHがJavaとSQL Serverのそれぞれbinにしか通ってない・・・
そりゃコマンド使えないはずだ。さては、素人が書き換えやがったか。

Windowsフォルダ(C:\Windows)、システムフォルダ(system32)などをPATHに追加し、ログオンしなおしてipconfigの動作を確認。

その後は、必要最小限な記述のわかりやすい手順メモを見ながら何とかセットアップ完了。
Eclipseは英語のままだけど。

PostgreSQLのセットアップでは、pgAdminの挙動がどうも不安定で、psqlを使ってCUIで戦うことに。
とりあえずpsqlを立ち上げて、「\d」を打つと、


'more' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。


まだちゃんとシステムフォルダにPATHが通っていなかったらしい。今一度環境変数を確認し、再度ログオンしたらやっと動作。


ようやくDBも起動し、データも突っ込んで、Apacheも起動し、あとはEclipseを起動してプラグインでTomcatを起動してWebアプリを動かしてみるか!と思ったら、Eclipseで OutOfMemory。ヤッホー!


この時点で時計は午後8時。
さすがにこれはもうダメだ、仮にうまいこと開発環境が入ったとしても、今後謎のトラブルに見舞われることは目に見えている!というわけでリーダーに相談したところ、

「次に来られる日までに、OSを再インストールして、環境もこちらで準備しておきます」

とのこと。

ありがたい!なんてありがたい!
けど、俺の今日の一日はいったい何だったのか・・・。

午前中の放置プレイの間にWindowsから再インストールしておけば、きっと夕方には開発環境のセットアップも終わっていただろうに…。


まぁ、そんなもんです。

このトラブルでいろいろと調べものをしたおかげで、開発者時代の感覚がだいぶ甦りました。
次回からは、バリバリいくぞ!