IT技術者「35歳定年説」について考えてみた

※この記事は丸太式 Advent Calendarの16日目です

IT技術者の定年は35歳であるという節、いわゆる「35歳定年説」がありますが、試しに検索してみると「本当だった」という声と「嘘だった」という声が両方とも見られます。

個人的な見解ではありますが、「35歳定年説」は嘘だと思っています。

まず、日本社会は年功序列の考えがまだまだ強く、IT企業であっても例外ではないということがあります。
会社側が”35歳定年”になってしまうキャリアパス、つまりマネジメントへの道しか提供していない為にこのような俗説が出現したのでしょう。

ただ、35歳だろうが45歳だろうが、途中で技術から離れてしまう様な人は技術者では無いと思っていますし、それまでどれだけの功績を残していても認識を改めることになります。
技術から離れてマネジメント側につく人は、技術にさほど興味が無かったのでしょうね。
本当に技術に興味があれば、現場から離れることはないでしょう。

確かに”プロジェクトマネジメント”は誰かがやらなければならないことですが、だからといって技術から離れるくらいならそんなものは技術者じゃない人に任せておけば良いのです。(技術を知らない人がマネジメントするという問題もありますが、技術から離れてまでマネジメントに専念するならあなたは技術者ではありません)

以上、個人の見解でした。
私が35歳になるまでまだ10年以上ありますが、そのときになっても同じような意見が言える技術者でありたいです。

HibernateのCriteiraをメソッドチェーンで書いたらなぜかテンションが上がった件

※この記事は丸太式 Advent Calendarの15日目です

業務でHibernateを使っていますが、これまでは弊社内の大半の実装に合わせてこんな感じでCriteriaを書いていました。

Criteria criteria = session.createCriteria(Hogehoge.class);
criteria.add(Restrictions.eq("userCode", userCode));
criteria.add(Restrictions.in("fugaCode", fugaCodes);
criteria.add(Restrictions.ge("targetYearMonth", targetDate);
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.sum("days").as("days"));
projectionList.add(Projections.sum("hours").as("hours"));
criteria.setProjection(projectionList);
criteria.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);

今日は実装中に仕様追加が発生したので、ストレス解消を兼ねてスピード重視で実装したら、いつの間にかメソッドチェーンで書いていました。

Criteria criteria = session.createCriteria(Fugafuga.class)
    .add(Restrictions.eq("userCode", userCode))
    .add(Restrictions.in("fugaCode",  fugaCodes))
    .add(Restrictions.ge("targetYearMonth", targetDate))
    .setProjections(Projections.projectionList()
        .add(Projections.sum("days").as("days"))
        .add(Projections.sum("hours").as("hours")))
    .setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);

流れるように実装できたので、自分にはメソッドチェーンの方が向いているようです。
弊社のコーディング規約に特に記載が無ければ、今後ともメソッドチェーンで書きたいですね。


Criteriaをメソッドチェーンで書くと、次のような利点があるように思います。
* (作るべきSQLが見えているなら)流れるように書き表すことが出来る
* わざわざcriteria(変数名)や;(セミコロン)を書かなくて良い
* ProjectionListを変数に格納しなくても良い
* Eclipse等のIDEで整形すれば、適度にインデントが設定されて見やすい

「俺ならこういう理由でこうしたい!」という話があれば、是非お聞かせください。

電脳書房が半額セールやってる件(14日まで)

※この記事は丸太式 Advent Calendarの13日目です

IT系書籍専門の中古買取・販売で有名な電脳書房さんが、14日まで対象の書籍が半額になるキャンペーンを実施しています。

普段からほとんど汚れがない古本を扱っているので、これはかなりお得ですね。

さて、何を買おうかな?

[Sonatype NEXUS][メモ] 自前のMavenリポジトリを使って依存関係を管理できるようにする

※この投稿は、丸太式 Advent Calendar 2014の11日目です

概要

世の中に公開されているOSSのJavaライブラリは、大抵MavenやGradle等の構成管理ツールで管理できます。
しかし、自分で作ったライブラリや会社の都合で公開できないライブラリを使う場合、自分でJarファイルを追加したり、依存関係を管理しなければなりません。
Javaは1個のライブラリが大量の依存ライブラリを必要とすることもよくあるので、これは非常に面倒です。

そこで今回は、OSSのMavenリポジトリ実装である”Sonatype NEXUS OSS”にライブラリを登録する手順の1例を(かなりざっくりと)紹介します。

手順

  1. 追加したいライブラリのJarを(ダウンロード、自前ビルドなどの方法で)用意する
  2. それっぽいpom.xmlを作る
  3. Sonatype NEXUSのUIからデプロイ

※ソースが用意できる場合、pom.xmlを作ればビルド・デプロイをmvnコマンドでやれます。

Jarを用意する

バイナリのJarを調達します。ソースやJavadocのJarを追加で調達すればEclipseやNetbeansなどのIDEで便利になりますが、今回はとりあえずバイナリだけ登録します

pom.xmlを作る

追加したいライブラリのためのpom.xmlを作ります。
依存しているJarがMaven Central等でホスティングされていれば、その依存関係も記載します。

デプロイ

NEXUSにログインし、repositoriesを開きます。
NEXUSは標準で「3rd party」というリポジトリが用意されているので、これを選択します。
下側に出ている「Artifact Upload」タブからデプロイできます。

GAV Definitionで「From POM」を選択するとファイルアップロード用のフィールドが表示されるので、先ほど作ったpom.xmlをここで指定します。
「Select Artifact(s) to Upload」ボタンからアップロードするJarを選択して「Add Artifact」ボタンを押すと、その下のグリッドに表示されます。
pom.xmlとJarを選択・追加したら、「Upload Artifact(s)」ボタンをクリックすることで、アップロードが完了します。

デプロイした物の利用

デプロイした物を利用するには、pom.xmlにNEXUSのリポジトリを設定して参照できるようにします。
初期状態のNEXUSには{NEXUSのURL}/content/groups/public/というリポジトリが有り、これを指定すると色々と幸せになれる層ですよ。

[メモ] BRMSを組み込むことによる、基幹業務パッケージのカスタマイズ工数削減の可能性の考察

※この投稿は、丸太式 Advent Calendar 2014の10日目です

ビジネスルールエンジンについて、しばらく考察を続けています。
今日は(あまりまとまっていませんが)現状のメモをまとめておきます。
どれくらい先になるかはわかりませんが、将来的に整理しなおすつもりです。

以下メモ

アプリケーションとは独立した、ビジネスルールを処理するための仕組みや実装を、ビジネスルールエンジン、または単にルールエンジンという。

基幹業務パッケージの導入においては、導入先の企業の業務フローに合わせたカスタマイズが必要となる。

特定の業種に対して横展開で受注を獲得しているパッケージの場合を考えてみる。
各企業向けのカスタマイズ部分を基となるコードに密結合させてしまうと、似たようなカスタマイズを繰り返し行うことになりかねない。

このような場合にルールエンジンの概念を導入すると、工数を削減できる可能性がある。
例えば、画面の入力値をバリデーションし、結果に応じてデータを修正し保存する処理があったとする。
この処理をビジネスルールとすると、バリデーション、データの修正、保存の三つに分けることができる。
これらをルールエンジン上に構築することで、アプリケーションの更新とは別にルールの組み替えや追加が可能となる。

先述の例で言うと、データを保存した後に”特定のユーザに対してメールで通知する”という処理を追加する場合、ルールエンジンではあらかじめ規定しておいたルールを追加するだけで良い。

#jjug_ccc #ccc_r16 JJUG CCC 2014 Fall 参加レポート / R1-6 Concurrent Mark-Sweep Garbage Collection 再入門

※この投稿は、丸太式 Advent Calendar 2014の9日目です

今日はJJUG CCC 2014 Fallの参加レポート3本目です。

概要

R1-6 Concurrent Mark-Sweep Garbage Collection 再入門
by 久保田 祐史さん (@sugarlife)

メモ

CMS GC

  • GC: 不要なメモリ領域を探し、解放して再利用可能とする
  • Parallel GC: アプリケーションを止めて動く。GC時間は短いが、応答しなくなる
  • Concurrent GC: アプリケーションと同時に動く
  • Concurrent Mark-Sweep GC: ゴミじゃない領域をMarkし、Markされていない領域をSweepして再利用可能にする
    Compactionしないので、メモリ空間が断片化する

HotSpot VMのCMS GC

  • Heap -> New Gen.(Eden, Survivor0, Survivor1), Old Gen.(Tenured)
  • Minor GC: New Gen.に対してParallel Copy GC: アプリケーションを止めて、メモリが断片化しないようにGC
  • Major GC: Old Gen.に対してCMS GC

  • Minor GC: Eden -> Survivor 0, Survivor 0 -> Survivor 1

  • Promotion : Survivor -> Tenured
  • Major GC: Old領域の占有率やHeap使用量増加速度によって発生する
  • CMS GCは安定していない。失敗してSTW:Stop The Worldを伴うFull GCが発生することがある

  • Full GC (with STW): 全領域がGC対象
    Promotion failed, Concurrent mark failed

GCログの読み方

  • タイムスタンプ: Java processのuptime (sec.)
    -XX:+PrintGCDateStampsで、読める時間表記で出力
  • Minor GC: ParNew GC前のNew領域サイズ->GC後のNew領域サイズ(総容量)
    かかった時間は後ろの方に出るtimes (real)を参照
  • Minor GC (promotion): PromoteされたサイズはNew領域の差分 – 全体の領域の差分

  • CMS GC: initial mark
    STWをかけて、ルートオブジェクトから直接たどれるオブジェクトをマーキング

  • concurrent mark
    アプリケーションを再開しつつ、initial markでマーキングされたオブジェクトからたどれる全オブジェクトをマーキング。
    処理中に生成・変更されたオブジェクトはDirty Cardにされる
  • cuncurrent preclean
    STWが発生するRemarkを短縮するため、concurrent mark中にDirty Cardのオブジェクトをマーキング
  • concurrent abortable preclean
    Minor GCによってEden使用量が2MBになるまで最大5秒待つ
  • Remark (Final mark)
    STWしてNew領域を全スキャンして、New領域からOld領域を参照しているものにmark
  • concurrent sweep
    未マークのオブジェクトを改修
  • concurrent reset
    次のCMS GCで使う関連マップをクリアして、initial markの処理にゴミを残さない

注意すべきパターン

  • Full GC: promotion failed: Minor GCでOld領域にPromoteできなかった場合に発生
    断片化を解消するためのFull GC

    • 短命オブジェクトはNew領域で改修するべき(断片化を防ぐ)
    • New領域のサイズを調整する
    • PromoteさせずにNew領域で粘る
    • 兆候: Minor GC後のOld領域より、次のMinor GCの前のOld領域が大きい->短命オブジェクトがOld領域に飛んでる
    • 兆候: Old > NewだがPromotion Failed: Newに大きいオブジェクトしか入っていない
  • Full GC: concurrent mode failure: CMS GC中にもう一度CMS GCが発生しようとした場合

    • CMS GCの改修が間に合っていないので、開始タイミングを早める
    • サーバのスペックをあげる
      • 単純にいメモリを増やすより、CPUスペックをあげるべき
  • GC locker: GCを止める機構。HotSpot初期化や、JNI API呼び出しの一部

  • GC locker: Trying a full collection because scavenge failed
    • GCが止まっているのでNew領域にはいらずOLD領域に割り当て
    • 深刻な断片化、Promote失敗
  • 対策
    • GC Lockerの頻度を下げる
    • 断片化しないGCを使う
    • 短命JVM

自分用Mavenリポジトリを作る

※この投稿は、丸太式 Advent Calendar 2014の8日目です

自分で作った物のJAR(fat jarではない)をMavenリポジトリにデプロイしておけば何かと便利な気がしたのと、ExCellaをMavenで管理できないのはやっぱり不便なので、自前のMavenリポジトリを用意してみました。

必要なもの

  • Javaの実行環境
  • 適当なサーバ
  • Nginx等のフロントサーバがあるといいですね

やること

  • Sonatype NEXUS OSSをダウンロード
  • 適当なディレクトリに展開
  • 展開したディレクトリで、以下のコマンドをを実行
    % bin/nexus start
    ※Windowsならbin\nexus.bat startで良いんじゃないでしょうか
    フォアグラウンドで実行するなら、startの部分をconsoleにすれば良かったはず。

NetBeansでpersistence.xmlを生成してHibernateを使ったらはまった話

※この投稿は、丸太式 Advent Calendar 2014の7日目です

現象

NetBeans 8.0.1でJPAの持続性ユニットをHibernateを使うようにして作成すると、EntityManagerFactoryでEntityManagerを作れない。
※Persistence Unitを正しく指定しても、見つからない旨の例外が発生する

原因

NetBeansが生成するHibernate向けのpersistence.xmlの内容で、providerorg.hibernate.ejb.HibernatePersistenceが設定されるが、このクラスは@Deprecatedでありなにやら挙動が違うらしい。

対応

persistence.xmlのproviderに、org.hibernate.jpa.HibernatePersistenceProviderを設定する。
このクラスは、org.hibernate.ejb.HibernatePersistenceのJavadocに記載されている、代替となるクラスらしい。

#jjug_ccc #ccc_r15 JJUG CCC 2014 Fall 参加レポート / R1-5 JavaでやってみるThe Twelve-Factor App

※この投稿は、丸太式 Advent Calendar 2014の6日目です

昨日に引き続き、JJUG CCC 2014 Fallの参加レポートです。

概要

R1-5 JavaでやってみるThe Twelve-Factor App
by 渡辺 祐さん(株式会社ビズリーチ)
@nabedge

メモ

The Twelve Factor App

  • 論文(っぽいよみもの)
  • Herokuの元CEOが作った
  • “どんなWebアプリケーションであっても、だいたいこの方針で作ればいいんじゃねーの”というもの

ポートバインディングを通じてアプリケーションを公開せよ

  • 【自らポートを開いて】
    • 開発したアプリケーションの”依存ライブラリのTomcat/Jettyで”ポートを開く
  • main()メソッドで起動できるので、Run As -> Java ApplicationでTomcatがポートをバインドして起動できる
    • WTP Plugin, Sysdeo Tomcat Pluginはいらない
    • Tomcatのバージョンアップも、pom.xmlのバージョンを変えれば良い→普通のリリースフローで対応可能

廃棄容易性

  • 高速な起動はJavaではあきらめる
  • グレースフルなシャットダウン: Shutdown Hookを使う
    • Springなら@PreDestroyアノテーションをつけるとシャットダウン前に呼ばれる

ログをイベントストリームとして扱え

  • 「全てのログを標準出力に集める」
  • とりあえず標準出力に出しておけば、後から好きなところに流せるので。
  • 依存ライブラリのログ出力はslf4jのブリッジライブラリなどで集約する
  • GCログは・・・

設定はOS環境変数に格納せよ

  • 設定ファイルに本番DBのパスワードも格納してVCSに管理するの?
  • OSが違っても環境変数の設定はほとんど同じ
  • 気の利いたライブラリはOS環境変数からの設定値読み込みは対応している
  • 今時ならChef/Puppet/Ansibleで設定するでしょ

依存関係を明示的に宣言し分離せよ、ビルド/リリース/実行は厳密に分離せよ

ビルド

  • バイナリ間の依存関係管理機能のあるビルドツールを使う(Maven, Gradle)※Antはダメよ

  • ビルドの結果はjar, warというバイナリ

  • バイナリはパッケージリポジトリサーバにデプロイするもの
  • MavenもGradleも、依存関係の解決にはパッケージリポジトリを使う

リリース

  • パッケージリポジトリから開発したアプリのJARと依存ライブラリのJARを取得して、依存JARをコピーしてZIPに固めてSCPで送り、サーバー上でUNZIPするまで

実行

  • java -cp “jar群の展開dir/*” com.example.ExampleMainClass
  • 設定は環境変数に格納されているはず

アプリケーションをステートレスなプロセスとして実行せよ

  • 少なくとも、Stickyセッションを使うな→現実問題難しい
  • ステートレス:アプリケーションサーバにセッションを持たせない

#jjug_ccc #ccc_r13 JJUG CCC 2014 Fall 参加レポート / R1-3 実例Javaトラブルシューティング! 稼働中のシステムを立て直した半年間の軌跡

※この投稿は、丸太式 Advent Calendar 2014の5日目です

11月15日に、JJUG Cross Community Conference 2014 Fallが新宿で開催されました。
朝の基調講演から参加するつもりでしたが、残念ながら寝坊してしまったので途中からの参加となりました。
今日から何日かに分けて、セッションのメモをAdvent Calendarの記事として公開していきます。

概要

http://www.java-users.jp/?page_id=1292#R1-3
by 谷本 心さん@Acroquest Technology(株)
@cero_t

メモ

世の中のシステムは完璧か?
→最近リリースしたシステムは完璧か?

完璧ならざるシステムの例

処理が遅い
アクセスを裁けない
脆弱性
システムエラー
etc…

方針

  1. 検索処理の高速化
  2. 購入エラーの是正
  3. 大量アクセスを捌く
    ※Struts + Hibernate + JSP

最初にやったこと

→まずはSeleniumの自動試験を作る
直す過程で壊すことがないように
→CheckStyle / FindBugsをかけてリファクタ
可読性を向上させながら、何とかする

→ダメだった。
1. 300KLのコード、大半がデッドコード
1. 試験項目作成中にもエラーが頻発
1. その間にも本番システムでエラーが多発

方針転換

  • 問題のトリアージ(優先度の設定)
    「一番の問題は何か?」→「購入に失敗すること」(損失の本質)
  • 購入に失敗する理由→これらの改善こそ【顧客が求めること】
    • 購入時にシステムエラーが起きる
    • 検索が遅くて購入までたどり着けない
    • TV放送でアクセスが集中すると、システムがダウンしてしまう
  • どうやって問題を見つけるか(ソースコード上の問題より、現場の問題をつかむ必要がある)
    • エラーの発生頻度(HTTPステータス、アプリケーションエラー)
    • 性能の傾向(通常のレスポンス、アクセス増大時のレスポンス性能)
  • どうやって現場の問題をつかむのか
    ※稼働システムにブレークポイントはだめ

    • ログの収集(アクセスログ、アプリケーションログ、MySQLのスロークエリログ
    • 低負荷な解析ツールの適用(ENdoSnipe等)
  • ログ分析
    • ElasticSearch(ログの蓄積) ※リアルタイム検索・解析エンジン
    • Kibana(可視化) ログ検索、可視化
    • Fluentd(収集)
  • 典型的な問題の検出
    • ENdoSnipe OSSのトラブルシュートツール。メモリリークや同一SQLの発行回数など。動的なFindBugsのようなもの

Mission1 検索処理の高速化

  • 問題点
    • 検索処理は日常的に重い(10~30秒程度)
    • 2~3日間隔で非常に重くなる
  • 分析状況
    • 100件/秒のアクセスで、全てのレスポンスが5秒以上かかる
    • 夜間、ほぼアクセスがない場合でも10~20秒かかる
    • 謎のレスポンス劣化(最大3000秒!!!)
      • スロークエリログを見ると、同じ形になる→間違いなくDBに問題
      • なぜ線形に上がるのか?→SQLを見ると、全て同じストアドプロシージャ
  • 謎のレスポンス劣化原因について仮説を立てる
    ※トラブルシューティングでは、まず問題を確認し、仮説をいくつか立ててから検証・考察するべき

  • スロークエリのストアドプロシージャを精査

    • Temporary Tableに数万件のinsert
    • 明らかに無駄な処理が多数あり、削ったが改善されず
    • Temporary Tableはどうしても必要だったので、
      • Temporary Tableをon memory
      • Temporary Tableのメモリ割り当てを増やす
        →結果・・・Disk I/Oが激減、CPUのI/O waitが激減。スロークエリも改善

Mission2 購入エラーの是正

  • 問題の確認
    • 購入処理の途中でエラー
      • システム内要因(NPE等)
      • 外部システム要因(DB,決済等の応答無し、等)
    • お客様からのクレームで気づく
    • カード決済が絡むので、問題
  • アプローチ
    • 購入処理の開始時にロギング(ログをDBに記録)
    • 処理の途中、終了時にもロギング
    • ログを解析して、正常終了した処理と異常終了した処理を可視化
    • エラー原因ごとに発生件数を整理して、件数が多いエラーから順に対応
    • バグパッチを当てるたびに、エラー数が半減
    • 外部システム要因のエラー以外は対処完了

Mission3 大量アクセスを捌く

  • 問題
    • TV放送などで大量アクセスがあるとレスポンスが悪化してシステムダウン
    • ストアドプロシージャは対処したが、CPU使用量は上がるので。。。
  • アプローチ
    • 同時アクセス数制限の強化 APサーバごとに、検索処理の同自利楠と数が一定数を超えたら503
    • 検索結果のキャッシング
    • 同時検索数を制限 ※同一検索条件は待たせ、キャッシュから読み取る。違う検索条件では同時に検索できる仕組み
  • 構成の問題
    ボトルネックはDBなのに、なぜAPサーバをスケールアウトしているのか・・・
  • アプローチ
    TV放送時にもスケールアウトしない
    →システムダウンがなくなる
    →レスポンス改善
    ※closeされていないコネクションが残ってしまう場合があった

このシステムの今後

  • 全面的なデザインリニューアルと同時に処理をRESTful APIとして再実装
  • 購入処理の非同期化
    • 在庫確保とカード決済ができた時点でレスポンスを返す
    • 外部システム連携部は自動リトライ
  • ElasticSearch / Kibanaの改善
    • シングルノードで運用しているので、たまに死ぬ
    • 処理負荷が高すぎて過去ログを流し込めない

まとめ

  • 長期的トラブルシュートでは、ログの可視化は効果的
    • 現実に起きている問題がわかる
    • 改善効果がわかる
  • 下手にスケールアウトすると怖い