「兼チャレ」「兼任」という制度を活用してみました

はじめまして、インフラチームの内田です。主に社内ネットワークを担当しています。 ウィルゲートでは「兼チャレ」「兼任」という制度があり、私は前年度に両制度を活用して開発室以外の部署に兼任していました。 「兼チャレ」「兼任」という制度について、またその時の感想をご紹介いたします。

「兼チャレ」「兼任」という制度

「兼チャレ」「兼任」とは何か?

ウィルゲートでは「兼チャレ」と「兼任」という2つの制度があります。 「兼チャレ」「兼任」共に自分が所属する部門以外の部署への兼任に挑戦できる制度となっており、社員が多様な経験を通して自分、事業、組織を成長させるための挑戦機会を制度として実施しています。 2つとも部署を兼任するという点で同じですが、稼働と予算に対する考え方が違っています。

「兼チャレ」は主にチャレンジの意味合いが強く、ミッションや稼働工数は定められていません。 兼チャレ先事業部の上長と相談して何をするのか、何がしたいのか等を決めて業務として取り組んでいきます。 志望者が応募した後に両部署で検討およびすり合わせを行い、上長から承認を得て挑戦することができます。

「兼任」では明確なミッションが定められており、そのミッションを達成するために稼働や予算を調整して業務に取り組みます。 両事業部間で稼働について相談、どちらの事業部でどれくらい稼働するのかを決めてから業務開始となります。 兼任ではミッションを達成できそうな人を会社が選出して調整を図ります。 対象者の同意が得られたら両部署で検討およびすり合わせを行い、上長から承認を得て兼任が開始されます。

何故兼チャレに挑戦したのか?

自身について迷っていたので、色々経験してみたかった

私が兼チャレに挑戦してみようと思ったのは、自身のキャリアについて悩んでいたからです。 今までインフラのエンジニアとして働いてきたのですが、自分は将来どうなりたいのか、何がしたいのか。よくわからないまま日々の業務をこなしていました。 そうした時に主にコンテンツを企画しているチームが兼チャレを募集しており、「挑戦してみてはどうか」とマネージャーから声がかかりました。 私自身としても色々体験して自分の見識を広げたいと考えていたので、兼チャレに挑戦してみることにしました。

兼チャレに挑戦した成果と課題

全てが刺激的、未知の領域は楽しい!

今までずっと開発室に所属していたので、他の事業部で行われている業務について何も知りませんでした。そのため、兼チャレ先で行われていた業務は全て未経験で、とても新鮮でした。 お客様に直接納品するコンテンツとはどのように企画しているのか、今まで開発室が作ってきたツール等はどういった時にどのように活用されているのか。 今までは漠然としか知らなかった物が目の前で扱われていて、とても刺激を受けました。

自走できるメンバーに成長!

取り急ぎ兼チャレとして所属し、最初に行った業務はコンテンツの初期企画でした。 ウィルゲートではコンテンツマーケティング事業としてお客様に適したコンテンツを企画・納品しています。 その中で初期企画という業務ではお客様から「どんなターゲットを想定しているのか」「どんな情報を閲覧者に届けたいのか」等をヒアリングして企画書を作成し、お客様に納品する業務のことを指します。 0からコンテンツを企画したことはなかったので、世のコンテンツとはこのように作られているのか、と感銘を受けました。

より詳しくコンテンツについて知りたい方は、 検索ユーザーに愛されるコンテンツ設計について徹底解説~集客できるコンテンツとは?~ | プロモニスタ をご参考頂ければと思います。

「エンジニア」としての価値は提供できず

しかし、作業員としてコンテンツの企画・運用に徹してしまい、エンジニアとしての価値貢献はほぼ何もできていませんでした。 元々チームメンバーが少なく、運用する上で人の手が足りていなかったので一定の貢献はできていたと思いますが、それ以上の何かを残すことはできず兼チャレの期間が終了してしまいました。 運用について手を動かすことばかり考えていたので、考える方向を変えたらもっと良いものが貢献できたのではと思い悔しく感じたのを覚えています。

兼任として参画、求められているミッション

今度は兼任、兼チャレ時に出来なかった価値提供のリベンジ!

兼チャレ期間が終了して開発室所属に戻ると思っていたのですが、「引き続き兼任として業務を手伝ってくれないか」と声がかかりました。 チームメンバーが少なく私が抜けると運用が回らなくなってしまうので、運用が安定するまで協力して欲しいと。 私個人としては兼チャレ時に提供できなかったエンジニアとしての価値を今度こそ届けるチャンスと考え、承諾しました。 両事業部から承認が得られましたので、今度は兼任として所属、業務に取り組みました。

兼任に挑戦した成果と課題

今度こそ「エンジニア」として価値貢献!

今度は予め運用業務と効率化の両軸で稼働することを事前に決めておき、スケジュールや稼働工数もそのように分配して業務に取り組みます。 それが功を奏し、運用業務もそこそこに効率化に向けて稼働することができ、今まで手動で行われていた運用業務を自動化するマクロを開発し、運用を開始しました。 その結果としてマクロ導入前に比べて80%の稼働削減に成功、常に運用業務に圧迫されていたメンバーたちの負荷を削減することに成功しました。

他にも改善、チーム全体稼働50%削減を実現

その後も手動で行われている業務をマクロなどで自動化できるものは一通り自動化させていき、最終的にはチーム全体の稼働を50%削減することができました。 兼チャレから始まってようやくエンジニアとしての価値貢献ができたかと思い、やりがいと強い達成感を感じたのを覚えています。 そういった流れで兼任先には間違いなく価値貢献ができたかなとは思います。

今後はメイン事業部にも事例を共有したい

兼任先ではそういった成果を残してきたのですが開発室にはうまく共有できておらず、私ばかりが良い経験をしたという所で終わってしまいました。 今後は兼任に限らず新しい領域に挑戦した際は何が良いのか、何に苦労したのか等を開発室に伝えられたらと思っています。

まとめ

社会人として部署などに所属した場合、全く触れたことのない領域に挑戦するのは工数の兼ね合いや調整等とても大変なことだと思います。 しかし兼チャレという制度のおかげで未知の領域に挑戦することができ、とても良い経験をさせてもらいました。

また、今まで開発してきたアプリ等がどのように使われているのか、自分たちが組み上げてきたものがどうやって役に立っているのかを知ることができました。 場面によっては自分が使うこともあり、どこをどうしたらもっと便利に使ってもらえるのだろうか、といった発想まで繋がってアプリの改善を行うこともできました。 様々なことに興味がある人や自分のように迷走している人にとって、この兼チャレまたは兼任という制度はとても良い刺激を受けることが出来る制度だと思います。

PHPフレームワークのバージョンを上げるための取り組み

サグーワークス開発チーム PMの横道です。

前回はチーム目標に対する取り組みのお話しをさせていただきましたが、
今回はその取り組みの1つであるPHPフレームワーク(以下フレームワーク)載せ替えの取り組みの内容をお話していきます。

tech.willgate.co.jp

フレームワーク載せ替えの取り組みの背景

1年ほど前に実施したサービス全面リニューアルでフレームワークをCake1系から3系に載せ替えを行いました。

※その時の記事はこちら tech.willgate.co.jp

リニューアル完了時に載せ替えられたのはシステム全体の半分ほどでした。
フレームワークを載せ替えた箇所の新規開発や追加改修については整備されているので開発しやすい状態になっていますが、載せ替えが終わっていない箇所については開発しづらい為、開発工数がかかってしまうということが起きていました。
開発しやすい環境作りのために、フレームワークの載せ替え作業をチーム全員で協力して行っていくことにしました。

フレームワーク載せ替えするにあたって

サービスを成長させるための機能開発がある中で、意気込みだけでは並行してフレームワーク載せ替え作業を進めることはできません。
継続的にフレームワーク載せ替え作業を進めていくためにどうすればいいか考えた結果

  • 載せ替えない対象を明確化
  • 載せ替える対象を種別分けと優先度付け

上記の2点を決めてから取り組むことにしました。

継続的に進めるために決めたこと

載せ替えない対象を明確化

システム全体の半分を載せ替えるとなると開発工数がかなりかかってしまうので、載せ替え対象と載せ替えない対象の仕分けを行い、特に載せ替えない対象を明確にしました。

  1. 今後使われなくなる機能は対象外とする

    • 現在運用で使用していない機能は対象外
    • 使用頻度が低い機能は対象外(使用頻度を事業部にヒアリングして確認)
    • 別画面で代替え可能な場合は載せ替え対象外
  2. 上記の以外の機能の中で載せ替え対象の仕分けを行う

    • セキュリティの観点で重要な機能は載せ替え対象
      • ログイン機能やポイント換金機能など
    • サービスの主軸になる機能は載せ替え対象
      • サービス成長の過程で改修する可能性があるため
    • 上記以外は載せ替え対象外
      • (小さい機能に関しては、載せ替え作業を研修期間に課題として有効活用することもあり)

載せ替える対象を種別分けと優先度付け

載せ替え対象が明確になったので次は優先度決めと開発計画を立てていきます。
優先度は「開発」と「保守」の2種類に分類

開発:機能改修するときに対象の機能ごと作り直す
保守:現行の機能をほぼそのまま作り直す

「開発」に分類された機能

機能改修自体に事業部が考えている優先度があるため、その優先度に合わせて載せ替えを実施していきます。
載せ替えを行わない開発と比べ開発コストはかかってしまいますが、システム保守コストと追加改修があった際のコストを考えると投資するメリットがあることを事業部に説明し承諾してもらっています。

「保守」に分類された機能

開発側で順に対応していくので下記の内容で優先度決め、順次対応することにしていきました。

  1. セキュリティの観点で重要な機能
    • サポートが切れた状態で使用し続けることはリスクなので優先度を高くする
  2. 運営が不便に感じている機能
    • 作り直すついでに修正することで運営工数が下げる狙い
  3. 使用頻度の高い順
    • 使用頻度が高ければ追加改修が来る可能性が高くなるので早めに対処

事業部サイドでは開発予定していない内容ですが、事業部に必要性やメリットをしっかり説明することで理解してもらうことができたので、載せ替え作業を行う時間を確保することができました。

現在の進捗状況

開発に絡めて載せ替えを継続的に行っている為、この1年間で載せ替え作業をかなり進めることができていて、最近では古いフレームワークでの追加改修は全く行っていないので、主要どころの機能は一通り載せ替えることができたと実感しています。
あと半年ほどで載せ替え作業が終了する見込みが立っているので、引き続きチームで協力して載せ替えを進めていければと思います。

サグーワークス オンライン発注リニューアルプロジェクトを振り返って

 サグーワークスの開発をしている石川です。

 昨年度サグーワークスは、フレームワークを載せ替え、システムの大半をリニューアルし、サグーワークスの地盤を固めることができました。
 今回はオンライン発注リニューアルプロジェクトとその振り返りについてお伝え出来ればと思います。

 

サグーワークスとは

f:id:char1129:20180326184205p:plain

 サグーワークスとは、受託型記事作成サービスです。コンテンツを求める企業から、記事の制作依頼をいただき、記事の企画や構成を行なった上で、サグーワークスに登録しているライターの技量や経験に応じて、ライターに様々なお仕事を紹介しています。
 2018年2月、クライアントが記事をオンラインから発注することができる、オンライン発注機能のリニューアルをいたしました。

リニューアルプロジェクトの始まり

 今回の開発はリニューアルで、以前にもオンライン発注機能がサグーワークスにはありました。リニューアル前のオンライン発注機能は、昨年度のフレームワーク載せ替えリニューアルと並行して開発された機能であったため、リソースも期間も制約が厳しく、機能を限定した形でリリースに至りました。そのような状況で開発した機能でありながら、多くの発注者の皆様にご愛顧頂き、嬉しく思います。
 そして機能のリリースから1年が経過した2017年10月、記事のニーズの変化に合わせて、オンライン発注リニューアルプロジェクトが始動しました。

プロセス

 今回のリニューアルでは過去の発注者の声や要望を整理し、サグーワークスを運営する事業部だけでなく、コンテンツの企画をするコンサルタントやディレクターの協力を得て、初期の企画・要件設計、デザイン、プロトタイプが出来上がってきた段階で徐々に開発がスタートしていきました。
 今回のプロジェクトではUI/UXの改善も含めたグロースの観点も取り入れ、フォームの傾向分析、発注者の流れ、今後の改善施策の整理を行いました。ここで上がった施策の一部として、フォームの表示順の変更や、ボタンの表記の変更、数字の見せ方などがあり、現在いくつかは経過を観察しているところです。

リリース

 2018年2月20日、リニューアルされたオンライン発注機能をリリース致しました。リリース当日から発注があり、開発者、事業部から喜びの声があがりました。改めて作り手としてエンジニアとして、使っていただけることが嬉しく感じる瞬間でした。

プロジェクトを振り返って

 プロジェクトを終えてから、私たちはwebディレクターを交えての振り返りの機会と、チームメンバーとKeep, Problem, Tryに分けたKPT形式で振り返りを行いました。
 ディレクターとの振り返りでは、運用面で改善した点や今後に向けての課題が上がりました。運用面での改善した点では、社内のコミュニケーションツールとして利用しているSlackとシステムとの連携や、発注者が作成した案件の情報を直接サービスに取り込み、記事の募集につなげられる点、納品が自動化し、出来上がった記事から発注者に届けられる点が運営メンバーにとって役立っている点で、別のフローにも早く取り入れたいという声が上がったと聞きました。一方で、現在の運用体制における課題や記事のニーズと品質についての課題、今後のサービスをどう成長させていくかといった課題があがりました。ここで上がった点は、今後の開発で変化させていき、サービスの成長につなげていければと思っています。

 

f:id:char1129:20180326184356j:plain


 チームでの振り返りで上がった今回の良かった点は、タイトなスケジュールの中、チーム全体で誰が何をしているのか把握できたこと、大きな機能の開発が先に完了し、全体の流れが確認できるように開発が進められたこと、テスト期間や検証期間、改善期間を十分設けられたことが上がりました。またチーム内でスケジュールの共有や連携を促す人が生まれ、各人が率先して作業のカバーを行う動きが取れていたことは、次のプロジェクトにも引き継いでいきたいことです。
 一方で、チーム内で情報の共有が初めからうまく行われていたかというと、そうではありません。チーム内でハブとなる形で状況を把握する人が生まれ、お互いのタスクを把握するところから、これまで以上にチームワークを発揮してプロジェクトが行えたことです。この経験から、プロジェクト開始のキックオフの意義、定期的なタスクの確認、報告・共有を行う必要性を再認識するきっかけになりました。

最後に

 プロジェクトが円滑に進行できたことは、多くの人々の協力があった上で成し遂げられたことだと思います。今回のプロジェクトに関わった皆さまに改めて御礼と、サグーワークスを利用してくださるユーザの皆さまにサービスを安心して末長く使っていただけますよう、今後も開発していければと思います。

JavaScript のグラフライブラリ比較 - 私達がChart.jsからHighchartsに乗り換えた理由 -

はじめに

新卒2年目(もうすぐ3年目!)のエンジニア、宮西です。

現在、私が開発に携わっているプロダクトでは、グラフを使って様々なデータを表示しています。 グラフ化の利点は、一目で要点を伝えられるところ。 開発中のプロダクトは分析系のサービスであるため、「分かりやすいグラフ」はとても大切な要素です。

今までは、Chart.jsというグラフライブラリを使って、これらの画面を作っていました。 しかし、より分かりやすくするために、高度な機能・柔軟なデザイン性が求められるようになりました。 その中で、Chart.jsでは対応しきれない部分がでてきたため、ライブラリの再選定を行うことになりました。
今回はその結果をお知らせしたいと思います。

技術選定に至った背景

やりたかったこと

今回作りたかったグラフは以下のようなものです。 f:id:miyanishi-yuki:20180319094555p:plain

具体的には、

  1. 折れ線グラフ・棒グラフ・積み上げ棒グラフおよび、これらの複合グラフを描画する
    • 複合グラフの場合、y軸が左右にあるグラフ(2軸グラフ)となる
  2. グラフの点とその周辺にマウスオーバーした際に、そのグラフを強調して表示する
    • 対象のグラフを太く、他のグラフを薄く表示する
    • 対象の点の情報をツールチップで表示する
  3. カーソルに追従する縦線を引く
  4. グラフの中に任意の文字や絵文字を表示し、クリックした際にイベントを発火させる
  5. その他、細かなグラフのデザイン(例えば、x軸のラベルの文字間隔など)を調整する

なぜ、Chart.jsではできなかったのか

Chart.jsは、HTMLのcanvas要素にグラフを描画しています。 実際に、Chart.jsで描画されたグラフがどのようなHTMLで構成されているのかを見てみると、canvas要素しかありません。 まさに、キャンバスに描かれた絵のようなものです。 そのため、決められたオプション以外の動きやデザインの変更は不得意という欠点がありました。

上記の「やりたかったこと」の内、1, 2はChart.jsでもできたのですが、3と4はChart.jsのオプションでは用意されていませんでした。 また、5についてはまさにChart.jsの不得意な分野でした。
少々強引な方法を使えば実現するものもありましたが、 別のグラフライブラリで簡単にできるのであればChart.jsに固執する必要はないと考え、 新しいグラフライブラリを探す決断に至りました。

比較した結果

結論

この技術選定の結果、Highcharts という有料のグラフライブラリを使うことに決めました。 以降で、比較したグラフライブラリについてと、比較結果を順を追って説明していきます。

選定候補のグラフライブラリ

今回選定を行ったグラフライブラリは以下の6種類です。

比較

最初に、比較に用いた記号の意味を説明します。

記号 説明
ドキュメントを読めば実装できる
可能だが、一工夫必要(許容できる範囲内)
可能そうだが、時間や手間がかかるので、なるべくやりたくない
× 許容できない手間がかかる

実際に比較した結果が以下の表です。

No. Chart.js Taucharts C3.js Google Charts amCharts Highcharts
1 折れ線グラフ・棒グラフ・積み上げ棒グラフおよび、これらの複合グラフを描画する ×
2 グラフの点とその周辺にマウスオーバーした際に、そのグラフを強調して表示する - ×
3 カーソルに追従する縦線を引く -
4 グラフの中に任意の文字や絵文字を表示し、クリックした際にイベントを発火させる × -
5 その他、細かなグラフのデザインを調整する △ or ×

Chart.js以外のライブラリはSVGを用いています。 SVGでは、グラフの点や線、軸やラベルなどのグラフの要素が、HTMLの要素で表現されています。 つまり、ライブラリが用意したオプションで指定しなくても、グラフ描画後にCSSでデザインの調整ができます。 そのため、5のデザインの微調整については、Chart.js以外はすべて○という結果になりました。

Tauchartsは、2軸グラフのデザインに問題がありました。
2軸グラフにした際に、y軸が左右に表示されるのではなく、左側に2つ軸が出てしまいました。 2つの軸が1ヶ所にまとまって表示される状態は見にくく、要件を満たしていないと判断しました。 そのため、Tauchartsについてはその他の詳細な調査を行っていません。

C3.jsは無料のライブラリの中でも高機能で、ドキュメントも充実していました。 調査を始めた段階では第一候補として考えていたのですが、マウスオーバー時に発火するイベントに問題がありました。 C3.jsのマウスオーバーイベント内では、「どのx軸上にカーソルがあるか」は特定できるようになっていました。 しかし、そのx軸上にあるグラフの内のどのグラフが選択されているのかは分かりませんでした。 そのため、2で挙げた「対象のグラフの強調」ができず、利用を諦めることになりました。

最終的に、要件を満たしたライブラリは3つありました。Google ChartsとamCharts、 そしてHighchartsです。 その中でHighchartsを選んだ理由は、ドキュメントの充実度とオプションの充実度、そして調査時に感じた扱いやすさでした。

Google Chartsは要件を満たした唯一の無料ライブラリでした。 しかし、Google ChartsはHighchartsやamChartsに比べて、ドキュメントの充実度は劣ると感じました。 実際、サンプルコードで実装されていた機能を別のグラフで利用しようとした際に上手く動作せず、 さらにドキュメントを読んでも理由が分からずに困ったことがありました。

amChartsはHighchartsと同等の機能がありながら、Highchartsより安価でした。 ドキュメントというよりはサンプルが多く存在していました。ここで気になったのは、ドキュメントの見やすさです。 基本的にサンプルベースになっているのですが、オプションの書き方などを体系的に理解するのが難しく感じました。 オプションやイベントが体系的に説明されたページもあるのですが、今度はサンプルの数が減ってしまいます。 これは個人の好みだと思うのですが、Highchartsのように、体系的にまとまっている中にサンプルが豊富にちりばめられているドキュメントは理解しやすく、魅力的でした。

おわりに

以上の理由から、私のチームのプロダクトでは、新しくHighchartsを利用する運びとなりました。 今回の要件をすべて満たすライブラリはなかなか見つけられず苦労しました。

最後の3つにしぼられた時、Highchartsを使いたいという気持ちがありましたが、値段のこともあり少し躊躇していました。 そんな時、一緒にプロダクトを作っている事業部の担当者から、
「エンジニアの皆さんが使いやすいものを選んで欲しい。無料でも、安くても、使い勝手の悪いものを使って消耗したり、工数がかかってしまうことは望んでいない。」
と言ってもらえたことで、Highchartsに決めることができました。 先日、実際に画面作成でHighchartsを使ってみて、使いやすさや柔軟さを実感しました。 (好みなどもあると思うので、あくまで個人的な感想ですが…。) 改めて、使い勝手を重視して決定させてもらえたことに感謝しています。

この記事が、これからグラフライブラリを使いたいと思っているかたの参考になれば幸いです。

【プロマネ】プロジェクトの「測る化」の実践

はじめに

開発グループPMO(プロジェクトマネジメントオフィス)の大嶋です。

過去10年近くのプロジェクトマネージャー(PM)的な役割を経て、下期からウィルゲート開発グループを横断的に見るPMOとしてゼネラルマネージャー(以下GM)を補佐する形で組織戦略の立案遂行や開発本部の運営、採用活動などを主なミッションとしています。実はこのブログ自体もそういった役割の一環として、よりよい形に変えていくことを意識しています(笑)

ウィルゲートは大きくコンテンツマーケティング事業とメディア事業があり、それぞれの事業の中でも大小複数の開発プロジェクトが並行で進んでいます。1週間~1ヶ月くらいで終わるものが大半ですが、中には半年からそれ以上の規模で動いているものもあります。

今回は、大きめのプロジェクトを対象としてコンディションを客観的な視点で見て必要に応じた打ち手に繋げるために、GMより託された『変化に強い計画・問題発見の技術 プロジェクトの「測る化」』の書籍を参考に行った取り組みをご紹介します。

変化に強い計画・問題発見の技術 プロジェクトの「測る化」

変化に強い計画・問題発見の技術 プロジェクトの「測る化」

 

 

プロジェクトの何を「測る化」するか

ビジネスにおいて「見える化」というワードは、トヨタ自動車が浸透させたものとして有名だと思います。ウィルゲートでも、主に開発プロジェクトの「見える化」はカンバン方式でタスク管理するツールを活用して行われてきています。

tech.willgate.co.jp

今回は「測る化」ということで、一歩進んでプロジェクトにおいて見えづらい指標を定量化する試みになります。
書籍に則ると、定量化するべきものは以下の「QCD+S」が対象になります。

  • Quality ・・・品質
  • Cost ・・・コスト
  • Delivery ・・・納期
  • Scope ・・・スコープ

この中でもスコープは普段なかなか見えづらいですし、ウィルゲートの開発プロジェクトにおいても進行途中で開発要件が変わることは少なくないので、特に注目して「測る化」をしていきました。
余談ですが、開発スコープが変わることはややもするとネガティブな捉え方もされがちかと思いますが、中長期のプロジェクトであるほど時間の経過とともに周辺の状況も変わっていくものなので、一定の変化はあるべきものと捉えて普段から計画や目標設定をしています。

どのように「測る化」したか

  • スコープについて
    まず最も注目したと述べた「スコープ」に関しては、ファンクションポイントを算出することで「測る化」としました。ファンクションポイントの考え方自体は1979年に提唱されているそうですがウィルゲートではほとんど初めての試みとなったので、Web上の情報を参考に算出方法をみんなで学んで実践しました。
    チームによってはスクラム開発手法に則りストーリーポイントを見積として使用しているところもありますが、今回はプロジェクト横断的に実践するために書籍も参考にファンクションポイントを使用しています。

    FP 法のイメージをつかむ - あしのあしあと

  • コストについて
    コストの「測る化」についてはこれまでも会計処理のために、毎月開発に掛けた工数(時間)をもとにして算出していたのでそれを転用しました。
    基本的にはエンジニア1名あたりの単価×人数となり、そこにそれぞれのプロジェクトへの稼働比率(100%専任なのか、2つを50%ずつなのかなど)を加味して算出しています。
  • 品質について
    品質についてはサービスで起きた障害事案は開発組織全体で統括的に管理しているんですが、プロジェクトが完了してしばらく経たないと評価できないものになります。従って今回はプロジェクトによって管理方法が異なることを理解した上で、リリースまでのテスト工程で検出したバグや、変更依頼の件数を障害管理表からカウントして使用することにしました。
  • 納期について
    今回は完了したプロジェクトを扱ったので、進捗状況の測定は対象としませんでした。
    代わりに、どのくらいのアウトプットしたのかを「測る化」するべく、カンバンのチケット数と、コード量を計測することにしました。
    コード量の測定は、以下のようにgit logコマンドをリポジトリ(ブランチ)別に、プロジェクトの期間(--since,--until)を指定して実行する形で行いました。
    ただしそれだけだとフレームワークや外部ライブラリのコード量もカウントされてしまうので、該当する箇所のディレクトリまで指定したコマンドを合わせて実行してその分を差し引く形にすることで、実際に記載したコード量だけをカウントするようにしました。

    # コード行数をカウント(全行数,追加行数,削除行数,総更新行数)
    git log --numstat --pretty="%H" --no-merges --since= <sincedate> --until= <untildate> --author="" <branch> <directory> | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d,+%d,-%d,%d", plus-minus, plus, minus, plus+minus)}'> output.csv
    # コミット回数をカウント
    git log --pretty=oneline --no-merges --since= <sincedate> --until= <untildate> --author="" <branch> <directory> | wc -l | awk '{printf "," $1}'>> output.csv
    # ファイル数をカウント
    git ls-files  | wc -l | awk '{printf "," $1}'>> output.csv 
    

 

「測る化」した結果

「QCD+S」の軸で3プロジェクトの「計る化」を行って以下のような数値がまとまりました。

f:id:oshima106:20180309192213p:plain

こうして得られた数字に対して、それぞれの指標を掛け合わせた係数を算出することでプロジェクトのコンディションを定量的に評価する基準値としていけるのではないか、と考えています。

f:id:oshima106:20180309193425p:plain

気をつけたこと

  • はじめに自分でやってみる
    こういった取り組みをする上で、現場のプロジェクトリーダーの協力は不可欠でした。
    開発業務に専念したい現場になるべく負荷を掛けずに実現するために、PMOである自身が先行して小規模なプロジェクトを対象に取り組んでみて成功イメージを作ることで、分担して現場にお願いするところとそうでないところを切り分けることができました。
  • 正確性の追求よりも早期実現を重視
    いわゆるスモールスタートというわけでもないですが、まず運用をはじめてそこから改善していければいいと考えて取り組みました。例えば今回初めて取り組んだファンクションポイントの計測では、完璧を求めて粒度を細かくしたり複数名でチェックして正確さを担保するといったことは避けて、「1時間で行える範囲で算出する」という取り決めで簡易的に行いました。コード量についても同様で、厳密に全てのライブラリ部分を除外したカウントするようなことはせず、おおよその規模感を出すことを優先しました。
  • 異なるサービスのプロジェクト間での横比較は行わない
    「測る化」をして数値が「見える化」されると、どうしてもそれを比較したくなってしまいます。
    しかし、プロジェクトごとのシステムを構成する言語・フレームワークミドルウェアだけでなく、関連する事業のステージやステークホルダー、サービスの特性も異なるので、横比較してもほとんど意味がないと考えています。従って比較は同じ事業/サービスや、時間軸で連続性のあるプロジェクト同士でのみ行うものとしました。(例えば、一連のプロジェクトのフェーズ1とフェーズ2で比較するなど)
    これまでのプロジェクトを遡って「測る化」は行っていないので今は比較対象がなく、今回を起点にして今後の比較基準に活用できればと考えています。

まとめ

簡単ですが、プロジェクトの「測る化」を実践してみた事例のご紹介でした。
書籍にならうともっと緻密に、様々な切り口での「測る化」の観点がありましたが、あくまで目的としてはプロジェクトのコンディション把握と改善であり、さらにはいかに価値のある開発を行うかということを忘れずに今後も継続していければと思っています。

新卒での1年間を振り返ってみて

昨年の4月に新卒で入社したエンジニアの吉田です。入社してあっという間に1年が経とうとしています。
入社前と入社後で感じた違いをまとめていきたいと思います。

入社の経緯

学生時代は専門学校で、Webデザインの勉強をしていて、Webサイトの企画からデザイン、実装までの技術を学んでいました。授業では、上流工程を学ぶことが多く、実装はフロントエンドの実装がメインでした。
授業外の活動で、2年連続で技能五輪Webデザイン職種に出場しました。技能五輪に出場したことで、授業ではほとんど勉強していない、サーバーサイドの技術を学びました。
企画からデザイン、サーバーサイドからフロントエンドまでの技術を競うので、Webに関わる技術に一通り触れることができました。
最初はフロントエンドエンジニアを目指していましたが、技能五輪でサーバーサイドの技術にも触れたことで、サーバーもフロントも楽しいと思い、どちらも挑戦することができる会社で働きたいと思っていました。
ウィルゲートを決めた理由としては、メディアの企画を行う部署と、開発サイドの距離が近く、話し合いながら実装しているのが良いなと感じ入社をしました。企画などの上流工程を学んでいたので、そちらにも興味があり、どちらにも関われるチャンスがあるというのがすごく魅力的に感じました。

普段の業務

普段の業務では、Millyの機能開発と運用保守を行なっています。サーバーサイドもフロントエンドも同じくらいの割合で開発を行っています。

Millyはウィルゲートで運営している、子育てを行なっている母親向けのメディアです。

millymilly.jp

学生時代との違い

学生時代は、1人での開発か、デザイナーと2人での開発で、自分がわかれば良い実装で、ローカル環境で開発していくというスタイルで開発を行っていました。しかし、入社すると複数のエンジニアでのチーム開発になり、サーバーが与えられ、新しいツールを使い、実装の規約が決まっていて、と全く違う環境での開発でした。技術面では技能五輪を経験したこともあり、なんとかついていけたのですが、環境面の違いに最初はかなり戸惑いました。

Git

学生時代ではGitを使ってのチーム開発を行ったことがありませんでした。軽く触ったものの、必要性を全く感じず使わずに作業を行っていました。なので入社した時は、ブランチ?コミット?プッシュ?という状況だったので、Gitの仕組みや操作を覚えるのに苦労しました。ブランチの仕組みを理解できず、別のブランチにプッシュしてしまったり、ミスをしながら作業していました。
そんな私でしたが、Gitを使っていくうちに仕組みが理解できてきたのと、社内でGitの勉強会があり徐々に理解することができました。

コーディング規約

cssのクラスの命名規則や、余白の取り方まで規約として決まっており、規約を守って実装していくというのに慣れるのも時間がかかりました。規約を読んだり、プルリクにコメントをもらったり、他の人のプルリクを見たりしながら規約を学んでいました。
規約通りの開発に慣れてくると、他の人が作った部分を読むことができるようになり、技術の理解も深めることができました。
最初は、覚えて実装していくのが大変だなと感じていましたが、規約を守っていれば保守性が高いソースコードにすることができました。

サーバー

ウィルゲートの開発環境は、1人1台の専用の仮想サーバ環境が整備されていてそこで開発を行っていきます。これまではローカルでの開発だったので、ターミナルでsshで繋いで...と、コマンドを覚えるのに苦労しました。コマンドはよく使うものについては覚えてきて操作することがきるようになりました。
さらに、鍵認証の仕組みも分からず、毎回パスワード入力を行っていたのですが、最近、鍵認証で入れるようにしたら簡単にサーバーに入れるようになり、感動しました。

ツール

フロントエンドの実装を行っていく際に、Zeplinというアプリを使用してデザインからHTML・CSSに落とし込んでいきます。余白の取り方や、カラーコードなどが簡単に確認できるのでPhotoshopで余白やカラーコードを確認するのに比べて何倍も早く実装することができました。
学生の頃に知りたかったです。

まとめ

チームで開発することに慣れてきた1年でした。知らないことばかりで入りましたが、先輩方にたくさん教えていただき成長することができました。
gitや規約など学生時代から挑戦しておけばよかったかなと感じています。そこの知識を得るための時間を技術の習得の時間にあてられたらと思ってしまいます。
下半期では、テストコードやDocker、Vue.jsといった技術に挑戦する機会をもらえたので、技術面でも新しいことに挑戦していきたいです。

Laravel で Amazon DynamoDB を利用するための実装 tips 集

ウィルゲートで開発を行っている岡田 (okashoi) です。

私の所属するソリューションチームでは web コンサルティングのためのシステムの開発を行っています。

現在開発中のプロダクトにおいて Amazon DynamoDB (以下、DynamoDB)を利用しており、 Laravel で DynamoDB を利用する際の実装上の tips が貯まってきたので紹介していきたいと思います。

DynamoDB 概要

DynamoDB は KVS と ドキュメント指向データベースの両方の特徴を併せ持ったデータベースサービスです。

概要は以下の通りです。

用途

  • 基本的には KVS のような使い方
  • 加えて、あらかじめ決めておいたカラムでの範囲検索ができる

メリット

  • レスポンスが安定して速い(KVS の利点)
  • 柔軟・スキーマレス(ドキュメント指向データベースの利点)
  • アプリケーション側だけ考えれば良い(フルマネージド)
  • ストレージに上限がない
  • 自動的にスケールさせることができる

デメリット

  • 決められた方法での検索しか出来ない
  • 特性を把握しないとうまくスケールしてくれない
  • トランザクションはない

より詳しい話については他の多くの方が資料や記事を公開しているのでそちらに譲ります。

以下、 tips を紹介していきます。

ORM には laravel-dynamodb を利用

Laravel といえば Active Record パターンの実装である Eloquent ORM を特徴として挙げる方も多いでしょう。

この Eloquent ORM とほぼ同様のインターフェースを、DynamoDB 用に提供しているのが baopham/laravel-dynamodb です。

github.com

packagist での人気(Installs, Stars)などから、私たちのプロダクトではこの laravel-dynamodb を利用することにしました。

例として DynamoDB 上に Movies というテーブルがある場合、以下のようなモデルを定義しておくことで App\Models\Movie::create() でレコードを作成したり、 App\Models\Movie::find()App\Models\Movie::get() を使ってデータの取得が行うことが出来ます。

<?php

namespace App\Models;

use Baopham\DynamoDb\DynamoDbModel as Model;

class Movie extends Model
{
    protected $table = 'Movies';

    protected $primaryKey = 'year';

    protected $compositeKey = ['year', 'title'];

    public $timestamps = false;

    protected $fillable = [
        'year',
        'title',
        'info',
    ];
}

Model の使い方としては以下を押さえておくと良いと思います。

  • 基本的に Eloquent Model と互換がある(Eloquent Model を継承しているため)
    • できるからと言って何でもかんでもやるのはよくない
  • $fillable なども記述する必要がある
    • デフォルトで $incrementing = false の上書きだけされている
  • テーブルの Key を明記する必要がある(Hash Key 名前が id の場合は $primaryKey は省略可)
<?php

    // Hash Key のみの場合
    protected $primaryKey = 'hash_key'

    // Hash Key + Range Key の場合
    protected $primaryKey = 'hash_key';
    protected $compositeKey = ['hashKey', 'rangeKey'];
  • Index(GSI, LSI)についても明記する必要がある
<?php

    // GSI , LSI ともに $dynamoDbIndexKeys に書く
    protected $dynamoDbIndexKeys = [
        'index_1_name' => [
            'hash' => 'index_1_hash_key_name',
        ],
        'index_2_name' => [
            'hash' => 'index_2_hash_key_name',
            'range' => 'index_2_range_key_name',
        ],
    ];

より詳しい使い方は README を読みましょう。

ちなみに、Model 内部の実装はこちらです。

laravel-dynamodb/DynamoDbModel.php at master · baopham/laravel-dynamodb · GitHub

使っているときに迷ったり、疑問に思ったりしたら実装を読んでみるのも良いでしょう。

マイグレーションRDBMS と区別しない

以前 Qiita にも投稿したのですが、RDBMS 用のマイグレーションと同じ場所に DynamoDB のマイグレーションも書いています。

qiita.com

理由も Qiita に書いた通りで「DynamoDB のテーブル管理のために特別なオペレーションを増やしたくない」に尽きます。

具体的には以下のようなコードになります。

<?php

use Illuminate\Database\Migrations\Migration;
use BaoPham\DynamoDb\DynamoDbClientService;

class CreateDynamodbGaTrafficRecordsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // テスト時には DynamoDB を利用しない
        if (app()->environment('testing')) {
            return;
        }

        $params = [
            'TableName' => $this->getTableName('Movies'),
            'KeySchema' => [
                [
                    'AttributeName' => 'year',
                    'KeyType' => 'HASH',
                ],
                [
                    'AttributeName' => 'title',
                    'KeyType' => 'RANGE',
                ],
            ],
            'AttributeDefinitions' => [
                [
                    'AttributeName' => 'year',
                    'AttributeType' => 'N'
                ],
                [
                    'AttributeName' => 'title',
                    'AttributeType' => 'S'
                ],
            ],
            // キャパシティユニットは仮の値を入れておくだけ
            'ProvisionedThroughput' => [
                'ReadCapacityUnits' => 5,
                'WriteCapacityUnits' => 5,
            ],
        ];

        resolve(DynamoDbClientService::class)->getClient()->createTable($params);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // テスト時には DynamoDB を利用しない
        if (app()->environment('testing')) {
            return;
        }

        $params = [
            'TableName' => $this->getTableName('Movies'),
        ];

        resolve(DynamoDbClientService::class)->getClient()->deleteTable($params);
    }

    /**
     * 環境ごとのテーブル名を取得
     *
     * @param string $tableBaseName
     * @return string テーブル名
     */
    protected function getTableName(string $tableBaseName): string
    {
        // 環境名を Suffix として追加する(理由は後述)
        return studly_case($tableBaseName) . studly_case(app()->environment());
    }
}

コード中のコメントにも記載したとおり、キャパシティユニット(以下、CU)に関しては、テーブル作成時は仮の値(最小の 5 とか)を入れておき、あとから管理コンソール上で値を更新するようにしています。

CU は環境(本番/ステージングなど)によって変わるうえに、運用の中で変化していく値でもあるため、マイグレーションで管理する必要性が薄いことが理由です。

また、マイグレーションに関しては他のパッケージの利用も検討しましたが、それぞれ以下の理由で採用を見送っています。

環境をまたいでテーブル名を一意にする方法

運用に際して「テーブル名は本番環境・ステージング環境をまたいでを一意にしなければならない」という問題に後から気が付きました*1

これについてはテーブル名の suffix として環境名(APP_ENV の値)を付与することで解決しました。

今まで Movies という名前のテーブルだったのであれば、本番環境なら MoviesProduction に、ステージング環境なら MoviesStaging に、といった具合です。

先述のマイグレーションgetTableName() メソッドが登場したのはこのためです。

Model が参照するテーブルも環境ごとに変える必要もあるわけですが、これは getTable() メソッドをオーバーライドすることで解決しました。

<?php

namespace App\Models;

use Baopham\DynamoDb\DynamoDbModel as Model;

class Movie extends Model
{
    // (略)

    /**
     * テーブル名を取得
     * 環境ごとの suffix を付ける
     *
     * @return string
     */
    public function getTable(): string
    {
        $baseTableName = parent::getTable();
        return $baseTableName . studly_case(app()->environment());
    }
}

複数の Model で DynamoDB を使うのであればこの getTable() は Trait に切り出してしまうのが良いでしょう。

APP_ENV が衝突する複数の環境が存在する場合は、各々の事情に合わせて一意になる suffix を付けてあげましょう。

その他細かな tips など

find() は強い整合性での Read しかできない

Qiita に書いてあります。

qiita.com

Range Key での BETWEEN 条件を指定する際は where($rangeKeyName, 'range', [$min, $max]) を使う

こちらも Qiita に書いてあります。

qiita.com

バッチ処理などのリアルタイム性を求められない Read/Write を大量に行うときには retry() と併用する

Laravel のグローバルヘルパ retry() と併せて使うことで「CU 超過していたら 1 秒待ってもう一回リクエスト」というロジックをシンプルに書くことができます。

<?php

$movies = collect([]);
foreach ($conditions as $condition) {
    // キャパシティユニット超過の場合、再リクエスト(ウェイト1秒)
    $tmpMovies = retry(2, function () use ($condition) {
        return App\Models\Movies::where('year', $condition['year'])
            ->where('title', $condition['title'])
            ->get();
    }, 1000);

    $movies = $movies->concat($tmpMovies);
}

// $movies を用いた処理
// :

このような書き方は、大量に読み書きをする必要がある代わりに、リアルタイム性が求められないバッチ処理において活用する方法があります。

CU を低めに設定してあると、そのCUをいっぱい使い切る速さで読み書きの処理が進みます*2

実際に試した場合の様子がこちらです。

f:id:okashoi:20180227154331p:plain

21:00~00:00 の間、消費 CU がプロビジョニング済み CU 付近に張り付いているのがわかります。

なお、一時的にプロビジョニング済みの CU を越えているのは、過去300秒分は未使用の CU を持ち越せる(バーストキャパシティ)ためです。

この方法は、同じテーブル(または GSI)に対して並列で読み書きが動いているとうまくいかないかもしれません。

おわりに

以上、 Laravel で DynamoDB を利用する際の実装上の tips でした。

今後もこのような tips ・ノウハウは貯まっていくと思うので、DynamoDB に限らず紹介していこうと思います!

*1:本番環境とステージング環境でリージョンが異っていれば問題ない

*2:ただし、1回の読み書きで超過してしまうくらい低い CU では動きませんが