PHPerが
Java屋になるために
乗り越えたこと
株式会社ビズリーチ
芹沢和洋
@seri_k
第一回 Shibuya.java
自己紹介再び
芹沢和洋
株式会社ビズリーチ
エンジニア
@seri_k
id:serihiro
Blog:seri::Programing Diary
•上流SEとして社会人スタート→2年半で挫折
•SE時代にPHP独学1年
•転職してPHPで業務1年
•転職して今の会社でJava 半年
ドワンゴさんの新人研修資料より
http://ch.nicovideo.jp/dwango-engineer/blomaga/ar246504
PHPが書ける人がJavaを
修得するコストより
Javaを書ける人が
PHPを修得するコスト
の方が低い らしい
つまり
・・・なのか?
PHPerはアホなので
Javaを覚えるのは
すっげー大変
実際に
やってみた
2012年12月
株式会社ビズリーチJOIN
前職は受託でPHPで画面とかバッチとか書いてた
訪れた環境の変化
転職後
• 自社サービス
• java
• Struts2 + Spring2.5
• 社員100名近く
• エンジニア12~3名
(当時)
• Git
• Redmineによるチケッ
ト駆動開発
前職
• BtoB受託開発
• PHP
• PHP4ベースの
謎フレームワーク
• 社員5人
• エンジニア2人
• SVN
• 脳内タスク管理
結果
3つの壁に
ブチ当たる
壁その1
DIコンテナ
現場で最初に読んだコード
@Autowired
private HogeLogic hogeLogic
@Result(name = “/", value = "index.jsp")
public String index() {
form = hogeLogic.methodA();
return “success”;
}
hogeLogicが
newされてない。
でもなんか動いてる・・
普通に考えたら・・・
@Autowired
private HogeLogic hogeLogic
@Result(name = “/", value = "index.jsp")
public String index() {
hogeLogic = new HogeLogic();
form = hogeLogic.methodA();
return “success”;
}
Newしないと
ぬるぽっちゃうはず
HogeLogic.methodA()はstatic?
Public Class HogeLogic{
@Component
public void methodA(){
…..
}
….
}
Staticじゃない
でもなんか付いてる
分からないなりに考えた
• JavaがPHPパクってどんなメソッドもstatic呼び
出しできるようになっていた
• 実は誰かがNewしてる
• Newしなくても使えるようにコンパイラが独自
拡張された(もしくはやった)
• 秘書が勝手にやった
先輩に聞いた結果
• Springっていうのが@Componentってのが付いて
るクラスだけ勝手にnewしてプロパティに突っ込
めるようにしてくれてるから気にすんな。
→わたし、気になります
• 勝手にnewできる対象のクラスはxxx-bean.xmlっ
てファイルに書いてあるから
それ見れば分かる
→何書いてあるか分かりません(´・ω・`)
解決策:学ぶ
@IT
「Spring Frameworkで理解するDI」
シリーズ
•DIとはそもそもなんぞや?
•DIコンテナは何してくれるの?
•Springでどうやって実現するの?
という疑問の解消
http://www.atmarkit.co.jp/ait/articles/0504/29/ne
ws022.html
解決策:学ぶ
http://www.amazon.co.jp/dp/4774130001
「 Spring2.0入門」
•Beanの書き方
•interceptorの解説と使い方
の習得。
今でもちょいちょい業務中にチェック
ちなみに
• PHPにもDIフレームワーク(AOPフレームワー
ク)は存在します
• PHP5.4以降対応なので新しすぎてまだあまり普及してないぽいですが
https://code.google.com/p/bearsunday/wiki/introduction
壁その2
StackTrace
分かりづらい…読むのだるい…
java.util.MissingResourceException: Can't find bundle for base name
jp.apli.sdk.eie.EIEBufferCSyuyakuListOut, locale ja_JP at
java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:707) at
java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:679) at
java.util.ResourceBundle.getBundle(ResourceBundle.java:546) at
jp.apli.sdk.common.corba.SdkCorbaDataBuffer.<init>(SdkCorbaDataBuffer.java:74) at
jp.apli.sdk.common.corba.SdkCorbaData.<init>(SdkCorbaData.java:120) at
jp.apli.sdk.eie.servlet.SdkDataBuilder.buildSdkCorbaData (SdkDataBuilder.java:59) at
jp.apli.sdk.common.corba.SdkCorbaExec.buildDatas(SdkCorbaExec.java:130) at
jp.apli.sdk.common.corba.SdkCorbaExec.function(SdkCorbaExec.java:77) at
jp.apli.sdk.eie.servlet.SdkServletEvent$DataSend.exec(SdkServletEvent.java:307) at
jp.apli.sdk.common.event.SdkEvent.execEvent(SdkEvent.java:93) at
jp.apli.sdk.eie.servlet.SdkServletEvent.execEvent(SdkServletEvent.java:1609) at
jp.apli.sdk.eie.servlet.SdkServlet.doPost(SdkServlet.java:700) at
javax.servlet.http.HttpServlet.service(HttpServlet.java:772) at
javax.servlet.http.HttpServlet.service(HttpServlet.java:865) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:415) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:447) at com.fujitsu.interstage.jservlet.tomcat.servlets.InvokerServlet.service
(InvokerServlet.java:257) at javax.servlet.http.HttpServlet.service(HttpServlet.java:865) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:415) at com.fujitsu.interstage.jservlet.tomcat.core.ContextManager.service
(ContextManager.java:541) at com.fujitsu.interstage.jservlet.tomcat.service.connector.
Ajp12ConnectionHandler.processConnection(Ajp12ConnectionHandler.java:147) at
com.fujitsu.interstage.jservlet.tomcat.service.TcpConnectionThread.run
(SimpleTcpEndpoint.java:334) at java.lang.Thread.run(Thread.java:484)
すぐ分かればいいけど
java.util.MissingResourceException: Can't find bundle for base name
jp.apli.sdk.eie.EIEBufferCSyuyakuListOut, locale ja_JP at
java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:707) at
java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:679) at
java.util.ResourceBundle.getBundle(ResourceBundle.java:546) at
jp.apli.sdk.common.corba.SdkCorbaDataBuffer.<init>(SdkCorbaDataBuffer.java:74) at
jp.apli.sdk.common.corba.SdkCorbaData.<init>(SdkCorbaData.java:120) at
jp.apli.sdk.eie.servlet.SdkDataBuilder.buildSdkCorbaData (SdkDataBuilder.java:59) at
jp.apli.sdk.common.corba.SdkCorbaExec.buildDatas(SdkCorbaExec.java:130) at
jp.apli.sdk.common.corba.SdkCorbaExec.function(SdkCorbaExec.java:77) at
jp.apli.sdk.eie.servlet.SdkServletEvent$DataSend.exec(SdkServletEvent.java:307) at
jp.apli.sdk.common.event.SdkEvent.execEvent(SdkEvent.java:93) at
jp.apli.sdk.eie.servlet.SdkServletEvent.execEvent(SdkServletEvent.java:1609) at
jp.apli.sdk.eie.servlet.SdkServlet.doPost(SdkServlet.java:700) at
javax.servlet.http.HttpServlet.service(HttpServlet.java:772) at
javax.servlet.http.HttpServlet.service(HttpServlet.java:865) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:415) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:447) at com.fujitsu.interstage.jservlet.tomcat.servlets.InvokerServlet.service
(InvokerServlet.java:257) at javax.servlet.http.HttpServlet.service(HttpServlet.java:865) at
com.fujitsu.interstage.jservlet.tomcat.core.ServletWrapper.handleRequest
(ServletWrapper.java:415) at com.fujitsu.interstage.jservlet.tomcat.core.ContextManager.service
(ContextManager.java:541) at com.fujitsu.interstage.jservlet.tomcat.service.connector.
Ajp12ConnectionHandler.processConnection(Ajp12ConnectionHandler.java:147) at
com.fujitsu.interstage.jservlet.tomcat.service.TcpConnectionThread.run
(SimpleTcpEndpoint.java:334) at java.lang.Thread.run(Thread.java:484)
この辺まで読なきゃいけ
ないケースが辛い…
この辺はすぐ読めるが
でも読まないとどうしようもない
謎エラーが出て悩む
→無精してついつい読まずに先輩に聞いてしまう
→再現させてConsole上のStacktrace見せる
先輩「ああ分かった。
下の方のここでコケてる。
ここがおかしいから上でコケてる」
→Stacktraceをしっかりエラーの原因が
分かるケースが存在する・・みたい?
解決策:頑張って読むクセを付ける
• 最初はしんどい。。が、時間かかってでも読む。
• 頑張って読んでるうちに、どこを見るべきか分
かってくる。
• 本当の原因箇所は冒頭の数行にあるとは限ら
ない。下から順番に読んでいって何が起きてい
るかを把握するように意識する。
→ケース毎の読み方が分かってきて
最近は解決が早くなってきた(気が
する)
参考:DBFlute久保さんのブログ
「デバッグ手順(スタックトレース重要)」
http://d.hatena.ne.jp/jflute/20090224/1235473382
壁その3
SAStruts使用時の
ハマリやすさ
そもそも導入がしんどい
• CakePHP,Symphony,Zendframework等
→ファイル落としてきてフォルダ毎入れれば終了
• SAStruts
→自分でjarを落としてきてbuildパスに通すか、
Mavenのpomにゴリゴリ書いて落とす
→MavenだとTomcatのWEB-INF/lib配下に依存ライ
ブラリが入らないから設定書いて動かす
そして何故か早い段階でハマる
ハマったケース
・SAStruts + S2Chronosの構成を作る時に、
s2chronos-coreの参照をpomに記述すると
バージョンの不整合なのかS2コンテナ初期化
で失敗して起動しない
→s2chronos-coreのバージョンの問題??
参考:
http://kinjouj.hatenablog.jp/entry/20121026/1351226167
そして何故か早い段階でハマる
ハマったケース
・MavenのArchetypeで作成したSAStrutsプロ
ジェクトはそのままだとjettyで起動できない
→2リクエスト目以降でぬるぽが発生
→jettyのバグが原因
→Tomcatでは起こらない
http://dev.classmethod.jp/cloud/p6881/
web.xml上で指定するrequestDumpFilterを外すことで解決
参考:
解決策:自分なりのベストプラクティスを
構築する
• 「こう構築すれば絶対上手くいく」パターンを
見つけるまで試行錯誤する。何度も作っては
壊しを繰り返して良い方法を見つける。
• SAStrus自体はもう進化しない(多分)が、
周辺環境は進化する。
それに併せて環境構築の手順も変わってくる。
まとめ:3つの壁と乗り越えるための対策
• DIコンテナ:
知らなければ外部リソースから学ぶ
実際に手を動かして使ってみて覚える
• StackTrace:
読むための修行をする
• SAStruts環境構築:
スクラップアンドビルドで
ベストプラクティスを探す
宣伝
株式会社ビズリーチはエンジニア絶賛募集中です。
・Webサービス開発に興味がある
・新規事業立ち上げに関わりたい(色々と企画立案中)
・Javaでアジャイルな開発がしたい
・Struts2使いたい
・AWSとバリバリ連携したものを作りたい
→現状:EC2,RDS, EMR,S3,ELB を使用
・Mongo,Cassandra等のNoSQLを使ったシステム開発がしたい
・芹沢と一緒にUTの普及を進めたい
一つでもピンと来たら
https://www.bizreach.co.jp/recruit/
ご清聴ありがとうございました

PHPerがJava屋になるために乗り越えたこと