eyecatch
Thu, Feb 23, 2017

Hibernateはどのようにして私のキャリアを破滅寸前にしたか

このエントリでは、Grzegorz Gajosによる記事、How Hibernate Almost Ruined My Careerを紹介する。 (Grzegorzから和訳と転載の許可は得た。) 以下はその全文の和訳だが、意訳超訳が混じっているので、もとのニュアンスを知りたければ元記事を読んでもいいし、読まなくてもいい。 (adsbygoogle = window.adsbygoogle || []).push({}); 想像してくれ。 君はJava開発者で、次のビッグプロジェクトを開始しようとしているところだ。 君は、そのプロジェクト全体に影響する根本的な決断をする必要がある。 君の柔軟なデータモデルをオブジェクト指向で抽象化するベストな方法を選択したい。生のSQLを扱いたくはないからね。 どんな種類のデータもサポートしたいし、理想では全種のデータベースをサポートしたい。 すぐに思いつくのは、単にHibernateを使うという解だ。そうだろ? Javaディベロッパの90%は君に同意するだろう。 しかし、それって正しい決断になっているだろうか? Hibernateが一般に受け入れられているスタンダードだからといって盲目的に採用してしまうと、どんな問題が発生するかを見てみよう。 モニカというJava開発者がいるとしよう。 モニカは最近出世してアーキテクトの役職に就き、会社の新製品のための技術スタックを選定する責任者になった。 彼女は、Javaの世界にはデータベースとのやり取りを扱うたった一つの適切なツールがあることを知っている。Hibernateだ。 Hibernateは良く知られ支持されているJPAのスタンダードではあるが、プロジェクト開始前に多少のチェックをするのが定跡だ。 幸いにも、同僚のベンが適任者を知っている。 4年前、Hibernateは銀の弾丸かのように見えた ベン: やあモニカ。ジョンを紹介させてくれ。彼はHibernateの達人だ。君の助けになるはずだ。 モニカ: ジョン、時間を取ってくれてありがとう。 今、私たちが次なる目玉製品を開発しようとしてるのは知ってる? 次のFacebookやGoogleになるつもりなの。 忙しくなるわ。巨大なものになる。 本当にすてき! みんなとても興奮してる! 私はアーキテクトの役に就いたから、とりあえず採用する技術スタックを選定しなければいけないの。 ひとつだけまだ欠けてるのが永続化なんだけど… ジョン: Hibernate! モニカ: そう!そのとおり! わたしもそう考えていたの! それならわたしたちにぴったりで上手く行きそうでしょう。 マーケットと豊富な実績に裏付けられた、真の業務問題のための真の業務ソリューション。 とてもたくさんのポジティブな経験談を聞いたことがあるわ。 けど、一つ問題があって、チームメンバのひとりがそれに絶対反対してるの。 アプリケーションとデータベースの間に別のレイヤを加えるのを気にして。 彼はすごく頭がいいから、これが良い決断だと納得させるには本当にしっかりした根拠が必要なの。 助けてくれる? ジョン: もちろん、よろこんで! Hibernateは、実際、すばらしいツールです。 銀行といった、大きな真の業務ソリューションで広く使われています。 それを使って失敗するということはありえません。 永続化ときたらHibernate。 Javaで書いているならそれが完全に正しい選択ですし、さらには他の言語への移植もあります。 どれだけ多くの職務記述書がそれを要求しているか! モニカ: 全く同感! 同じことを感じていたわ。 前のプロジェクトで、ほとんどのところで生のJDBCからSQLを使っていたんだけど、ばかげてた! そうでしょ! けど、実は、ほんとに優秀なSQL屋がチームにいて、Hibernateが生成したSQLを見て神経質になってるの。 きたなくて読みにくいって。 これって将来問題になりそう? ジョン: 気を付けてください。DBA屋ってのは違ったものの見方をします。
eyecatch
Tue, Feb 14, 2017

ブログアドレスを変更したときにやったこと

このブログの閲覧数がそこそこの規模になってきたので、Google AdSenseで小遣い稼ぎを始めようとしたら、最近サブドメインがwwwじゃないとできないようになったようだったので、サブドメインをtbdからwwwに変更した話。 変更自体はそんなに難しくなかったけど、Googleの検索順位を保つためにいろいろ気を使う必要があった。 (adsbygoogle = window.adsbygoogle || []).push({}); ブログアドレスの変更 以前にも書いたが、このブログはHugoで作ってGitHub Pagesでカスタムドメインで公開している。 コメント欄を設けるためにDisqusを使っている。 Cloudflareを使って全体をHTTPS化していて、その関係でkaitoy.xyzドメインの名前解決にはCloudflareのDNSを使っている。 アクセス解析などのためにGoogle AnalyticsとGoogle Search Consoleを使ってる。 この構成で、ブログアドレスの変更に必要だった修正を列挙する。(この順にやったわけではない。) 1. ブログソース修正 Hugoの設定ファイルであるconfig.tomlに書いてあるbaseurlの値をhttps://tbd.kaitoy.xyzからhttps://www.kaitoy.xyzに変え、また、各記事の内部リンクのURLもwwwのに変えた。 あとrobots.txtのSitemapのURLもhttps://www.kaitoy.xyz/sitemap.xmlに更新した。 2. GitHub Pagesの設定変更 ブログリポジトリに行って、SettingsのGitHub Pages欄のCustom domainの値をhttps://www.kaitoy.xyzに変えた。 ついでにブログリポジトリのトップに表示されるDescriptionのWebsiteの値も新しいURLに変更した。 この変更によりありがたい副作用もあった。 GitHub Pagesはwwwというサブドメインを特別扱いしていて、以下の恩恵を受けられるのだ。 wwwを省略したURL(apex domain)でアクセスすると、GitHub Pagesサーバがwww付きのURLにリダイレクトしてくれる。 安定していて速い。 3. CloudflareのDNS設定変更 CloudflareのDNSで、もともとCNAMEレコードでkaitoy.github.io(GitHub Pagesのデフォルトのドメイン)のエイリアスをtbdにしていたのをwwwに変更した。 また、上記の通りapex domainでGitHub Pagesにアクセスしても上手いことやってくれるようになったので、www.kaitoy.xyzのエイリアスをkaitoy.xyzとするCNAMEレコードを追加した。 CloudflareのDNSはapex domain(i.e. kaitoy.xyz)に対するCNAMEレコード設定をサポートしているので、これでwww.kaitoy.xyzでもkaitoy.xyzでもGitHub Pagesにルーティングされるようになった。 4. Disqusの設定変更 ホームの右上の歯車アイコンからAdminを開いて、ヘッダのSettingsからブログのURLを選んでその設定画面を開き、Website URLをhttps://www.kaitoy.xyzに変更した。 5. Google Analyticsの設定変更 管理タブのプロパティ設定のデフォルトの URLをhttps://www.kaitoy.xyzに変更しただけ。 Googleのページランクを保つためのあれこれ 以前もどこかに書いたが、どんなにすばらしい内容の記事を書いてもGoogle検索結果の2,3ページくらいまでに出てこないんであれば誰も読んでくれない。 このブログのいくつかの記事はそれなりにいいキーワードでいい検索順位になっていたので、サブドメイン変更によってページランクに悪影響が出るのはなるべく避けたかった。 調べたら、Google Search Consoleのヘルプにまさにその悪影響を防ぐ方法が載っていたので、これに従ってあれこれした。 1. 自身を参照する rel="canonical"リンクタグを付ける ブログの全てのページのヘッダに以下の様な移転先アドレスを指すlinkタグを付け、変更後のアドレスが正式なアドレスであることをGooglebotに教えてやる。 <link rel="canonical" href="https://www.kaitoy.xyz/2015/07/18/first-post/"> Hugoのソースでいうと以下の感じ。 <link rel="canonical" href="{{ .Permalink }}"> 2.
eyecatch
Tue, Jan 24, 2017

Goslings開発メモ - その5: Spring Boot最終編 (静的リソース処理)

「Goslings開発メモ - その4: Spring Boot続続続編 (ロギング)」の続き。 Spring Boot最終編で、静的リソース処理について。 (adsbygoogle = window.adsbygoogle || []).push({}); Spring Boot(Spring MVC)での静的リソース処理 この時点でのGoslingsは単なるREST APIサーバで、アクセスしてもJSONを返すだけだ。 アプリとしての体を成すためには、そのAPIを利用するクライアントコード、つまりHTMLドキュメントやCSSファイルやJavaScriptファイル(静的リソース)も返すようにしないといけない。 HTMLドキュメントを返す場合、普通はなんらかのテンプレートエンジンを使うものだが、Goslingsは本当に単純なGUIなので、サーバに置いたHTMLファイルをそのまま返したい。 「Getting Started Guides」にはServing Web Content with Spring MVCというのが乗っているが、これはThymeleafというテンプレートエンジンを使うものなのでちょっと違う。 Spring Bootリファレンスガイドによると、クラスパス(またはServletContextのルート)の/static/、/public/、/resources/、/META-INF/resources/のいずれかに静的リソースを置けば、特にコードを書かなくてもクライアントからアクセスできるらしい。 (逆に、一般的に静的リソースを置く場所である、プロジェクトのsrc/main/webapp/には置くべきでないとのこと。これは、jarにパッケージングするときにビルドツールに無視されることが多いため。) この仕組みについて、この記事を参考にちょろっとソースを見た感じでは、これらのパスはResourcePropertiesのCLASSPATH_RESOURCE_LOCATIONSに定義されていて、これをWebMvcAutoConfigurationがResourceHandlerRegistryでリソースロケーションとして登録することで静的リソース置き場たらしめている模様。 (このResourceHandlerRegistryはResourceHttpRequestHandlerを設定するファサード的なものっぽい。) [email protected](その1参照)が付いているクラスがあって、spring-webmvc.jarがク[email protected] [email protected]上記WebMvcAutoConfigurationが実行される。 spring-webmvc.jarはspring-boot-starter-web.jar(その1参照)が引っ張ってくる。 なお、Spring MVCの静的リソース処理の全体の流れについては 、ちょっと古いけど「handling static web resources」という記事が分かりやすい。 要は、URLに指定されたパスからサーバ上のリソースを探し当てるResourceResolverというものが優先度順に連なっているリゾルバチェイン(ResourceResolverChain)があって、まずこいつがリソースを取得する。 次に、そのリソースを加工するトランスフォーマチェイン(ResourceTransformerChain)というものに通し、その結果をクライアントに返す。 トランスフォーマチェインはResourceTransformerが連なったもの。 リゾルバチェインとトランスフォーマチェインは上記ResourceHttpRequestHandlerに設定される。 リゾルバには以下の様なものがある。 PathResourceResolver: ResourceHttpRequestHandlerに設定されたリソースロケーションからリソースを単純に検索するリゾルバ。 CachingResourceResolver: キャッシュからリソースを検索するリゾルバ。テンプレートエンジンの処理結果のキャッシュとかが返るのは多分ここから。 GzipResourceResolver: gzipで圧縮されたリソース、つまりURLで指定されたパスに.gzという拡張子を付けたリソースを検索するリゾルバ。 VersionResourceResolver: リソースバージョニングを実現するためのリゾルバ。 WebJarsResourceResolver: WebJarsのjarファイル内のリソースを検索するリゾルバ。 リゾルバの設定などについてはQiitaのこの記事ががよくまとまっている。 凝ったことをしたいときは参照しよう。 トランスフォーマには以下の様なものがある。 CssLinkResourceTransformer: CSSファイル内のリンクをクライアントがアクセスできるURLに変換する。 CachingResourceTransformer: 変換したリソースをキャッシュする。 AppCacheManifestTransformer: HTML5のAppCacheマニフェスト内のリソースを扱うトランスフォーマ。 デフォルトでResourceHttpRequestHandlerにはPathResourceResolverだけが設定されている。 以上をまとめると、クライアントからGetリクエストが来ると、WebMvcAutoConfigurationが設定したリソースロケーション(e.g. /static/)をPathResourceResolverが検索して、そこに置いてあるHTMLファイルとかをクライアントに返してくれる、ということであろう。 Javaのコードを全く書かなくていいので楽。 Javaのコードを書いて静的リソースファイルを明示することもできる。 [email protected][email protected]を返せばいいらしい。 @RequestMapping("/hoge") public String hoge() { return "/hoge.html"; } 単純な静的リソースに対してこれをやるユースケースはあまりなさそう。 テンプレートエンジンを使っていてパラメータを渡したいときにはこういうリクエストハンドラを書くことになる。 Spring Bootのウェルカムページとファビコン Spring Bootはindex.htmlとfavicon.icoという名のファイルを特別扱いする。 前者がウェルカムページで後者がファビコン。 ウェルカムページ Spring Bootのリファレンスガイドにもちらっとかいてあるけど、リソースロケーションにindex.htmlというファイルを置いておくと、それがウェルカムページとして設定され、URLのパスにルート(e.g.
eyecatch
Tue, Jan 17, 2017

Goslings開発メモ - その4: Spring Boot続続続編 (ロギング)

「Goslings開発メモ - その3: Spring Boot続続編 (例外処理)」の続き。 Spring Boot続続続編で、ロギングについて。 (adsbygoogle = window.adsbygoogle || []).push({}); Spring Bootアプリにおけるロギング Spring Bootアプリにおけるロギングについては公式のマニュアルとHow-toガイドを読むべし。 この記事にはこれらの内容をまとめておく。 Spring Bootは内部でのロギングにApacheのCommons Loggingを使っている。 Commons Loggingはファサードライブラリだ。 つまり、Commons LoggingはロギングAPIだけをアプリケーションに提供し、実際のログ出力処理をするロギング実装ライブラリへの橋渡しとして機能する。 ロギング実装ライブラリには色々な選択肢があるが、Spring BootはJUL、 Log4j 2、Logback用のデフォルト設定を備えているので、これらのいずれかを使うのが楽であろう。 全てのスターターはspring-boot-starter-loggingというロギングスターターに依存していて、これがLogbackを使うので、普通はそのままLogbackを使うことになる。 spring-boot-starter-loggingは、JUL、Commons Logging、Log4j、SLF4Jによるログ出力をLogbackにルーティングするため、アプリ側や他の依存ライブラリがこれらを使っていてもLogbackに一本化できる。 spring-boot-starter-loggingの代わりにspring-boot-starter-log4j2に依存し、Log4j 2を使う方法もあるが、Goslingsには普通にspring-boot-starter-loggingを使った。 また、Goslings本体のログ出力には、プレースホルダを使いたかったのでSLF4Jを使った。 Spring Bootアプリにおけるロギング設定 Spring Bootが備えているデフォルトのロギング設定は、ERROR、WARN、INFOレベルのログをいい感じにフォーマットしてコンソールに吐くというものになっている。 以下この設定の変更方法などを書く。 ファイルへのログ出力 ログをファイルにも吐くようにするには、logging.fileというプロパティでファイルパスを指定するか、logging.pathというプロパティでディレクトリパスを指定すればいい。 (後者の場合ログファイル名はspring.logになる。) Spring Bootアプリでプロパティを指定する方法は色々あり(こことかここ参照)、大抵はapplication.propertiesで指定するんだろうけど、手軽にコマンドラインで以下の様に指定することもできる。 java -jar build/libs/goslings-0.0.1.jar --logging.file=build/hoge.log ログファイルはデフォルトで10MBでローテーションする。 ログレベル ログレベルには重大度の低い方からTRACE、DEBUG、INFO、WARN、ERROR、FATALの6段階があり、指定したログレベル以上のログが出力される。(OFFというログ出力を止めるものもある。) つまりSpring BootのデフォルトのログレベルはINFOだということだ。(LogbackにはFATALがなくERRORとして出力される。) ログレベルはlogging.level.<ロガー名>という形式のプロパティで指定できる。 例えばコマンドラインから指定するなら以下の感じ。 java -jar build/libs/goslings-0.0.1.jar --logging.level.org.springframework.web=DEBUG 全ロガーのログレベルはlogging.level.rootで指定できる。 ロギング実装ライブラリの設定 ロギング実装ライブラリの設定ファイルをカスタマイズして、より詳細な設定をすることもできる。 Logbackの場合、クラスパスのルートに置かれたlogback-spring.xmlかlogback.xmlがロードされる。 設定ファイルの二重初期化を防いだりSpring Boot拡張設定を利用可能にするために、前者のファイル名が推奨されている。 (Groovyが使える環境ならlogback-spring.groovyでもいい。) いつものようにjavaコマンドでアプリを起動する場合は-jarオプションを使うため、-cpオプションでクラスパスを指定しても無視されてしまうので、基本はlogback-spring.xmlはjarの中に入れることになる。 プロジェクトのリソースディレクトリのトップ(デフォルトではsrc/main/resources/)にlogback-spring.xmlを置いておけば、GradleのJavaプラグインのprocessResourcesタスクによってjar内の適切な場所に取り込まれる。 logging.configプロパティで設定ファイルのパスを指定することもできる。