PageObject について調べて、考えを改めた話

こちらの発表資料を拝見して、僕も PageObject って頑張らないといけない印象を持っていたけど、本当に頑張らないといけないんだっけかな?-と思い、 PageObject について考えたこと、調べたことのまとめです。

 

 

speakerdeck.com

 

僕が過去に苦労していたこと

ページ要素の収集。IdやName属性がHTMLタグになく、必要な要素のXPathを取得していたこと

アプリケーションの操作で画面要素を隠蔽していなかったこと。Getterで隠蔽はしていたけど、それを隠蔽というかは疑問。

 

僕がやっていたこと

PageObject という名で、ページ上のWebElementを集めたクラスを作っていたこと

 

PageObject について調べたこと

そもそも誰が考えたのかなーって調べたら、Martin Fowlerさんの記事が見つかりました。

martinfowler.com

 

気付いたこと

PageObject が提供するAPIは、アプリケーションの操作でありページ要素を隠蔽するということ

PageObject を利用する必要があるテストの目的が、例えばユースケーステストだとすると、そのユースケースにおいて利用される画面操作をAPIとして提供すれば良いということ。つまり、APIが必要とするページ要素だけを取得すれば良いということ

ただし、これは PageObject が提供するAPIユースケーステストで利用されることを前提とした話なので、 PageObject の設計については都度考える必要はある

 

そういえば、 PageObject ってどう設計すれば良いの?っていう疑問は、息子が生まれる前だから、 1 年前くらいから持ってました。今回の記事をきっかけに、理解が出来て良かったです。

 

アプリケーションの操作 = ユースケースの 1 課程と捉えると、ICONIXのモデル(シーケンス図)は PageObject 設計に利用出来るかなと思うので、今度実験してみたいと思います。

 

気付かせてくれた snowhiro さんには感謝です。

JJUG CCC 2017 Spring で話そうと思ったけど話さなかった JPA の話

実は準備が簡単だったので、JPA の話も用意してたり。

自分の振り返りにはちょうど良かった。

www.slideshare.net

JJUG CCC 2017 Spring の懇親会でLTさせて貰った話

今日はベテランのJavaユーザの方々がいる中、LTをさせて貰いありがとうございました。

一番大事なのは、懇親相手を見つけることでしたがLTやって終わってしまいました。

 

次は事前に準備してリベンジしたいな~(^_^;)

 

www.slideshare.net

Spring Framework はじめました

久しぶりにチームで開発をできることになったので、フレームワークの選定をしました。

 

フレームワークを使って実現したかったこと

  • お願いする人と作る人が互いに共通のコンテキストに基づいてイメージしながら会話が出来ること(作るときに間違いを少なくすること)

 

例えば…

僕(お願いする人):

「まず、僕の方で○○画面にボタンを追加しておいたから、それをクリックしたらこのカンプにある画面に遷移してーコントローラにリクエストハンドラを追加して、追加したテンプレートビューにリダイレクトしてー、イメージできてるかな?分からなかったら説明しよう)

Aさん(作る人):

「あぁ、コントローラにリクエストハンドラを追加して、追加したテンプレートビューにリダイレクトすればいいですね。カンプにあるテンプレートビューのベースHTMLはあります?ー」

僕(お願いする人):

「あるよ。テンプレートにはThymeleafを、スタイルはBootStrapのを使ってね。じゃあ、新しく作る画面の説明をするね。これは■■の情報を入力する画面で、登録ボタンを押したら確認画面を表示するんだけど、遷移前に入力値のチェックをしたいんだー(よかった、バッチリだ。新しい画面については、まずカンプを参考にしてInputタグを配置して、スタイルを適用するところから始めてくれるといいな。入力値チェックはBean Validationを使ってー)

Aさん(作る人):

まずは、カンプを参考にしてInputタグを配置して、スタイルを適用するところから始めますね。出来たら見てください。入力値のチェックは■■入力画面に対応するFormクラスにBean Validationを追加していけばいいですね。項目チェック仕様を見てもいいですか?ー」

 

このように、フレームワークを通して共通のコンテキストに基づいて、ユーザ要件を反映した外部設計の結果を作る人に伝える際に、お互いが同じ内部設計をイメージできると、プロジェクトが整理されるので気持ちがいいなと思います。

 

勿論、プログラム設計書を作って説明する―という手もありますよね。

開発手法に囚われすぎず、脱線しすぎず、状況に応じて仕事の進め方を変えられるように判断する為の知識を持っていられるといいな―と思います。(適切なアドバイスをしてくれるプロマネがそばに居てくれると最高ですね。)

 

  • フレームワークのコンテキストに基づき設計されたパッケージに、意図した通りコードを実装して貰えるようにすることで、後々ジョインする人がそのフレームワークのコンテキストを持っていれば、すぐにコーディング出来るようにすること(保守対象を分かり易くしておくこと)

 

例えば…

僕(お願いする人):

「今回入った改修の説明をするね。これは■■の情報を入力する画面で、登録ボタンを押したら確認画面を表示するんだけど、遷移前チェックしている入力値のチェック仕様を変更したいんだー入力値チェックは■■画面のFormクラスにBean Validationを使って実装されているから、そこを修正してー)

Bさん(作る人):

「今回の言語はJavaで、使っているフレームワークはSpring MVCですから入力値のチェックは■■入力画面に対応するFormクラスのBean Validationを変更すればいいですね。項目チェック仕様と変更仕様を見てもいいですか?ー」

 

このように、フレームワークを通して共通のコンテキストに基づいて、すぐに改修箇所をイメージしてコーディングに移れると、仕事が早くてお互いにもPOにもハッピーだなと思います。

 

経緯

今回、フレームワークの選定を自分で改めてしようと思ったのは、作る人だけに内部設計を任せっきりになっていたのを止めて、お願いする側(僕も含めて)にも内部設計出来るスキルを養いたかったからです。(少なくとも僕と同じチームになったメンバーには、そうなって欲しいなと思っています。)

 

上記では「作る人=プログラマ」でしたが、プロジェクトの状況によっては「作る人=別組織に所属するSE」というケースもあります。

いずれにしても、人がする仕事なので、やることは同じでもその人のコンテキストに基づいて内部設計が行われます。

 

この結果どうなるかというと、項目チェックがリクエストハンドラに実装されたり、サービスに実装されたりします。

これが繰り返されると、もう改修するのも危なくて触りたくないアプリケーションが出来あがってしまいます。

 

アプリケーションは、業務を遂行するために使われたり、サービスにおいては時には稼ぎ頭となって使われたりします。(ECサイトはその最たる例だと思っていて、店舗がオープンしていなければ売り上げは生まれません。極端ですが、僕らの給料の原資となる会社の利益も生まれません。)

 業務の効率や質を良くする為、もっと売上を増やす為に、アプリケーションは改修を繰り返していきます。

 

そんな時に、直す箇所を誰も知らないアプリケーションがあったらどうでしょうか。Aさんのように最初に作ってくれた人がいつまでも居るわけではありません。

 

改修を担当することになったCさんは、まず改修箇所を探す事から始めます。

ようやく見つけた箇所を直したと思ったら、別の箇所がおかしくなったと声が掛かり―なんてやっていると、改修結果が反映されるまでいくら時間があっても足りません。

(危ないから)テストケースを増やそうといった、工数を増やすような判断―この場合や状況に応じては正しいかもしれませんが―に至ってしまいます。

 

一方、すぐに直す事が出来て、改修をリリースできたら、少しでも早くから売上や利益を作る時間を確保できます。

 

カッコつけっぽいですが、一応はこういう意識で仕事をしてます。サービスを運用して稼ぐビジネスでは、運用する人たちは稼ぎ頭ですし。彼らの運用効率が下がれば、時間が掛かり余計なマンパワーが発生して利益は下がります。

僕たちが声を聞くし、それを素早く形にするから、そっちもそれに応えてね―って気持ちです。こう考えて仕事(開発・保守)をした方が楽しいです。

 

だから、正確に品質を保ちつつ開発し、すばやく保守する為に、フレームワーク選定を通して必要なポイントを身に付けようと考えました。

 

選定条件

  1. お願いする人は、何を作ればいいかを明確に説明できること
  2. 作る人は、説明を聞いて何を作ればいいか明確にできること
  3. アプリケーションが完成してなくてもテンプレートビューのデザインを確認できること
  4. コミュニティに参加して、他のユーザと話ができる環境があること
  5. 自分たちが使える言語であること

 

1、2番は共通認識を持てる概念が整っていて、理解しやすければOKです。

 

3番は画面イメージを作ったらすぐにフィードバックを貰いたかったので、JSPは避けたいと思いました。

また、メンバーのスキルを考えたときに、デザインを確認するために、画面の作り方(スタイルの適用)、サーバアプリケーションの仕組み・作り方を一気に説明して混乱させるより、HTMLを書いたら画面をすぐに確認出来た方が、ステップバイステップで教えられるので良いと考えたのもありました。

 

4番は日本 Selenium ユーザコミュニティやテストのコミュニティに参加した経験から、いろいろな方にお世話になったな―と思っていた為です。

社外の方が圧倒的にユーザ数が多いので、情報量も多いだろうと考えました。

 

技術的な条件である3番以外は、フレームワーク自身が備える性質だったり、TwitterJJUGを通して肌で感じていたことだったので、3番を中心に調べました。

 

その節は、とても助けられました (*^。^*) 

 

この結果、その条件を満たすThymeleafテンプレートエンジンを組み合わせて使えるフレームワーク Spring(Spring Boot)を選択しようと決めました。

 

フレームワーク決定後に気付いた大事なこと

実際に使い始めてから、いろいろな方に助けてもらいました。

 

外部データの扱いに疑問を持っていたとき

 

リリースを効率化する方法を探してたとき

 

application.ymlの 設定で困ってたとき

 

ThymeleafのValidationで困ってたとき 

 

(´;ω;`)ブワッ

僕も誰かにお返ししたいという気持ちになります。

だからコミュニティに人が集まるのでしょうね。

 

参考にしている書籍、ドキュメント

内容が濃いです。

2週目からは、痒いところに手が届いていることに気付いてゾクゾクしてきます。

1月中頃から使っていますが、時々読み返してます。

 

後は、Spring Project Documentation 、stack overflow、Blogに助けて貰ってますが、そろそろSpring Securityについてはアーキテクチャを理解して?、authenticationを独自実装したり応用したいなーと思ってます。

 

使い方を覚えるためにそれなりに時間を要しましたが、1月中頃から使い始めて直ぐにパッケージングから役割分担も出来て、フレームワーク導入は順調にスタートしました。

 

きっと、上記イメージどおりにメンバーと開発しながら、今回の選定目的を果たすことができるでしょう。これからが楽しみです。

新しい取り組み、振り返り

今回、自身でフレームワークを選定して、それについて教えながら開発に取り組むことが初めてだった為、振り返りの為にやったことをまとめて置こうと思います。

開発前に準備したこと

  • どんな風に進めていきたいかを考えた
  • 開発後にどんなチームになっていたいかをイメージした
  • メンバーにお願いしたいことを考えた
  • メンバーの現在のスキル、今後どうなりたいか、現状を踏まえて自分はどう行動するといいかを考えた
  • メンバーが出来るようになると、ハッピーになることを考えた
  • 実践と説明が簡単な開発手法を探して、自分で実践してみた
  • 実践したことをメンバーに説明して、取り組み方のイメージを描いて貰った
  • メンバーが困ったときに参照出来るように、ツールや必要に応じて手順をドキュメントに残した
  • ユーザーストーリーとタスクをバックログにまとめた

開発中にしていたこと

  • バックログを見ながら進捗の確認と、課題や疑問の確認をした
  • 一人で出来ないことは同じ画面をのぞき込んで解決した
  • フレームワークの使いながら覚えて教えること
  • 難易度が高い(と思っている)事の調査、コーディングをした

やりたいけれど出来ていないこと

  • 他に時間を取らざるを得ず、出来るようになってほしいことをコーディングしながら説明することが出来なくなったこと
  • ミーティングの開催頻度が下がったこと

振り返って思ったこと

  • 調べて出来るようになることが多い
  • やり方とやることを説明した結果、成果を見られるのは素直に嬉しい
  • 自分からやってくれるタイプのメンバーなので、出来るようになってほしいこと(開発手法)を説明する何か(ドキュメントとか)があると、各自の都合に合わせて開発を進められそう
  • 調査に時間を要し、自分一人の開発になっている
  • 調査結果を共有していない
  • 全部が全部、何々をしてから説明しようーとか考えず、お願いしたら出来る事はもっとあると思う
  • こうしたいんだけどーって、メンバーに相談してみたらいいと思う

今回は、折角の機会なのでアジャイルに開発を進めてみようと Visual Studio Team Services を使って開発しているのですが、形だけで一人前であまりイテレーションを回せてません。同じイテレーションにタスクを増やしちゃっているし…(^_^;)

 

原因は、未経験の技術(フレームワーク)を使う事に時間が掛かっていることじゃないかな?と最初考えたのですが、経験していたら上手く出来るのか?と言うと…

 

自分がこの状況を改善する為に出来ることを考えてみると、自分で実践して分かったら伝えるーみたいな格好つけ精神が原因なのかなーと思いました。

自分の悪癖っぽいです。

 

後は、管理的なこと。他のこともやりながらなので、イテレーション期間中、各タスクにどれくらいの時間をかけようかを書き出して、予実を見ていくことが大事でした。

予実が見えれば今後のイテレーションの中で最低限、必要とする時間の確保にも走れますし。

つい、時間外や時間が出来たらとー自然と考えがちみたいなので、ここは意識してやろうと思います。

 

こう改まると、久しぶりに振り返った気がしてきます。

来月も振り返ろう。

スレッドについて調べる為に「Javaパフォーマンス」を読んだら良いことだらけだった話

きっかけ

普段からよく利用するTomcatにおいて意図したスループットを得るためには、どうやらスレッドについて理解すると良いんじゃないかと考えがこと。

そもそもJavaのスレッドってなんなのか調べようと思い、本書ではスレッドについて言及されていた為、本書を読みました。

Javaパフォーマンス

Javaパフォーマンス

 

結局、本書からは当然ながらスレッドに関する明確な答えは得られませんでしたが、アプリケーションの開発/運用において大切なことを学んだ気がするのでまとめたいと思います。

 

学んだこと 

全体を俯瞰する

監視対象の状況を全体的に俯瞰するためにも、まずはテスト環境でJava Flight Recorderを使ってみたいと思います。その便利さを体感できたら、本番でも利用することを進言したいと思います。

 

意識する指標の明確化

今までのパフォーマンステストを振り返ると、スループット、レスポンスタイムのどちらもごっちゃになったテストをしていたように思います。

今後はこれらの違いを踏まえたテストをやり直そうと思いました。

 

CPU100%が悪いとは限らない

高負荷状態が長時間続いたら何かの予兆だと感じるのは大切だと思いますが、その瞬間で見ると複数のCPUが全て実行されていることで100%になっている場合もあります。

対象の環境での適切な状態をCPUのコア数を把握したりすることで、実行されるスレッドがいくつになるとCPUの使用率が瞬間的に100%になるのかを予め想定した上で、異常な状態を早期検知できるようにしたいなと思いました。

 

JITコンパイラの役割

JavaJavaバイトコードと呼ばれるアセンブリ言語による命令を生成しますが、CPUに依存したバイナリコードはその時点では生成されません。

これがJavaのどの環境でも動作する所以なのですが、実際にJVMが実行する際にはJust In Timeコンパイラによってバイナリコードへと最適化されます。

この最適化の方法にも種類があり、ヒープの使用方法にも関係する為これを知らずにヒープのチューニングはできないと思いました。

 

JITコンパイラの種類

クライアントコンパイラでは早期に全コードのコンパイルが行われます。一方、サーバコンパイラは実行されるコードのうち、よく利用されるコードを最適化対象としてバイナリコードへとコンパイルします。

よって、ヒープサイズが大きければクライアントコンパイラによって全コードバイナリコードに最適化されますが、小さい場合は途中で最適化が止まってしまうこともあるようです。

ここを知らないとインタプリタ型の言語と同様の実行方法のままになってしまう為、要注意だなと思いました。なお、以下のコードキャッシュがそれに当たります。

起動処理の最適化

起動時間のスピードが求めらる場合は、早期に最適化するクライアントコンパイラを利用すると良いです。

コードキャッシュのチューニング

コンパイルされた命令が格納される領域であるコードキャッシュサイズを調整することもできます。ここの領域がいっぱいになると本来高速に実行されるべきコードが高速に実行されなくなる場合がある為。jconsoleでコードキャッシュサイズを監視する。

 

ヒープ領域

メモリにはヒープ領域と呼ばれる領域があり、old領域、young領域(eden、survivor)で構成されています。一般的に、オブジェクトは生成されるとedenに話入り当てられます。ガベージコレクションが発生すると利用中のオブジェクトはsurvivor、old領域に移ります。そして、old領域がいっぱいになると未使用のオブジェクトはフルガーベッジコレクションによって破棄されるーという仕組みになっています。

Javaの基本だそうですが、本書を読むまで私は知りませんでした。読み終わってから思ったことですが、これらはJavaアプリケーションが適切にメモリを使っているかを意識、チューニングする為の基礎知識ですね。

 

ガーベッジコレクタの種類

スループット型ガベージコレクタ、コンカレント型ガベージコレクタがあり、前者はold領域から未使用オブジェクトが破棄される際に、アプリケーションスレッドを停止しますが、後者はフルガーベッジコレクションに近い処理を行う前にコンカレントサイクルというold領域の解放をアプリケーションスレッドと並行して実行することで長時間のアプリケーションスレッドの停止を避けることができるようになっています。

一見すると後者の方が良さそうにも見えますが、old領域の解放だけでコンパクト化は行わないので、young領域からold領域への昇格にold領域の未使用オブジェクトの解放が追いつかない場合はconcurrent ode failureに伴うフルガベージコレクションに近い処理が走りアプリケーションスレッドが停止するので、ガベージコレクタの種類に応じたアルゴリズムを把握しておくことはパフォーマンス劣化の原因分析の為にも大切だと思いました。

 

ガベージコレクタのチューニング

ヒープサイズの変更

ヒープサイズが小さ過ぎれば、ガベージコレクションが多発しアプリケーションのパフォーマンスは下がります。

ヒープサイズが大きくても、ガベージコレクションの時間は長くなる上、スワッピングが同時に発生するとディスクI/Oも同時に発生し、パフォーマンスは下がります。これがフルガベージコレクションと同発すると自体は最悪になる場合もあります。

この為、適切なガベージコレクタを選択することと、アプリケーションが必要とするヒープサイズを知ることはチューニングの基本となることを知りました。

並列度の指定

ガベージコレクションによって実行されるスレッド数は指定できます。また、ガベージコレクションとアプリケーションのスレッドの実行比率を指定できます。

このことから、マシンの適切な状態をパフォーマンステストで予め把握できるなと思いました。

ガベージコレクタのアルゴリズムの理解

「ガベージコレクタの種類」でも思ったことですが、アプリケーション実行環境のガベージコレクタの種類とその特性を理解した上で、デフォルトの設定によるパフォーマンスが許容範囲に収まっているかを判断するのは、一つのパフォーマンステストに当たると思いました。

実行環境、JVM自体、JVMno設定を把握しておかないと、どのタイミングでフルガベージコレクションが走るかや、その際のCPU使用率がどうなるかーなども適切なパフォーマンステストもできないなーと思いました。

 

ガーベッジコレクションのログ

ガベージコレクションのログを記録しておくことで、ガベージコレクションの解析を行うことができます。その中でもGC Histgramを活用するとGCによるオーバヘッドをチェックすることができるので便利だと思いました。

また、現状を抑えておけば、取得しておいたログの解析時にガベージコレクションの振る舞いが現状で想定されるものなのかどうかも判断がつくと思いました。

 

ヒープヒストグラムとヒープダン

ヒープヒストグラムではヒープに存在するオブジェクトのヒストグラムを表示してくれます。この為、無駄に生成されているオブジェクトの発見や、ガベージコレクションが頻発する原因の分析に役立てられることを知りました。

また、解析にはその状況を再現する必要がある為、予めヒープダンプを取得しておくと良いということも学びました。

ヒープを非効率に使用するようなアプリケーションになっていないかどうかをチェックして改善するためのテストにも使えるなーと思いました。

ただ、オブジェクトの生成元を辿っていくのは大変みたいですが…

 

OutOfMemoryError対策

メモリリークやヒープ領域を使い尽くしていることが一つの原因として引き起こされるエラーですが、メモリのサイズが問題なのか、アプリケーションロジックが問題なのかを適切に状況把握する必要があることを知りました。

というのも、適切にメモリを使用するようにプログラミングされたアプリケーションに対して用意されたヒープのサイズが小さいだけといった単純な場合から、コレクションのように自動的に解放されないコレクションが残り続けるようなケースもあり、アプリケーション側で対応しなければならない原因もあるためです。

このようなケースについては、生成するオブジェクトが参照されなくなったらガベージコレクタに解放されるように参照状況を制御する必要があることを知りました。

オブジェクトの参照の仕組みを理解して、アプリケーション開発時のコードレビューするポイントとしたいなと思いました。

 

Javaアプリケーションの合計メモリ使用量

これはネイティブメモリとヒープの使用量を足したものです。

Javaアプリケーションの実行環境におけるメモリサイズと合計メモリ使用量の関係もスワッピングの発生によるパフォーマンスの低下と関係するため大切です。

 

まとめ

結局、本書からはスレッドとは何かーという本来知りたいことを調べることはできなかったのですが、Javaアプリケーション/利用するプログラムの動作原理を理解することの大切さについて気づかせてもらえたので、棚から牡丹餅だったと思います。

おかげで、今後こんなことをしていきたいなと思いました。

  • パフォーマンスに関する要件定義、作り込み方の見直し
  • アプリケーションのコードレビューの見直し
  • アプリケーションパフォーマンステストの実施方法の見直し
  • アプリケーションサーバ、アプリケーションの監視方法の見直し

 

また、今回の学習を通して調べたクラスローダーについて、こちらのサイトから以下のようなことも学ぶことができました。

IBM developerWorks 日本語版 : クラスローダーとJ2EEパッケージング戦略を理解する

  • JVMが使用するメモリの構造(Permanent領域)
  • クラスローダの働き・目的
  • Webアプリケーションのクラスローダの仕組み
  • JavaEEアプリケーションのパッケージング戦略
  • サーブレットが参照するメモリ

 

後日談 ースレッドについて理解できた話ー

後日、Twitterで「JVMについてもっと知りたいなー」とつぶやいたら、親切な方が以下のドキュメントの所在を教えてくれました。

The Java® Virtual Machine Specification

 

これを読んだおかげで、次の情報を調べる糸口を掴むことができ、Javaのスレッドとスレッドとは何かーについて理解することもできました( ´ ▽ ` )

 

JVMのスレッドについて

Chapter 17. Threads and Locks

Threads may be supported by having many hardware processors, by time-slicing a single hardware processor, or by time-slicing many hardware processors.

Threads are represented by the Thread class. The only way for a user to create a thread is to create an object of this class; each thread is associated with such an object. A thread will start when the start() method is invoked on the corresponding Thread object.

上記から読み取ったこと

  • プロセッサがサポートするスレッドを作る為に、スレッド実装者がJavaのThread.classのオブジェクトを生成する。それを起動するにはstart()メソッドを使うーということ
  • スレッドはJava固有の概念じゃなくてハードウェアに依存するものであるーということ

 

プロセッサがサポートするスレッドについて

www.youtube.com

 

プロセッサがサポートするスレッドをJavaで制御する様子

こちらの記事を見つけたおかげで、マルチスレッドはプロセッサ、OSがサポートするもので、それを利用する為にJavaプログラマはThread.classを利用してマルチスレッドを実現できるということを理解しました。よかったよかった。

d.hatena.ne.jp

 

結構な回り道になりましたが、Servletコンテナで意図するパフォーマンスを得るための勉強に今回学んだことを生かしたいと思います。

Pitalium を使って回帰テストを実践した時の話

はじめに

今回は12/18 に発表した「キーワード駆動テスト」の実践の中で利用したPitalium を使って、回帰テストを実践した時の話をします。

キーワード駆動テストシステムを構築した時は、マルチブラウザテストを並列実行するーというロールを委譲する対象としていました。

しかし今回は、並列実行以外にも任意のテストのデグレードを検知するーというロールの委譲先としても活用しました。

次節ではその時の考え方や実践内容について整理した話をします。

Pitalium を使って回帰テストを実践した時の話

 

www.slideshare.net

まとめ

スライドではPitalium はもとより、ツールを理解するときのポイントと、ポイントを押さえる事で実現したいことを具体的に明らかにできることを示しました。

Pitalium はとても素晴らしいプロダクトだと思います。本スライドが少しでもPitalium を利用しようとしている人の役に立ち、ひいてはPitaliumの利用者拡大に繋がれば幸いです。