フロントエンドエンジニアの嶌田です。2022 年 4 月からアクセシビリティ推進グループ(以下推進グループ)に在籍しています。今回はこの新しくできた部署について簡単に紹介します。また、会社や私がアクセシビリティに取り組む理由を語ってみようと思います。 弊社プロダクトのアクセシビリティを推進する取り組みは、これまでも有志が集まるワーキンググループの形で存在していました。ワーキンググループについては以前に Ltech という社外イベントで紹介しました。今年度からの新設部署はワーキンググループの流れを汲んでおり、推進活動に本腰を入れてコミットしていくために新設された部署です。 参考: Ltech#14 「LIFULL HOME'S」のフロントエンドについて語り尽くします! 開催レポート - LIFULL Creators Blog 推進グループは上長1名に、ほぼフルタイムでアクセシビリティにコミットするメンバー2名で構成されています。 アクセシビリティ推進グループの取り組み 推進グループのミッションは大きく2つに分かれます。プロダクト改善活動と、啓蒙・教育活動です。 プロダクト改善活動は、いまある LIFULL のプロダクトに手を入れてアクセシビリティ品質を改善していく活動です。現在の LIFULL のプロダクトには、キーボードやスクリーンリーダーで利用しづらい箇所が数多くあります。アクセシビリティを念頭に設計・実装されていなかったためです。そのため、このような問題を検出し、修正していく活動をしています。また、事業部やプロジェクトチームから持ち込まれる相談に乗ったり、デザインや実装のレビューを実施したりしています。 もう一方の啓蒙・教育活動は、プロダクト開発においてアクセシビリティが担保されるしくみを作っていく取り組みです。アクセシビリティの必要性や実践方法をレクチャーしたり、ガイドラインを策定し開発プロセスに組み込むといったことをしています。 このプロダクト改善活動と啓蒙・教育活動はどちらも重要と考えています。プロダクト改善活動に偏っては、新しくアクセシブルでないプロダクトが生み出されていく流れをとめられません。反対に啓蒙活動に偏っては、既存のプロダクトがはらむ問題点を解消しないまま先送りし続けることになってしまいます。 LIFULL とアクセシビリティ 専門部署を作る程度にはアクセシビリティに本気の姿勢をみせている弊社ですが、そもそも LIFULL はなぜアクセシビリティに取り組むのでしょうか? LIFULL は「あらゆるLIFEを、FULLに。」というメッセージを対外的に発信しています。世界中のあらゆる人々の人生を、安心と喜びで満たそうというメッセージです。「あらゆる」という言葉に込められているのは文字通り、能力や属性によって分け隔てすることのない、すべての人というニュアンスです。くわえて ACTION FOR ALL や LIFULL STORIES など、住宅弱者を支援するサービスや、多様な価値観や暮らしを応援するメディアを運営してします。 このようなサービスを展開する会社として、アクセシビリティに取り組まない理由はありません。 私とアクセシビリティ ここからは私のごく個人的な話になります。筆者は現在、企業でアクセシビリティを牽引していく役割を務めていますが、キャリアはこれまで一貫してウェブのフロントエンドを担当するエンジニアでした。私はいったいどういう経緯でアクセシビリティに興味をもち、何が楽しくて今の業務に携わっているのでしょうか? アクセシブルな UI との出会い 私のアクセシビリティへの興味は、元をたどってみるとネイティブ UI に対する劣等感が根底にあったように思います。OS やブラウザーが備えている UI がキーボードによる操作性や一貫性・堅牢性を備えていることは肌で感じていました。くわえて、キーボードショートカットを駆使することで、マウスの時よりずっと効率的な作業もできる。一方で、自分が実装するウェブの UI は、見た目だけそれらしく見せたハリボテを作っているような違和感を持っていました。中身が伴っていなくて、ネイティブ UI に対して劣ったものを作っている…と感じていたのです。 ところがウェブにも、堅牢でキーボード操作に対応した UI が存在していることに気付きました。Adobe AIR や Dojo Toolkit、jQuery UI といったプロダクトへのあこがれを通じて、WAI-ARIA というものの存在を知りました。ウェブアプリケーションをアクセシブルにするための仕様です。WAI-ARIA に準拠した実装をすれば、ウェブでもキーボード操作に対応した UI を実装できるのだと知りました。「私が作りたいものの指針はここにあったんだ」と思いました。 いつもよいものを作りたい デザインと実装が別々の価値基準で作られる制作体制にあまり満足していませんでした。「デザインを実装で再現する」とか、逆に「実装都合をデザイナーに飲んでもらう」ような作り方にモヤモヤしていたのです。一見、お互いの価値観をすり合わせをしていて素敵な制作チームだとも思えます。しかし相手が主張してくる内容によっては必ずしも同意できることばかりではなかったりして、最終的に納得のいかないまま渋々ながら一方が折れる…といったことにもなりかねません。 キーボード操作を実装したいという私の思いも、プロジェクトの目的と照らしたら「エンジニアの自己満足」と一蹴されてしまっていたかもしれません。 デザインと実装とは、そういう緊張関係の間に成り立つものではなかったはずです。何かお互いが「これはよい」と思えるものを共有しながらものづくりができればよいのに…と思っていました。 アクセシビリティに向き合い始めてから、アクセシビリティが自分の求めていたものじゃないかと思えるようになりました。アクセシビリティこそが、ウェブサイトを作るためにデザイナーと実装者とで共有できる品質の指針や価値基準になりうるのではないか…と。 アクセシビリティを中心に据えると、私があこがれていたキーボード操作できる UI も大手を振って実装できるようになるし、私の劣等感もぬぐい去られるような気がしました。 ウェブへの恩返し 小学校のころに初めてホームページを作って以来、ゲームのコミュニティサイトの運営などを通じていろいろな人と出会い、貴重な経験もしてきました。「ウェブにおける自分」の人格は自分の中でも今も大きな比重を占めています。多感な時期に私の創作意欲の受け皿になってくれたことも、今ウェブの仕事をして食べていけていることも、感謝してもしきれないくらいの恩がウェブにはあるのです。 自分にはこれしかできないから…というのはまあそうですが、私はウェブに恩返しをしていきたい。では、どういう形で恩返しができるか? と考えた結果、自分が関われる範囲において、ウェブがウェブらしくあるように貢献していきたいと考えるようになりました。 「ウェブらしさ」とはなんでしょうか? 十人十色答えは違いそうですが、アクセシビリティこそがウェブらしさなのだと私は考えます。ウェブサイトを作るとき、アクセシブルにしてくれというウェブの声が聞こえてくる気がするのです。 そんなこんながあり、私にアクセシビリティを推進していく気概ができあがってきたようです。 LIFULL はアクセシビリティ「やっていき」 2年前に入社した時から細々と社内でアクセシビリティを推し進めてきました。ワーキンググループでいくつか実績を積み上げて、100 人以上のエンジニア組織の中に運よく専門部署が立ち上がるまでになりました。 この実績は明らかに私だけのものではありません。私が入社する前にもアクセシビリティを重要視してデザイン・実装をしていたメンバーがいます。旗振り役としての経験の乏しい私の背中を押してくれたメンバーや上長がいます。ほかの会社で同じく推進役をしている先輩諸氏、そのアドバイスや実績、アウトプットにも大いに助けられています。そもそも、LIFULL という会社が社是として「利他主義」を掲げている会社であることも推進しやすさに大きく影響しているのだと思います。 しかも、私たちの活動はまだまだこれからというところです。コミュニティから受け取ったものをしっかりと成果にかえつつ、私もまたコミュニティに還元できるように努めてゆこうとあらためて感じています。 LIFULL はプロダクトのアクセシビリティを重要と考えています。継続的にプロダクトや制作プロセスを改善してまいります。今後も LIFULL のアクセシビリティにご期待ください。 🙂 LIFULL は一緒に働けるクリエイターを募集しています。アクセシビリティへの取り組みが良いね👍と思ったら、求人をぜひご確認ください。 hrmos.co hrmos.co hrmos.co hrmos.co
はじめに エンジニア二年目、寺井です。 先日行われた AWS JumpStart というAWS初学者向けイベントに参加した際のレポート記事になります。 ■ イベント概要 AWS JumpStart はAWS初学者のエンジニアの方々を対象とした、実践的な研修プログラムです 将来的にAWS活用をリードする人材になるための第一歩をスムーズに踏み出せるようなプログラムをご提供します 単なるAWSサービスの学習だけでなく、要件に合わせて適切なアーキテクチャを検討・設計する経験を積む部分にフォーカスした内容となっております 例えば、以下のような方々にもオススメです! ・AWSの名前は知ってるが使ったことは無い ・EC2等の単体サービスは触ったことあるが、全体のアーキテクティングは経験がない ・クラウドネイティブなアプリケーションを設計する上で重要な観点を知りたい 例によって初心者エンジニア向けな記事となっておりますよろしくお願いします。 この記事が参考になりそうなレベル感 AWS未経験 ~ AWSチョットワカル なエンジニアのみなさん 後述しますが、AWSを全く触ったことがなかったり、エンジニア関連の技術を何も触ったことがないという方にはかなりキツめなイベントでした。内容についてもレポートをしていきますので、参加してみたいけど今の自分のレベルでは不安...という方もぜひ読んでレベル感を察していただけたらと思います。 全体のスケジュール 完全オンラインでのスケジュールです。画像だと文字が潰れてしまっているかもしれませんが、朝9時から夕方6時までぎっしりと詰まった内容ということが伝わると幸いです。 朝9時集合はキツかったです。 1日目前半 ~グループワークではじめまして~ まずは全体説明とウォーミングアップを兼ねたチャットでの自己紹介がありました。内容を見ていると職種はけっこう様々なエンジニア職が集まっていて、年齢層は幅広め、ただAWSサービスを利用した経験があまりないと言った人が多かったです。社会人向けのイベントでしたが、インターンをしている学生さんもいました。参加者は全体で80名程度、サポートをしてくれるAWSの方が3名でした。 その後は簡単なAWSサービスの紹介LTがありましたが、事前学習用動画として一時間程度の入門動画を観るよう指示があったので、その内容の復習になります。 そして二日間の日程を通じて行われるアーキテクチャ設計のお題を出されました。お題はこちら、 グループワークお題 こんな要件を満たすサービスのアーキテクチャ設計をしてくれというお題ですね。納期は翌日です。ちなみにこのお題を出される際にちょっとしたシナリオも一緒に用意されていたのですが、要約すると「ブラック企業に就職してしまった新人エンジニアの俺たちが、入社二日で会社の命運を握るサービスのアーキテクチャ設計を任された件」って感じです。気になった方はぜひ参加してみてください。 その後、各チームに分かれてグループワークが始まりました。 私と一緒のチームになったのは全員同じくらいのエンジニアレベルで、バックボーンは様々だったのですが全員がエンジニア歴1〜2年のグループでした(他のチームもいくつか見ましたがレベル感としてはほとんどの人が同じくらいだと思います。たまに初心者か...?って感じの強そうな人がいたような気もしますが)。 お互いはじめましてでしたが、全員が同じくらいの初学者ということもあり特に緊張することもなくグループワークに入っていくことができました。 さて、今回のように初心者エンジニアが集まると「誰も正解がわからない」、「何をどうしたらいいのかが全くわからない」という状況になりがちです。 そんな時でも安心なのが、グループワーク全体日程を通じて三回、オフィスアワーというAWSの人に直接相談できる機会が設けられていたことです。 初回の相談時はどうしたらいいのかが全くわからず、設計図もそれっぽいものを並べただけという悲惨な状況でしたが、「この要件を満たすためには例えばこういった機能が必要そうで、これを調べてみるといいかも」といったアドバイスをいただくことができ、無事に軌道に乗るところまで持っていくことができました。 少しでも知見のある分野ではそれぞれが積極的に意見を出すといったチームワークも発揮しつつ、それっぽい設計図ができてきたところで初日のグループワークの時間が終了。作業時間は三時間ほどあったはずですが、一瞬で過ぎ去っていった印象です。 普段の業務もこれくらいの速さで時間過ぎればいいのに。 1日目後半 ~スケーラブルなWebアプリを作るハンズオン~ 1日目後半はグループワークを中断して、実際にAWSサービスを使ったハンズオンを行いました。 内容としては、「複数のアベイラビリティーゾーンを作成、それぞれのパブリックサブネットにECSとFargateタスクを設定してELBを接続、最後にそれぞれのプライベートサブネットにRDSをリーダーとプルレプリカ1台ずつ起動」というものです。図にすると以下のような設計になります。 ハンズオン完成図 ここまで書いてある意味がよくわからないといった方には中々やりごたえのある内容だったのではないでしょうか。とはいえ丁寧な解説手順書があり、わからない人向けに個別フォローまでやってくれるので迷子になってしまうといったこともなく安心です。 一方で、ここまで書いてある意味がそれなりにわかる方には正直あまり効果の無い内容だと感じました。リソースの作成や設定まで全て手順書に細かく書いてあるので自分で特に設計等を考える必要もなく、あーこの設定ね、とポチポチするだけで完成してしまいます。また、基本的にそれ以上突っ込んだ内容は取り扱わず、AWSの方々も途中の設定で詰まってしまった方のフォローにずっと回っていたので、早く終わってしまった人は各々好きなことをしていてください状態でした。その間に設計の課題を考えることができたのでありがたかったのですが、私にとってはこのハンズオンではあまり得られるものがなかったかなと感じます(理屈はわかっていても実際に自分の手で一から作成した経験は無かったので学びになったといえばそうかもしれませんが)。 という内容を最後のアンケートで書いたのでもしかしたらこの後の回では内容が変わっているかもしれません。 2日目 ~グループワーク追い込み編~ たった二日間の日程ですが、納期が目前に迫っている(という設定)ので朝からグループワークの続きです。 着々と要件を満たした設計を実装しつつ、オフィスアワーの質問も活用して一通り設計が完成してきました。 初日はボロボロだった設計もこの段階になるとさらなるブラッシュアップのために機能を追加するといったフェーズになってきます。 そんなこんなで出来上がった最終的な成果物はこちら。 アーキテクチャ設計完成図 オ ー ル サ ー バ レ ス にしました。やはりサーバレス...サーバレスは全てを解決する...!ちなみに発表会では全部サーバレスだと...!?みたいな感じでちょっとざわついていました。 ※この設計図で全要件が担保されているのかと、そもそもこの構成で動くWebサービスができるのかは未検証です。もし何か不備に気付いてしまったベテランのみなさまは寛大な心でスルーしてください。 この構成に仕上げるまでの流れとしては、 チャット機能でリアルタイム性を実現するためにWebSocketをAPI Gatewayで実装 API Gatewayの後ろにつける実行部分としてはメンバーが使用経験があって、かつスケーリングできてAZ等の設定も考える必要のないLambdaで実装 それに合わせてDynamoDBにデータ保存 + OpenSearchを使った検索機能 その他仕様に合わせて調整 といった段階を踏みました。 発表会では質疑応答の時間があり、その後講評をいただきました。それぞれの主な内容としては、 質問: サーバレスに振り切ったモチベーションとしてはどういったものがあったのか。 -> 上述の構成に仕上げるまでの流れの内容をそのまま回答。 想定されるアクセス流量はこの設計で耐えられるのか。 -> 我々の見立てではLambdaのスケーリング機能でなんとかなる想定。同時実行数に関しても上限緩和申請をして対応すればなんとかなりそうという見込み。 講評: 今回のようなサーバレスの多い設計だと短期間での実装には非常に適しているが、Managedなサービス部分が増えるほど自由にカスタマイズできる部分が少なくなっていくのでそういった部分まで考えられると良いかも。 Lambdaの実装部分に関してはもう少し考慮の余地があって、例えばアクセスに耐えられるかの部分は平均だけではなくピーク時の流量を想定して耐えられる設計なのか、関数の実行時間がどれくらいかかりそうなのかまで考えられるとより適した設計が見えてくるかもしれない。 討論を重ねてグループ内ではそれなりに納得のいく形に仕上げたつもりでしたが、深い部分まで考えを巡らせることが十分にできなかったなと感じました。 また、仕様書を表面的になぞっただけの設計にとどまらず、実際に運用した際に生じてくる問題部分まで考えを及ばせる必要があることに改めて気づかされました。 企業がプロダクトとして出すものとしてはかなりお粗末なものになってしまったと痛感しましたが、実際の業務でやらかしてしまう前に経験を積むことができたのは大きな収穫だったと思います。 おまけ ~別チームの設計~ 発表会では4チームごとに分かれて発表を行ったのですが、チームによって設計方法から粒度までかなり異なっていたのが面白かったです。例を挙げるとキリがないので少しだけ紹介すると、 チャット部分のリアルタイム性はAWS AppSyncで実装 処理部分をECS+ASGの設定で実装(ハンズオンでやった内容を応用) セキュリティ部分に注力して認証やIAM設定をガチガチに設定していたチーム 実運用まで想定したリソース選択まで踏み込めていたチーム などが見られました。 所感 二日間フルタイムの日程だったのですが、終わってみるとあっという間のプログラムでした。グループワークの時間だけでも合計で7〜8時間程度はあったのですが全然話し足りないという感想でした。 また、グループ全員がほとんど同じレベルだったのがかなり良かったと感じます。誰かに任せてやってもらえばいいやではなく、自分が全力で参加しないと完成しないという気持ちになりましたし、他のメンバーも同じような思いで参加していたのではないでしょうか。結果としては全員が何かしらの部分で活躍できる機会があったように思います。 また、発表会を通じて自分たちの設計したアーキテクチャへのFBをいただけたことと、別グループの設計の発表も聞くことができたこと、最後にはAWSの方から実装例の共有もあったりと、短い時間で非常に多くの学びがありました。 おわりに ある程度AWSを触ったことがあるといった人が実務に近い設計の経験を積むといった文脈では非常に有意義なイベントだと感じました。今後の業務で学んだことを活かしていきたいですね。 一方で、全くAWS触ったことないという人にとってはグループワークの話し合いに着いていくのがかなり大変だったと思いますし、吸収できる学び量もけっこう変わりそうな気がします。とはいえ、最低限の講義パートやハンズオンもあったので、少しでもサービスを触ったことがあるなら十分食らいついていけるのではないでしょうか。 今年度は全部で4回同一内容のイベントが開催されるので、本記事を最後まで読んでいただいたみなさんも参加してみてはいかがでしょうか。 最後になりますが、LIFULLでは一緒に働いていただける仲間を募集しています。今回希望してイベント参加をしたように、エンジニアが成長できる機会が盛り沢山の職場です。カジュアル面談もやっていますので、よろしければこちらもご覧ください。 hrmos.co hrmos.co
こんにちは、 LIFULLプロダクトエンジニアリング部の趙(チョウ)です。 苗字からわかると思うんですが、国籍は中国です。 中国で大学卒業して一人で日本に来てから3年間になりました。 せっかくの機会なので、外国人が日本に来たこの三年間の生活とお仕事について話したいと思います! 日本とLIFULLに来るきっかけ 私の大学は中国の大連理工大学で、大連には日本の企業は多いので、日本語専門及び日本語強化の専門が提供する大学が多いです。自分の専門も「ソフトウェア(日本語強化)」です。 日本語強化というのは、専門のソフトウェア以外の英語をやめて、代わりに日本語の授業を受けることです。専門のおかげで卒業してからある程度の日本語を話せます。 そもそも日本語できるから海外に生活するわけではないですが、ある機会でネオキャリアが中国に来て面接会を開催しました。十数社の会社が参加しまして、LIFULLはその一員です。 私は友人から誘われたので、就職会の参加を決め、各会社を回っていって、LIFULLのホームページのデザインが一番良くて(私はフロントエンドに興味ある)、利他主義の経営理念も気に入って、LIFULLの面接を申請しました。日本語で面接受けるのは初めてなので、すごく緊張しました! そして面接で話もはずみ、LIFULLに入社することができました! LIFULLのお仕事 入社 入社したばかりの時は使う環境と言語は大学時代に学んだこととは大きく差があり、環境構築や最初のタスクをこなすだけでも大変でした。ありがたくてメンターさんが優しく教えてくれてすぐ慣れてきました。 一年目で物件情報管理のシステムと追客システムを担当させていただき、すごく勉強になった一年でした。 色々触れること 二年目からは組織変更でLIFULL HOME'Sの開発を担当させていただきました! やったことは主に不動産検索サービスの設計と開発です! 他には接客力ランキングページの作成とか↓ LIFULLタグの開発にも参加させていただきました! そして三年目からまた新しい組織に配属されていてB向け領域に行きました! メインの担当はWEBの設計、開発とメンテナンスです。 その他に、グループで担当しているシステムがKEEL環境で稼働しているので、KEEL環境に関しての調整、メンテ、新しい環境作り、デプロイとかの業務もやらせていただきました! www.lifull.blog KEELに関しての業務によってKEELチームと基盤チームのメンバーと相談する機会が一気に増えてきました、他部署のみんなの魅力も感じました。 コロナ時代 入社2年目からコロナが流行して、2020年3月の頭から在宅勤務になっていて、業務の進み方は大きく変わりました。 まず在宅になったことで通勤時間がなくなりました。そして家に仕事するなら部屋の明るさと温度調節自由でもっと安心と集中できる環境を作れるようになりました。 最初リモートワークでコミュニケーション不足になると思いましたが、Zoom、oViceとかのサービスを使ってオンライン飲み会とキックオフをやるのも意外と盛り上がれる!MTGとかも会議室予約しなくてもやれるし、コミュニケーションにも特に影響を感じませんでした。 一人で海外に暮らす体験 言語 日本に来る外国人は、日本語学校を申請して日本に来てから日本語を学ぶのが多いですが、私はちょっと違って中国で日本語を学んでから直接に就職するので、まだ慣れてない状態で職場に行く最初は大変でしたQAQ。毎回他メンバーと話す時はすごく集中して、話す前は必ずノートで話したいのを書いて準備してきました。MTG中みんなの話を追いつかない場合もありました。でも部署の皆さんは私と話すときは意識的にゆっくり話してくれたり簡単な単語を使ったりをしてくれてるのはすごくありがたいでした。 みんなのおかげで日本語の職場をだんだん慣れてきました。 住所 日本に来たときはしばらく日本に働いてる友達の家に住んで、仕事しながら部屋探しをしました。小さい1Kでしたが、私の日本の初めての住むところでした、退社して帰宅後毎回愈されます! 二年間住ませて、その後コロナになっていて、快適な環境で仕事をしたほうが良いと思い家を購入しました。 ちなみに家探しはもちろんLIFULL HOME'Sで! 興味 日本のアニメと漫画は世界中にも有名で、私も子供時代からジブリとか、ナルトとコナンを見ながら育てられてます。日本に来てからももちろん、漫画、アニメとゲームを楽しんでます! 最近PS5を購入もできました! まとめ 素晴らしい三年間でした。 自分がやりたいならすぐやる人間なので(迷えば、敗れる!)日本に来ても、LIFULLに来ても、家を買うとかでも、数日間だけで決まったんです。それが良いのか悪いのか人によってですが、自分がこういう未知×チャレンジだらけの生活が好きです! 一人で海外で暮らすのは確か勇気が必要ですが、一歩踏み出したら、きっと今まで見たことない風景が見えます! 新しい世界に踏み出す自分とそのチャンスをくれるLIFULLに感謝します。 hrmos.co hrmos.co
こんにちは、プロダクトエンジニアリング部の鈴木です。 私達のチームでは、 リファクタDays の取り組みとして、APIサーバのテストコード(RSpec)のリファクタリングを行いました。 このリファクタリングにより、テストコードの記述量が大幅に削減され、数年間利用してきたAPIコントローラのテストコードを作業時間にして2週間程度で移行できました。 この記事では、どのようにしてチームでRSpecを改善したのか全体像をお伝えします。 APIサーバが抱えるテスト実装の課題 主な改善内容 ディレクトリ構成を整備・統一する テストの雛形を自動生成する モック・スタブ化をVCRで自動化する テストコードの期待値も自動で作る テストコードから実装の振る舞い以外を追い出す チームでの改善の進め方 まとめ APIサーバが抱えるテスト実装の課題 私達のチームが管理しているサービスでは、バックエンド(APIサーバ)が、RubyのSinatraフレームワークによるBackends For Frontend(BFF)構成となっています。 コントローラのテストは、RSpecで記述しており、APIサーバへの問い合わせ結果を検証しています。 APIサーバでは外部APIへの問い合わせが多く行われており、テストコードでは外部APIには問い合わせないよう、ダミーデータを返すためのモック・スタブ化が多く行われています。 そのため、図のようにサービスの機能追加・改修の度に、モック・スタブ化を行っていました。 これにより、テストコードの実装工数・コード量・管理の負担が増加し、サービス実装の足枷となりつつありました。 また、テストコード全体の構成にも明確なルールはなく、伝統的に書かれている構成を参考に実装している状態には、チームとして課題感を抱えていました。 負債解消前のテスト基盤 主な改善内容 まず、初めに刷新後のAPIコントローラのテスト作成方法を図示します。 刷新後のテストコードの作成は、ツールからテストコードの雛形を生成し、リクエストパラメータやテストコードを追記して作成します。 また、モック・スタブ化や期待値の作成は初回時に自動的に行われるため、実装者は生成された内容が正しいか確認するだけで良いようになっています。 負債解消後のテスト基盤 この仕組みに変更するためどのような対応をしたのか、各章で詳しく解説いたします。 ディレクトリ構成を整備・統一する テスト関連のディレクトリ構成は、実装コードと同じディレクトリ構成になるように変更することで、実装との対応関係を明確にしました。 先に、大まかな実装(src/配下)とテスト関連(spec/配下)のディレクトリ構成のイメージを記します。 ここでは、例として src/app/resource/mansion.rb という、APIのコントローラを対象としたテストのディレクトリ構成を記載しました。 . ├── spec #テスト関連 │ ├── app #テストコード │ │ └── resource │ │ └── mansion │ │ ├── helper.rb #テスト準備コード │ │ └── mansion_spec.rb #テストコード │ ├── fixture #期待値ディレクトリ │ │ └── app │ │ └── resource │ │ └── mansion │ │ └── result.json #mansion_spec.rbで利用する期待値 │ ├── helper #共通テスト準備コード │ ├── tools #テスト作成自動化用のツール群 │ └── vcr_cassettes #モック/スタブ情報(VCRカセット) └── src #実装 └── app └── resource └── mansion.rb spec/app配下にあるテストコードと、fixture/配下のテストコードの期待値ファイルは、実装側のsrc/以降のファイル名までをディレクトリ構造として配置するようにしています。 単純な話のようですが、今まではルールが明確でないなど、独自の共通化により異なるディレクトリ構造が生まれているなど全体像が把握しにくい状態でした。 全体のディレクトリ構成を整備・統一を初めに行うことで、新規実装者でも全体像を把握しやすく、後述の自動化も行いやすくなります。 テストの雛形を自動生成する テストコードを書くために共通で必要なファイルやコードは、自動生成することで実装者が楽をできるように仕組み化しています。 テストコード雛形作成のツールでは、テスト対象のAPIのエンドポイント(/mansion get)を指定して実行すると、適切なディレクトリにspecの雛形ファイルが配置されるようになっています。 雛形作成コマンドの実行例 ruby spec/tools/make_templates.rb /mansion get コマンドによって作成されたテストコードの雛形イメージ #./spec/app/resource/mansion/mansion_spec.rb # frozen_string_literal: true require_relative 'helper' describe Resource::Mansion do let(:params) { {} } # 必要に応じてリクエストパラメータの定義 # リクエストパラメータのバリデーションテストコード describe '#valid?' do it_behaves_like 'valid?', %i[] end # getリクエストのテストコード describe '#get', :vcr do let(:endpoint) { '/mansion' } let(:result_file) { 'mansion.json' } include_context 'expected_result' end end その他も、テストコードの作成に注力できるよう、ファイルの読み込みなどを極力自動化しています。 モック・スタブ化をVCRで自動化する 外部APIのモック・スタブ化には、 VCR を利用することで、モック・スタブ化を自動化しました。 今まで、外部APIに問い合わせる箇所は、テスト実行時には問い合わせないようモックを作成し、ダミーデータを返すスタブを記述していました。 モック・スタブ化にはRSpec標準の RSpec Mocks を用いてきました。 しかし、この方法は下記のような問題が発生しており、実装の負担になっていました。 外部APIのリクエストパターン分だけ、モック・スタブ化用のコード( allow().to receive().and_return() )を記述する必要がある モックを共通化するために、テストコードに shared_context()/include_context() が頻出する 外部APIへの問い合わせ結果の代わりとなる、スタブデータを作成する必要がある スタブデータが実際の問い合わせ結果と異なり、テストの問い合わせ結果と実際のAPIの結果が乖離する これらの問題の解決策として、VCRを用いました。 VCRは、Net::HTTPやFaradayといった様々なHTTPライブラリを、外部APIへの問い合わせが発生したタイミングで自動的に WebMock 等にモックします。 更に、問い合わせ結果をファイル(vcr_cassettes/配下)に初回のみ自動的に書き出ます。これをVCRではカセットと呼び、スタブデータとして自動的に利用します。 1度VCRの設定をしてしまえば、テストコードへの記述は、外部APIに問い合わせるコードが含まれるテストコードの context/it ブロックに :vcr を記述するだけで機能します。 describe '#get', :vcr do # このブロック中の外部API問い合わせを自動でモック・スタブ化 end この仕組みにより、下記のメリットが得られました。 モックコード・スタブデータを記述する必要がなくなる モック・スタブの記述がテストケースから無くなり、テストコードが読みやすくなる モック記述漏れにより、外部APIに問い合わせてしまうことがなくなる スタブデータが、実際の問い合わせ結果と同じなため、決定論理的なテストを行える 一方、ファイルを自動生成する都合で、describe/context/itにマルチバイト(日本語)を使いにくくなることが課題としてあがりました。 デフォルト設定のVCRは、 describe/context/it の命名で、スタブデータのディレクトリとファイルを作成します。 それにより、命名に日本語が入っているとディレクトリ・ファイル名の日本語がエンコードされ、CLIやGit操作うまくできなくなりました。 解決方法は、下記が考えられます。 CLIやGitを、マルチバイトでも問題ないように設定する VCRの設定でスタブデータのディレクトリを明示的に指定する describe/context/it を半角英数で記述しする 私達は、汎用性のため describe/context/it を半角英数で記述しすることを選択しました。 それ以外の殆どの課題は、VCR側の設定をカスタマイズすることで吸収できました。VRCは汎用性の高いライブラリだと思います。 テストコードの期待値も自動で作る テストコードの期待値も、初回テスト実行時にAPIのリクエスト結果から自動的に作成されるようにしています。 テストコードの期待値は include_context 'expected_result' の内部で下記のように、初回テスト実行時のみ作成と検証をしています。 fixtureディレクトリ配下に、テストコード用の期待値が存在するか確認する 存在しない場合、テストでのAPI問い合わせ結果を、期待値としてfixtureディレクトリ配下に書き込む 存在する場合、期待値ファイルを読み込み、作成は行わない テストを実行し、期待値とテスト実行結果を検証する 気をつける点として、初回テスト実行時はテスト結果と期待値が同じになるため、APIへの問い合わせ結果はどうであれテストを通過してしまう点です。 これについては、異常な期待値が生成されないよう、APIへの問い合わせ結果に問題があるときは警告を表示するよう対策をしています。 また、期待値が正しい値になっていることは、実装時とレビュー時に確認するようフロー化しました。 テストコードから実装の振る舞い以外を追い出す 最後にテストコードの見通しを良くするために行った対応として、テストコードにはテストコードのパターンごとに、実装の振る舞いに影響する受け取る値(引数)と返す値(期待値)のみを定義するようにしました。 これにより、テストコードから誰が見ても実装の挙動がわかりやすくなるようにしています。 具体的には、実装の振る舞いには関係の無い、テストを実行するのに必要なコード(準備コード)をhelperファイルに切り出しました。 helperファイルに移されるコードの例としては before や after ブロックで行うような、日時の固定や外部API以外(AWSリソース等)モック・スタブ化などの処理です。 準備コードを切り出すためのhelperファイルは2種類の配置方法を用意しました。 各テストコードでしか必要のないhelperのコード:各specファイルと同列のhelper.rbに配置。 日時の固定など、複数のテストコードでも利用するような共通のhelperコード:spec/helper/配下から共通で呼び出されるように配置。 日時固定の共通helper # ./spec/helper/contexts/time.rb # VCRカセットの生成時間で日時を固定する共通準備コード shared_context 'freeze_time' do before do travel_to(VCR.current_cassette&.originally_recorded_at || Time.now) end end 共通helper呼び出し用 # ./spec/helper/spec_helper.rb require './spec/helper/contexts/time' # 共通で読み込む準備コードを定義 def basic include_context 'freeze_time' end 個別helper(S3のモック・スタブ化) # mansion/helper.rb require './spec/helper/spec_helper' # mansion/mansion_spec.rbの実行に必要な、S3バケットのモック・スタブ化 shared_context 'stub_aws_s3' do let(:s3_resources_params) { { region: 'ap-northeast-1' } } let(:s3_resources) { instance_double('s3_resources') } let(:s3_client) { instance_double('s3_client') } before do allow(Aws::S3::Resource).to receive(:new).with(s3_resources_params).and_return(s3_resources) allow(s3_resources).to receive(:client).and_return(s3_client) end end テストケースのコード # mansion/mansion_spec.rb require_relative 'helper' describe Resource::Mansion do basic # 共通準備コードの読み込み describe '#get', :vcr do include_context 'stub_aws_s3' # 個別で必要な準備コードの読み込み let(:params) { { mansion_id: 123 } } let(:endpoint) { '/mansion' } let(:result_file) { 'result.json' } include_context 'expected_result' end end これにより、テストコードからは実装の振る舞いがわかりやすくなり、コードの見通しを良くしています。 これらの対応の結果として、大幅に自動化とテストコードの棲み分けがされたため、実装者が考慮しなければならない点が下記に集約されました。 テストコードごとのリクエストパラメータの記述 外部API以外のモック・スタブ化 期待値が想定される値になっているかの確認 テストコードも、8万行程度あったものが約4千行にまとめられ、20分の1となり大幅に改善できました。 チームでの改善の進め方 改善に向けては、 リファクタDays の時間の時間を使ってチームで進めてきました。 リファクタDaysとは、部署全体で進めている、技術的負債の解消とそれによる価値創造の加速を目的とした取り組みです。 我々のチームでは、月に1日業務とは別にリファクタDays時間を確保し、チームで管理しているサービスの技術的負債の解消をしております。 今回のRSpecリファクタリングは、下記のような流れで進めました。 サービスの課題をブレインストーミング形式で洗い出す テストコードの課題点をブレインストーミング形式で洗い出す テストコードの改善方針を定める チーム全員でリファクタリングを行いながら、改善の障壁を洗い出す チームで障壁について解決案を議論・解消 4から5を繰り返す テストコードの課題洗い出しブレストシート 初めから、RSpecの改修を目的にしていたわけではなく、チームでサービス全体からボトルネックを洗い出すところから始めました。 RSpecの改善が決まってからは負債解消をするにはどうするのがよいか、リファクタリングを実施しながら改善の検証を繰り返しました。 その結果として、チーム全員が納得できる改善結果にできました。 まとめ テストコードは、実装の保守・運用に必要なものですが、テストコードの記述に時間がかかると、実装工数増加に繋がり価値創造の妨げになりかねません。 今回は、テストコード作成の自動化と適切なファイルの棲み分けを行うことで、 次の価値創造の高速化に繋げました。 LIFULLでは、なかなか手を付け辛い技術的負債の解消も、チームのKPIとして掲げることで、精力的に取り組んでおります。 気になった方は求人情報も御覧ください。 hrmos.co hrmos.co
はじめに こんにちは!LIFULLのプロダクトエンジニアリング部でフロントエンドエンジニアを担当している竹本です。 今回はチームで初導入した「デザインスプリント」について どのような手法で導入したか 導入して感じた利点と現状の課題 を共有します。 デザインスプリントとは デザインスプリントはサービスの開発を効率よく進めるために各ステップごとにチームメンバーで議論してプロトタイプを作り、高速で価値を検証するプログラムです。 各ステップでは、リサーチ、プロトタイピング、ユーザーテストに則ったプログラムで構成しています。 これを何度も繰り返し研磨することでサービスの理想形を探究し続けるといった点が今回の目標になります。 チームでどのように実施したか まず今回の基本構成としましては、以下のようなプログラムに分けて実施しました。 DAY1 理解...競合調査やデータ分析による課題定義 DAY2 発散...課題を元に解決するHMW(How Might We)を作成する DAY3 決定...書き出したアイデアからプロトタイプを作成するアイデアを選出する DAY4 プロトタイプ...アイデアをベースにプロトタイプを作成する DAY5 検証...プロトタイプをユーザーがどのように使うのかを観察して仮説検証を行う 上記のプログラムを1つずつ簡単に説明していきたいと思います。 DAY1 理解のプログラム このプログラムでは、ユーザーのプロセスを徹底的かつ具体的に追いかけます。 今回はユーザー調査とKA法を用いて人々が求めている本質的ニーズや体験価値を導き出すこととしました。 ユーザー調査 ターゲットにとっての本質的な価値とは何かを探るためにユーザー調査を行います。 今回は、「住まい選びを始める段階の人が、どのように情報に触れて、どのように住まい選びを始めているのか」という題材の元、 デプスインタビューを実施しました。 大まかに分けてユーザー調査前に整理したリサーチ要件は以下になります。 背景 調査が必要な経緯、現在のステータスなど 目的 調査で知りたいこと ゴール どのような結果・状態が達成されていればインタビューは成功か 明確にすること どのようなことを知ることができたら、ゴールを達成できるか こうしたリサーチ要件を元にユーザー調査を行い、得られた結果を元に、KA法を用いて分析していきます。 KA法 KA法を用いたステップとしては以下になります。 「出来事」を読んでなるべく具体的にそのシーンをイメージとして思い浮かべる そのシーンに自分を置いてみて、行動したときの自分の心の動きを感じとる 自分の心の動きを投影して、ユーザーの価値観だったらどうなるか類推する 類推した心の動きから、「出来事」に含まれる価値を捉えて「心の声」として表現する 「出来事」と「心の声」を踏まえて、「〜する価値」というフォーマットにする KA法を用いてできる「出来事」「心の声」「〜する価値」の例 DAY1では様々な価値を発散し、グループ化した上でその価値を提供する既存製品・技術を書き込むまでを行いました。 ここで完成したものは「価値」を整理した価値マップと既存製品、技術マップになります。 DAY2 発散のプログラム このプログラムでは、以下の順序でHMW(How Might We)を作成し、その中から重要なHMWを抽出することがゴールとなります。 DAY1で完成した「価値マップ」を利用し、HMWをチーム内でできる限り作成する HMWの付箋をグループ化する 各メンバーが重要だと思うHMWに投票して、課題をまとめる。 HMW(How Might We)とは、「どうすれば~」から始まる簡潔な言葉で付箋を書いていく手法の1つです。 これにより付箋に書かれるフォーマットの統一と、課題について焦点を当て易くできます。 HMWの例 各メンバーが出したHMWをグループ化した上で重要だと思うHMWを投票により数個選んでDAY2のプログラムは完了となります。 DAY3 決定のプログラム このプログラムではDAY2で選出したHMWを元にアイデアの発散と抽出を行うことがゴールとなります。 課題ごとにアイデアを発散する アイデアを整理し、グループ化する 良いと思ったアイデアにメンバーが投票する どのアイデアをプロトタイピングするか決定する アイデア発散の例(黄色がHMW,オレンジがアイデア) アイデアの整理、グループ化が終わり次第、プロトタイプ作成を行うアイデアを数個選んでDAY3のプログラムは完了となります。 DAY4 プロトタイプのプログラム このプログラムでは採用したアイデアからチーム分けを行い、プロトタイプ作成のために作業時間を取りました。 プロトタイピング手法は最終的にテストできる形であれば良いのでチームごとで最も得意な形式で作成して頂きます。 プロトタイプを完成させた段階でDAY4のプログラムは完了となります。 DAY5 検証のプログラム このプログラムでは各プロトタイプのテストと検証を行いました。 実際にプロトタイプを使っていただくために、今回テスターは社員を協力してもらいました。 各テストが終わり次第、出た意見を元に考察し、反映する内容・次のアクションを決めました。 導入して感じた利点と現状の課題 それでは、デザインスプリントの各プログラムを回して感じた利点や課題について共有します。 利点について 統一された認識の元でのアイデア創出 短い間でプログラムを実施したため、DAY1で固めた認識が定着しプロトタイプを作成するまでに大きくずれることはありませんでした。 メンバーごとで分かれて作業した後もチームとして一体感を持ち、プロトタイプを作り上げられたと感じています。 短時間で密なプログラムによる効率的なコミュニケーション 短い間に長時間チームメンバーとコミュニケーションを取る仕組み上、メンバーの相互理解も並行して進んだように感じました。 これにより、デザインスプリント外でも職種間のやり取りがよりスムーズになりました。 課題について デザインスプリントのスピード感 本来5日間通して行うプログラムですが、今回はデザインスプリントをやりつつ並行して通常施策の作業を進めていたため、プログラムの間は1週間ほど空いてしまったケースもありました。 故にデザインスプリントで重要な要素の1つであるスピード感は意識し切れていなかった可能性があります。 プログラムごとに時間を空いてしまう場合は、前回のプログラムでは何を行ったかログを残しておき、次のプログラムでもすぐ考えられるように準備をしておくとスムーズに思考しつつプログラムを進めることができると感じました。 どんなサービスについてデザインスプリントを実施したか 今回、デザインスプリントを活用したサービスは住まいインデックスというサービスになります。 住まいインデックスは住み替えの予算、ユーザーにあった地域などのような住まい探しにおける悩みを解消するサービスです。 lifullhomes-index.jp まとめ デザインスプリントの初導入した手法と感じた利点、課題などを紹介しました。このように初導入でも挑戦できる環境は整っています。 今後デザインスプリントを導入検討している方々の参考になれば幸いです。 最後になりますが、LIFULL では一緒に働く仲間を募集しています。よろしければこちらも合わせてご覧ください。 hrmos.co hrmos.co
こんにちは!テクノロジー本部事業基盤ユニット改善推進グループ所属の王です。 現在はLIFULL HOME'Sの各種サービスが参照するデータベースをOracleからPostgreSQLに置き換えるDB移行プロジェクトの業務を担当しています。 今回のブログのテーマは、DB移行プロジェクト内の課題を解決するため、PostgreSQLデータベースの拡張機能oracle_fdwの使用検証および検証中の気付きです。 DB移行プロジェクトの詳細については、こちらのブログを参考にしていただけるとうれしいです。 www.lifull.blog www.lifull.blog www.lifull.blog DB移行プロジェクトの課題 oracle_fdwを使用検証するきっかけとしてはDB移行プロジェクトにある課題の解決です。 課題について説明します。 DB移行作業におけるテーブルの依存関係 DB移行プロジェクトで移行する予定のさまざまなSQLの中には、一つのSQLで複数のテーブルにデータ参照している場合があります。例としては複数テーブルの結合があるSELECT文、テーブルの参照結果を別テーブルにINSERTするなどです。 これらのSQLによって、DB移行作業におけるテーブル間の依存関係が発生しています。たとえば、テーブルAとテーブルBが同じSQLに使われる場合、テーブルAへのDB参照を完全に移行するため、テーブルBへのDB参照を変更する必要があります。 複雑なテーブル依存関係が課題 複雑なテーブル依存関係はDB移行作業に支障を与えて移行プロジェクトの課題となっています。 今回DB移行プロジェクトにさまざまな複雑なSQL文を移行する必要があります。SQLに使われるテーブルは数多くあり、DB移行におけるテーブルの依存関係は非常に複雑となっています。 移行する予定テーブルの中で、仮に一つのテーブルのDB参照が移行先に変更することが難しい場合、依存関係を持つほかのテーブルにも影響してしまい移行できなくなります。 上記の状況は実際にプロジェクト内で発生しています。複雑なテーブルの依存関係によって、部分的な移行進捗の遅れはプロジェクト全体の進捗に大きく影響する可能性があるため、現在プロジェクトの一つの課題となっています。 oracle_fdw 上記テーブルの依存関係による影響を減少させるために、oracle_fdwというPostgreSQLの拡張機能を導入することを検討しています。 oracle_fdwとは? oracle_fdwはPostgreSQLの拡張機能の一つです。 FDWとは、外部データラッパー(Foreign Data Wrapper)の略称です。Postgresにはさまざまな外部データラッパがあり、Postgres以外のデータソースをアクセスする仕組みです。oracle_fdwはその中の一つです。 Oracle上のテーブルやビューをPostgreSQLの外部テーブルにマッピングすることにより、PostgreSQLからOracleデータベースにアクセスして、データを取得することが可能となります。 oracle_fdwに関する詳しい説明は以下の資料が参考になると思います。 外部データとの連携 ~FDWで様々なデータソースとつなぐ~ Oracleデータベースにアクセスする ~oracle_fdwの基本的な使い方~ また、oracle_fdwはOSSとしてGitHubに公開されています。関連情報も以下から取得できると思います。 laurenz/oracle_fdw なぜ課題の解決に役立つ? oracle_fdwを使用することで一つのSELECTで複数のテーブルをJOINしている場合でも、異なるDBインスタンスにあるテーブルどうしをJOINしてデータを取得できます。 この特性を活かすことによってSQLを移行する時に、SQLに使われるテーブルを全部移行先のPostgreSQLにデータ参照変更が必要という制限はなくなります。 移行する予定テーブルの中で、仮に一つのテーブルのDB参照が移行先に変更することが難しい場合、依存関係を持つほかのテーブルにも影響してしまい移行できなくなります。 すなわち、上記のようにしばらく移行が難しいテーブルが存在する場合でもそのテーブルの参照だけOracleのままにしてほかの依存テーブルはPostgreSQLに参照することとなります。 検証作業での気付き oracle_fdwはまだ現段階使用の検証しており、実際にプロジェクト内で使用するのが始まっていないですが、検証作業をしてみていくつか気付きがあったので共有します。 PostgreSQLにインストール oracle_fdwのインストールは以下のページの記載を参照することがお勧めです。 インストールガイド 注意点は下記となります。 oracle_fdwの使用にはPostgreSQLのバージョンが9.3以上を要求しています。AWS RDSの場合、PostgreSQL 12.7、13.3、14およびその以降のバージョンしか導入できない制限があります。バージョン関連の情報は Amazon RDS でサポートされる PostgreSQL のエクステンション に参照可能です。 OracleへのアクセスにはPostgreSQLサーバにOCI(Oracle Call Interface)ライブラリのインストールが必要です。バージョン11.2以上を要求しています。 使い方 画像引用元: https://www.postgresql.fastware.com/postgresql-insider-fdw-ora-bas 上記の図に示すようにPostgreSQLの外部テーブルとOracleのテーブルのマッピング関係を設定する上で、PostgreSQLからOracleテーブルのデータをアクセスできます。 連携先のOracleデータベースの各種情報を利用して、下記の手順で設定する。 oracle_fdwのエクステンション(EXTENTION)の作成 CREATE EXTENSION oracle_fdw でPostgreSQLのエクステンションを作成する必要があります。 外部サーバの作成 Oracleのホスト、ポート、データベース名を格納する外部サーバを作成する CREATE SERVER ora_sv FOREGIN DATA WRAPPER oracle_fdw ## ホスト、ポート、データベース名を設定する OPTIONS (dbserver 'host_ora:1521/XEPDB1') PostgreSQLユーザーに外部サーバの使用権限をつけることも必要です GRANT USAGE ON FOREIGN SERVER ora_sv TO postgres; ユーザーマップの作成 OracleユーザーとPostgreSQLローカルユーザーとのマッピングする ## Oracleデータベースのユーザー名、パスワードを設定する CREATE USER MAPPING FOR postgres SERVER ora_sv OPTIONS ( USER 'ora_user', PASSWORD 'xxxx'); ユーザーマッピングすることで、Oracleユーザーと同じアクセス権限をもらう 外部テーブルの作成 最後、PostgreSQLに外部テーブルを作成して、Oracleテーブルとのマッピングを設定する CREATE FOREIGN TABLE f_ora_tbl( ## 主キーカラムはkeyオプションで設定する id int OPTIONS (key 'true'), name varchar(64), t_data timestamp) ## スキーマ、テーブルを設定する SERVER ora_sv OPTIONS (SCHEMA 'ORA_USER' , TABLE 'ORA_TBL'); テーブルのマッピングには以下の注意点があります。 テーブルカラム定義は、Oracle側のテーブルカラムと同じ種類のデータ型を定義する必要があります。異なるデータ型を指定する場合、oracle_fdwが自動的にデータ変換が行います。 OracleとPostgreSQLテーブルカラムのマッピングはカラムの順序をそれぞれ対応させる、外部テーブル作成する時はカラムの順番は要注意です。カラムの順番が間違っている場合、正しいデータアクセスが行われない可能性があります。 Oracle側のテーブルデータを更新する場合は、主キーカラムすべてにkeyオプションの設定が必要です SQLパフォーマンスへの影響 oracle_fdwを使うSQLを発行する場合、SQLの実行にOracleとPostgreSQL間の通信が発生します。ローカルのテーブルアクセスと比べて、データベース間の通信速度、通信容量の制限に影響があるため、SQLのパフォーマンスには影響する場合もあります。 連携先のOracleデータベースから大量のデータを取得する場合、SQLのパフォーマンスが落ち、PostgreSQLおよびOracleにも負荷をかける可能性があるため、実際の使用には要注意です。 PostgreSQL外部テーブルへのアクセスがある2つのSQLから説明したいと思います。 SQL A select count(*) from ora_tbl s join tbl g on s.id=g.id and (s.id=952 or s.id=948) Execution Time: 5.935 ms SQL B select count(*) from ora_tbl s join tbl g on s.id=g.id and (g.id=952 or g.id=948) Execution Time: 2656.699 ms * ora_tblは外部テーブル、tblはローカルテーブル。 上記2つのSQLは外部テーブルとローカルテーブルの結合を行い、絞り込み条件にあうレコード数を取得しています。 SQLの実行結果は一致していますが、SQL Aの実行時間はSQL Bより明らかに短いです。 SQLの実行計画から原因を特定すると、以下のことが分かります。 SQL A explain analyze select count(*) from ora_tbl s join tbl g on s.id=g.id and (s.id=952 or s.id=948) "Aggregate (cost=24004.50..24004.51 rows=1 width=8) (actual time=5.837..5.838 rows=1 loops=1)" " -> Nested Loop (cost=10000.29..24002.00 rows=1000 width=0) (actual time=0.430..5.566 rows=1153 loops=1)" " -> Foreign Scan on ora_tbl s (cost=10000.00..20000.00 rows=1000 width=14) (actual time=0.407..3.479 rows=1153 loops=1)" " Oracle query: SELECT /*727d818c0e8c5e5fc8c1ba25f14f1951*/ r1."COL_1" FROM "ORA_TBL" r1 WHERE ((r1."ID" = 952) OR (r1."ID" = 948))" " -> Index Only Scan using pk_tbl on tbl g (cost=0.29..4.00 rows=1 width=6) (actual time=0.001..0.001 rows=1 loops=1153)" " Index Cond: (id = s.id)" " Heap Fetches: 706" "Planning Time: 1.569 ms" "Execution Time: 5.935 ms" SQL B explain analyze select count(*) from ora_tbl s join tbl g on s.id=g.id and (g.id=952 or g.id=948) "Aggregate (cost=20019.19..20019.20 rows=1 width=8) (actual time=2656.574..2656.578 rows=1 loops=1)" " -> Hash Join (cost=10016.56..20019.18 rows=1 width=0) (actual time=276.345..2656.376 rows=1153 loops=1)" " Hash Cond: (s.id = g.id)" " -> Foreign Scan on ora_tbl s (cost=10000.00..20000.00 rows=1000 width=14) (actual time=0.400..2549.151 rows=717509 loops=1)" " Oracle query: SELECT /*90e1158c8e451061bc34a219bd77fa69*/ r1."ID" FROM "TBL" r1" " -> Hash (cost=16.53..16.53 rows=2 width=6) (actual time=0.028..0.030 rows=2 loops=1)" " Buckets: 1024 Batches: 1 Memory Usage: 9kB" " -> Bitmap Heap Scan on tbl g (cost=8.60..16.53 rows=2 width=6) (actual time=0.023..0.027 rows=2 loops=1)" " Recheck Cond: ((id = '952'::numeric) OR (id = '948'::numeric))" " Heap Blocks: exact=2" " -> BitmapOr (cost=8.60..8.60 rows=2 width=0) (actual time=0.017..0.019 rows=0 loops=1)" " -> Bitmap Index Scan on pk_tbl (cost=0.00..4.30 rows=1 width=0) (actual time=0.013..0.013 rows=1 loops=1)" " Index Cond: (id = '952'::numeric)" " -> Bitmap Index Scan on pk_tbl (cost=0.00..4.30 rows=1 width=0) (actual time=0.004..0.004 rows=1 loops=1)" " Index Cond: (id = '948'::numeric)" "Planning Time: 1.377 ms" "Execution Time: 2656.699 ms" 実行計画のForeign Scanの部分を注目してください。 SQL A " -> Foreign Scan on ora_tbl s (cost=10000.00..20000.00 rows=1000 width=14) (actual time=0.407..3.479 rows=1153 loops=1)" " Oracle query: SELECT /*727d818c0e8c5e5fc8c1ba25f14f1951*/ r1."COL_1" FROM "ORA_TBL" r1 WHERE ((r1."ID" = 952) OR (r1."ID" = 948))"" -> Foreign Scan on ora_tbl s (cost=10000.00..20000.00 rows=1000 width=14) (actual time=0.407..3.479 rows=1153 loops=1)" SQL B " -> Foreign Scan on ora_tbl s (cost=10000.00..20000.00 rows=1000 width=14) (actual time=0.400..2549.151 rows=717509 loops=1)" " Oracle query: SELECT /*90e1158c8e451061bc34a219bd77fa69*/ r1."ID" FROM "TBL" r1" 主な実行時間の差はForeign Scanから生じます。 Foreign ScanはOracleのアクセスする時に発生します。SQL Aの場合、Foreign Scanから取得するレコード数は1153です。SQL Bの場合、Foreign Scanから取得するレコード数は717509です。 結論として、oracle_fdwの使用する時、OracleとPostgreSQLの通信データ量はSQLのパフォーマンスに大きく影響します。 oracle_fdwを使う時のSQLパフォーマンスが気になる場合、Explain文でSQLの実行計画を分析してSQLチューニングすることがお勧めです。実行結果にあるForeign Scanの回数およびレコード数を抑えるSQLチューニングはSQLパフォーマンスの向上に役立つと思います。 oracle_fdwを使うSQLの性能を影響する要因はほかにもあるため、気になる方は下記の記事を参考できると思います。 Oracleデータベースにアクセスする ~oracle_fdwを使いこなすために~ まとめ 以上PostgreSQLのoracle_fdw拡張機能を検証してみた話でした。読んでいただきありがとうございます。 まだ実際にDB移行プロジェクトには導入していないため、導入後のメリットとデメリットまたはプロジェクトへの影響はまだ不明です。今後また機会があればブログを書いて共有したいと思います。 また最後にLIFULLでは一緒に働く仲間も募集しているので、よろしければこちらも併せてご覧ください。 hrmos.co hrmos.co
こんにちは、LIFULLでエンジニアとして働いている中島です。 私は2010年入社なので現時点で12年程同社で働いています。 長い方ではありますが、LIFULL社はそれよりずっと長く歴史のある会社で、多種多様なメンバーがいます。 その中には自分の意思で職種変更をしたメンバーや、自身の職種がそもそも時の流れとともに無くなり、変わらざるをえなかった方々もいます。 本記事では、フロントエンド領域に関わる職種変更に伴い、LIFULLではどのような課題があったか、また、メンバーの技術ギャップを埋めるためにどのようなサポートを行ったかについて紹介させていただきます。 コーダー職種からフロントエンド職種へ 育成を現場へ サポートの内容 その後の会社への影響 最後に one more thing コーダー職種からフロントエンド職種へ 5年程前、世の中のフロントエンドエンジニアに求められる技術スタックが大きく様変わりし、それまでマークアップ、CSSコーディングを生業にしていた方々はその際に大きな転換期を迎えたのではないでしょうか。 その世の中の転換が正しかったのかは私には分かりませんが、弊社でも同じように世の流れに沿う形でコーダー(マークアップを主とする)職種がなくなり、フロントエンドエンジニアという職種(あるいはもう少しプランナー、デザイナー寄りの職種)への変更の話がでて職種の新設、廃設がおきました。 会社としては移行対象者に対してはそれぞれサポートを試みましたが自学自習がベースにあり、業務時間を利用した学習の許可や、学ぶためのオンライン講座等の提供といった感じのものが多く、本人のモチベーションに依存している側面があり、人によっては中々厳しそうな現実が見えていました。 育成を現場へ 人事規定の変更なので人事側と技術マネージャーが主体となって動くわけですが、そこからのアプローチだと工夫しなければ既出の課題を抱えてしまうので、もともと自分の業務時間の数割を割いて行っていた技術育成の枠を使って移行メンバーのサポートをさせてもらないかと打診してみました。 (対等な同僚で且つ自分から望んだわけではない職種変更にあったメンバーにサポートという表現を使うのは随分と偉そうですが表現が難しいのでサポートという表現で記述していきます) 移行メンバーは10人程なので有志のメンバーで数人ずつ担当すれば現実的に対応可能なのかなと思っての提案だったのですが願ったり叶ったりということですぐにその運用が開始されました。 サポートの内容 弊社の場合、コーダー職からフロントエンド職への移行にあたっての最大の難所はJavaScriptなわけですが、幸い技術育成のためのドキュメントや理解度を図るための課題はもともと別の方々を対象にした技術育成を行っていた際に作っていたのでそれを再利用した方法で行うことができました。 JavaScriptそのものに対する学習カリキュラム 目的と内容については以下の通りです。 言語特性の理解(初級) 変数 式 値の種類 関数宣言 関数式 スコープ if for Array 言語特性の理解(中級) スコープチェイン クロージャ functionが一級オブジェクトであることの理解と意識の植込み 高階関数 再帰 コンテキストの理解 thisの決定原理 thisの束縛 call/apply classical実装パターンの理解 constructor/new prototype inherit class syntax DOM Modelおよび周辺技術の理解 DOM Scripting イベント バブリング・キャプチャリング 非同期について Ajax/JSONP 設計パターンの理解 オブザーバーパターン メディエイターパターン ストアパターン 各種ライブラリの再実装 10人もいれば全員に向けて会を開くのが最小コストにも見えますが、もともと興味があったメンバーが集まってるという前提があるわけでもないので個別に時間をもうけてお互いのマインドを理解しあい、心理的安全性を高めることに重きをおきながら毎週行いました。(今年で2年、それ以前から受けてた方もいらっしゃるので長い方は4年ほど) HTMLコーディングをバックグラウンドにもつ方々が多かったので、最近ではある程度言語理解が深まった後はJavaScriptのツールチェインとかaltJSの分野ではなくアクセシビリティを高めるために付随して必要になってくるJavaScriptを学ぶという方向性で授業内容を組み立てるようにしました。 具体的にはWAI-ARIA Authoring Practices 1.1(現在は1.2)で取り扱われているUIパターンの読み込み、実装練習になります。 www.w3.org WAI-ARIA Authoring Practicesで紹介されるUIパターンのうち、カリキュラムとして採用したもの Alert Disclosure Dialog Tabs Feed Listbox MenuButton Menu or Menubar Carousel Combobox Grid そのほかのUIパターンについてはこれらを履修後に読み込みだけを実施 これはそれまでの言語理解のための授業に比べると、自身のもともとある強みを拡張する方向の内容になるのでモチベーションの高まりを感じることができてとてもいい選択でした。 (人によってはその後サーバサイドに興味を持ちRubyやNodeでのアプリケーション制作の演習などに進んだケースもあります) その後の会社への影響 今LIFULLではいくつかのWG(ワーキンググループ)があります。 その中にはLIFULL HOME'S全てのフロントエンド開発をより良くしていこうというWG、全サービスを対象にアクセシビリティ向上を推進していこうというWGなどもあります。 私はその両方に所属しているのですが、フロントエンドを改善していく方のWGでは、デザイナーからこのサポートを経てフロントエンドエンジニアに転身された方が活躍してくれていたりします。 彼ら・彼女らにしかないバックグラウンドを生かした取り組みもあり、デザイナーとの橋渡しやスタイルガイドの作成など幅広く成果を出してくれています。 アクセシビリティの推進活動を行うWGにおいては、会社の全サービスを対象に推進活動を行うため、もともと数人のWGメンバーでは当然各PJに参入して実装支援を行う...とまではいかない現実がありました。 しかし、それぞれのPJには代わりにこのサポートをうけてくださった方々が入っていることが多く、そこで得た知識を実務に生かしてくれており、WGとしてはアクセシビリティレビューの請負や啓蒙活動、相談対応を、現場の転身組は実装でそれを力強く支えるという関係性ができつつあります。 最初は単純に移行をサポートしたいという気持ちだけで始まったものですが、それが回り回って波状的に会社を前進させる力となっているのを感じます。 最後に 近年フロントエンドエンジニアの採用事情はかなり厳しいと聞きます。 採用ばかりではなく内側に眠っている多くの才能にも目を向けていきたいですね。 one more thing LIFULLでは共に成長できるような仲間を募っています。 よろしければこちらのページもご覧ください。 hrmos.co hrmos.co
エンジニアの内藤です。LIFULL HOME'Sの売買領域を支えるエンジニアチームのマネジメントを担当しています。 弊社エンジニア部門では 強い個人・最高のチームになることで価値創造を加速させ続ける というビジョンを掲げています。 これは新しいサービスの開発や機能改善による足元での価値提供だけでなく、開発生産性を向上させることで長中期的により多くの施策をまわせるようになり価値提供を最大化させることを目指してのものです。 そこで私たちのグループは個人のスキル(テクニカル・ポータブル)・環境(プロダクト・ツール)・体制(チーム・業務フロー)を改善していくことにも取り組んでいます。 自分たちの開発生産性を向上させるのに何をしたら良いのか、自分事として捉えてもらうためにもグループのメンバー全員でディスカッションしました。 その中でメンバーから発案があったものの1つが 裏HOME'S斬り と名付けたものでした。 「HOME'S斬り」とは 裏HOME'S斬り の前に、LIFULLでの HOME'S斬り の取り組みについて説明します。 弊社では HOME'S斬り と称して、入社したての社員にLIFULL HOME'Sを使い倒してもらい、課題を見つけてその改善アイデアを発表してもらうことをよくやっています。 これは主に下記の目的のためにおこなっています。 サイトにどんなページや機能があるのか把握してもらう まだ慣れていなので、第三者的視点でサイトの課題を見つけてもらう サイトを長く運用・改修していると機能や見た目に慣れてしまい、課題に気付かなかったり課題と思えなくなってしまうことが多々あります。 社歴が長い社員にとっても新鮮な気付きを得られる機会で、非常に有益な場となっています。 「裏HOME'S斬り」とは 裏HOME'S斬り とは、この HOME'S斬り をHOME'Sの裏側であるプロダクトのソースコードを対象としてエンジニア目線でおこなうことです。 取り組みのねらい 裏HOME'S斬り を実施することは下記のようなメリットがあると考え、実行することにしました。 システムの負債に対する意識のレベルが共通化される ⇒ 若手のスキル向上 改善案を実施すればリファクタリングが行なえる ⇒ プロダクトの負債の解消 メンバー発案なので自分事と捉えて活動できるのではないか ⇒ 主体性発揮の機会・経験(チーム力向上) 実行における工夫 エンジニアがソースコードの課題を見つけて改善案を出すことは、下手するとディスるだけになってしまう懸念がありました。 ※その場に実装した人がいるかもしれないのに・・・ また、業務の負荷になる作業が増えてしまうと本末転倒なので下記のようなルールを定めました。 既存のコードには敬意を持って接しましょう 斬るべき対象はエンジニア目線であればいい ここのロジックもっとスマートにできないか データ構造が気持ち悪い これもう不要だよね アクセシビリティもっと考えられるはず etc がっつりプレゼン資料は作らなくてもいい 対象の場所がわかればOK 発表後、「直したほうがよいか」「すぐにできるか」あたりの軸を参加者で評価する 評価した結果 ふりかえり 通常業務に影響がでないように2ヶ月に1回ぐらいのペースで数回実施してきましたが、良かった点・改善すべき点がそれぞれ幾つかありました。 良かった点 ソースコードの負債に対する意識が強くなった 普段の業務でソースコードを見る際に改善点をより気にするようになった どう直すのが良いか議論が白熱することもあり、より深く本質的に捉えるようになった アクセシビリティの課題など一部のものは改善実施までおこなえた 純粋に楽しんで活動できた 改善すべき点 開発効率の向上を意識し過ぎたせいで「すぐにできるか」という点で該当するものが少なくなり、実施に移せないものが多かった 実施できそうなものも誰がいつやるかという点で曖昧になってしまい、実施まで進められないものもあった 期待していた自主性発揮についてはあまり効果がなかった 途中で「直したほうがよいか」に該当するものは規模に関わらずタスクチケットを作っておき、後ほど余裕がある時に対応できるようにするなどブラッシュアップしながら実施していました。 しかし、改善実施まで完了させるにはまだまだ工夫が必要なことが見えてきました。 例えば、すぐできそうにない規模のものでも負債解消度の高いものはプロジェクト化を検討したりすることで、実行まで進めることができそうです。 まとめ 上記のように 担当者を決める ・ 改善実施に使える時間を確保する ための仕組み化をできるだけ通常業務に影響を与えない形で構築できれば、より多くの改善実施の成果まで辿り着けると考えています。 引き続き 楽しんで活動できる利点を活かしたまま 、成果を出すために 裏HOME'S斬り の改善を続けていきたいと思います。 また最後にLIFULLでは一緒に働く仲間も募集しているので、よろしければこちらも併せてご覧ください。 hrmos.co hrmos.co
テクノロジー本部のyoshikawaです。 最近のLIFULLでは、自社が所有するデータの活用を目的に数多くの取り組みが実施されています。 今回はデータの発見可能性(Data Discovery)を向上させるための基盤構築を目指して実施したPoC(Proof of Concept)とそのOSSの選定について紹介します。 当初は「自社データの再利用性を高めたい」という広い意味を持った要件で開始したプロジェクトでしたが、 Data Discoveryがボトルネックになっていると判明し、解決策としての基盤構築に向けてPoCを実施することとなりました。 現場の課題調査からOSSの選定と試験運用まで一連のトピックをまとめていきます。 初期フェーズ: 現場調査と課題抽出 FAIR原則 データ利用の現場から抽出した課題 ボトルネックの特定と解決策の選定 PoCの開始 OSSの選定 Datahubとは Metadata ingestion PoCの評価指標 PoCの結果 Data Discovery Platform導入への期待 Data Discovery Platformはあくまでも必要条件 これからの展開 求人情報 初期フェーズ: 現場調査と課題抽出 昨年秋、「自社データの再利用性を高めたい」という目的とともにプロジェクトがスタートしました。 筆者をはじめ、プロジェクトメンバーにはデータエンジニア的なバックグラウンドを持つ人はおらず、まずは現場調査を通じ探索的に解決策を導出することとなりました。 ディスカッションや調査の際には記録を手続き的なドキュメントとして残すのではなく、 IBIS(Issue Based Information System) という手法と オンラインホワイトボードのMiroを活用することで、議事録作成をDialogue mapping化しDAGとして残しました。 miro.com 現場調査のフェーズは2ヵ月にわたり、なおかつ多くのステークホルダーに対して実施したため、 過去のやりとりと現在の関心事との関連を視覚的に把握しやすい形式で議論を行うことで議論の発散と収束を視覚化できたのは効果的でした。 MiroでのDialogue Mapping: 議論の現在地や目的を可視化 FAIR原則 データの再利用性を高めたいという観点でスタートしたものの、この時点ではデータエンジニアリングの観点が不足していたこともあり最終的な成果の定義に難儀してしまいました。 民間企業だけではなくアカデミックにおいてもデータ活用の問題は存在していると考えリサーチを行ったところ、データ共有の原則であるFAIR原則を発見しました。 biosciencedbc.jp FAIR原則を知り、これまでに自分たちが焦点を当てていたデータの再利用性とは、相互に関連する4つの原則のうち1つに関連するものでしかないと認識しました。 これ以降は、データ活用にまつわる複数の問題を念頭に置きつつ、ディスカッションや後続となるインタビュー調査を実施しました。 データ利用の現場から抽出した課題 データ分析者やAIエンジニア、プロダクト開発を行うアプリケーションエンジニアや企画職などデータに関連する職種の方々に協力いただきインタビュー調査を行いました。 その結果を要約すると、下記のような課題が得られました。 データの格納場所やデータの情報(メタデータ)あるいはデータの存在自体が不明、または特定のチームや個人のナレッジとして埋没している データの派生系が多く、利用価値のあるデータ・起源となるデータなどユニークなデータが発見できない 発見したデータが更新されているのか、誰が管理しているのかが不明で利用開始するまでに問い合わせが発生する いわゆるデータのサイロ化に起因する問題が目につきます。 これらインタビュー調査の結果を踏まえ、あるべき解決策は静的なドキュメンテーションや属人的な助け合いの仕組みの強化ではなく、 「自動で最新の状態に追従可能で、統一された形式に沿って管理・運用されたデータが入手可能な基盤」であると結論づけました。 ボトルネックの特定と解決策の選定 ここまでの調査は現場の開発者・分析者へのインタビューなどを通じてボトムアップ的に行われてきました。 調査で得られた生の課題の集まりに対して優先的に取り組むべき課題と解決策を選ぶために、書籍"The Self-Service Roadmap"にて導入されていた考え方を取り入れました。 The Self-Service Roadmapにおいては、データ活用の主たる指標とも言える"Time to insight"(知見を得るまでの時間)を "Discover", "Prep", "Build", "Operationalize"の4つのフェーズに分割することが提唱されています。 自分たちの調査によって集められた課題は、Discoverのフェーズ、特にデータセットあるいはそのメタデータの検索の課題に該当すると判断しました。 つまり"Data Discovery"こそが開発・分析現場のボトルネックとなっており、優先的に取り組むべき課題であると判明したのです。 PoCの開始 The Self-Service Roadmapにおいてself-service data platformが立ち行かなくなるアンチパターンとして、 問題を理解しないまま技術にだけ投資してしまうことと、一度に多くの問題を解こうとすることが挙げられています。 アンチパターンに陥らないためにも今回のプロジェクトではData Discoveryに焦点を当て、 これを持続的に解決可能な基盤を導入すべく、技術選定とそのPoC(Proof of Concept)から始めていきます。 OSSの選定 近年、海外を中心としてModern Data Stackという言葉とともに最新のデータ基盤周辺技術に注目が集まっています。 日本でも注目されているdbtのブログにて、Modern Data Stackの来歴とともに展望を読み取ることができます。 blog.getdbt.com Data Discoveryの分野だけでなく、Modern Data Stackを構成する技術は多岐に渡り、 解決したい問題領域や抱えるデータセットの量、事業フェーズなどの制約条件に沿って適切な技術を選定する必要があります。 今回の場合は「 "多様なデータソース" に対して "Data Discovery" を向上させるための "基盤(Platform)" の "PoC" を行いたい」という制約に基づき、 LinkedInとAcryl DataによるOSSである "Datahub" を選びました。 datahubproject.io Data Discoveryの向上を目指せるMetadata Platform系のOSSにはAmundsenやApache Atlas、Open Metadataなどがありますが、 PoC期間内での構築しやすさ・運用可能性、利用者(社内開発者・分析者)向けのUXや機能性を考慮した結果、Datahubを選定しました。 OSSの採用以外の選択肢には、社内で利用しているGoogle CloudのData Catalogを充実させるという選択肢もありましたが、 LIFULLのデータセットはAWSやGCPなど複数のインフラで稼働しているため、中立的なDatahubを試用することとなりました。 Datahubとは 公式ドキュメントでは下記のように説明されており、多様で複雑なデータエコシステムにおけるMetadata PlatformとしてData Discovery, Data Observability, Federated Governanceを実現させることが特徴として挙げられています。 Data ecosystems are diverse — too diverse. DataHub's extensible metadata platform enables data discovery, data observability and federated governance that helps you tame this complexity. Data Discoveryという点ではElastic Searchによるメタデータの検索やWebブラウザのようなUI、Datahub独自のシンプルで拡張性のあるメタデータスキーマによって実現されています。 このようにしてプロダクト開発者や分析者などデータ利用者にとってはシンプルな機能を提供しつつも、 Push型のデータ更新アーキテクチャによる最新のデータへの追従やData Lineageの取得によるObservabilityの確保と、 AWSのIAMのようなRBACによりFederated Governanceの実現を目指すことができ、継続的な運用に耐えうるカタログスペックを有しています。 また、DatahubではQuick Start用のDocker Imageやhelm chartsも用意されており、ローカル環境での試用やPoCが容易に実現可能です。 今回のPoC期間中でもhelm chartsを利用し、LIFULLの検証用Kubernetes環境上に1日程度でデプロイできました。 デプロイしたDatahubのトップ画面 Metadata ingestion RDB(MySQL,Postgres,etc),DWH(BigQuery,Snowflake,etc),BI(Tableau, Looker)など多岐にわたるデータソースから、カラムの物理名やスキーマ情報などのmetadataのingestionが可能です。 ingestされたmetadataに対してはUIやAPI経由で編集することが可能で、データに関するナレッジなどTeam Metadataも集約することが実現できます。 PoC期間中ではFederated Governanceの観点を検証しきれませんでしたが、基盤の管理者がingestionを中央集権的に管理・実行するのではなく データソースに近いプロダクト開発エンジニアやデータソース運用者がDatahub上のmetadataのOwnerとなることで、 自分達のTeam Metadataは自分達で管理しつつ横断的なプラットフォームで第三者が入手・検索可能にし、self-serviceなデータ基盤を実現できるのではないかと考えています。 例えば、DDDにおけるユビキタス言語を制定した後はDatahub上に載せて、チーム内外の認識の齟齬を減らせることが期待できます。 Metadata ingestionの実行後イメージ: タグやTermsからmetadataが検索できる PoCの評価指標 Datahubによって実現されるData Discovery Platformが本当に現場のData Discoveryを実現するかを評価することに加え、 大元の課題であったデータ活用の促進を実現できるかを検証するために、いくつか設問を用意しData Discovery Platformの利用者にアンケートをお願いしました。 例えば以下の2つです。 設問1. Datahubで構築したData Discovery Platformは、欲しいデータを発見するまでの時間を短縮するか? 設問2. Datahubで構築したData Discovery Platformは、データを発見してからデータを活用開始するまでの時間を短縮するか? The Self-Service Data RoadmapにおけるDiscoverにおけるメトリクス:"Time to find"への貢献度を設問1で収集し、 Discoverというmilestoneを含めたデータ活用開始までの時間短縮への貢献度を設問2として収集しています。 別途、性能評価やマシンリソースの消費度合い、費用など非機能的な要件の評価も行います。 PoCの結果 社内のデータ基盤エンジニア・データ分析者・アプリケーション開発者・技術マネージャーなどにData Discovery Platformは利用され、アンケートを実施いただけました。 その結果、設問1については9割が好意的な回答で、設問2については好意的な回答が5割、否定的orわからないという回答が5割でした。 Data Discovery Platform導入への期待 設問1で好意的な回答が大半を占めたことから、Data Discovery Platformを意図して構築されたプラットフォームが 現場のData Discovery向上に寄与することが立証できたと言えます。 データ発見という観点で既存の社内ツールや技術基盤に対する競合優位性があったことは確かですが、 今後全社的に運用する場合、ingestするデータセットが増加し玉石混合なmetadataを持ってしまうリスクもあるので注意は必要です。 Data Discovery Platformはあくまでも必要条件 一方、設問2では半数が「いいえ」あるいは「わからない」など好意的とは言えない回答であったことから、 Data Discovery Platformの実現はあくまでデータ活用のための必要条件であり、十分にデータを活用するには他にも解決すべき課題があると考えています。 ただし好意的な回答が少なかった外部要因として、PoC期間に十分なmetadataを用意できなかったという要因もあるので、 ingest自体を効率化するような仕組みを検証していきたいと考えています。 これからの展開 今回のPoCを経てData Discovery Platformの導入が開発現場・分析現場のデータ活用を促進する一歩となることを立証できました。 ただ、あくまでPoCが成功したに過ぎず本格的な稼働に向けては運用面での課題も存在します。 魅力的な技術や目新しい技術の多いModern Data Stackですが、"right tool for the right job"を原則としてこれからの基盤構築を行っていきたいところです。 求人情報 LIFULLではエンジニアの募集をしており、カジュアル面談も実施中です。 募集中の職種など詳細は下記をご覧ください。 hrmos.co hrmos.co
プロダクトエンジニアリング部の佐野です。 LIFULLでは2020年3月頃からリモートワークが主体の働き方になっています。 出社して働いていた頃と比較すると、同じグループのメンバーとは日々業務を進める上でコミュニケーションは取っているものの、他部署のメンバーとのコミュニケーションが少なくなった...という話もちらほらと。 偶発的なコミュニケーションも必要だ!とのことで社内サークル活動を推奨する制度が出来上がりました。 2022年1月末でサークルは74。多い! どこかのサークルに入っている人は747人。めっちゃ多い!! 上記の通り社内サークルは沢山存在していますが、その中でも今回は、私が主催者となって活動している映画サークルについてご紹介します。 映画サークルについて 映画サークルといっても、敷居は限りなく低く(ここ重要)、私の主催しているサークルは基本月1回の活動です(多いと疲れてしまうので)。 リモートワークが主体の働き方に合わせて、活動もオンラインで行っています。 基本メンバーは7名で活動しており、職種・部署はバラバラです。 このサークルで初めて知り合った方が多数で、対面で会ったことのないメンバーも中にはいます。 普段だと、同じ部署や同じ職種の人と知り合うことがほとんどなので、色々な職種・部署のメンバーと気軽にコミュニケーションが取れるのはサークル活動の強みだと感じています。 サークルで観る作品は、Netflixの中からメンバーが面白いと思ったものを観る形をとっています。 Netflixはたくさん作品があるので飽きません。 「映画」とサークル名についていますが、実際には映画に限らずドキュメンタリーなど色々な作品を観ています。 サークル開催 開催日が決まったらオンラインで集合して、速攻番組を観る…というせっかちスタイルではなく、大体の時間帯にオンラインで集合します。 業務ではないのでここはゆるく始めます。 作品を観る前後30分くらいは雑談タイムを設けていまして、その時にみんなで観る作品を雑談しながら決める形にしています。 こんなものを観たい、どんな番組が面白かった、スタートレックが好きだ、等の雑談を和やかにしています。 普段自分では観ない作品も観れますし、みんなの趣味趣向が知れて大変面白いです。 作品との偶発的な出会いが期待できます。 ちなみに作品を見るときは、「再生しまーす」で同タイミングで再生ボタンを押すようにして、各人の環境で作品を観ています。 また、サークル活動にはサークル活動費として会社から補助が出ます。 そのためサークル開催日には予算内で思い思いの飲食物を購入して、サークルでの時間を楽しんでいます。 1月の活動日には、エンジニアの青木さんも飛び入りで参加して和やかに過ごしました。 そのときは、「ミッドナイトアジア」というドキュメンタリーを観ました。 サークルに飛び入り参加してみての感想 今回飛び入り参加させていただいた青木です。 リモートワーク中心となる前は社内ですれ違えば会話していた面々と、 本当に久しぶりにお話しすることができました。 社員数が増えても、業務だけだと接点って増えるわけではないんだな、こういう機会があるのって大事なんだな、と実感しました。 「ミッドナイトアジア」は、まぁ自分では手を伸ばさない作品でサークルならではのチョイスで楽しめました。 まとめ 今回は私が主催する映画サークルについての紹介でしたが、先述した通り多種多様なサークルが存在しています。 ゲームや数学、エンジニアが他職種の方にプログラムを教えるサークルもあります。 サークル活動を通して普段の業務で関わることのない他部署の知り合いも作れますし、コミュニケーションも取りやすくなると思います。 自分で主催するもよし、サークルに入るもよし。 リモートワーク主体の働き方になりましたが、今回紹介したサークル活動以外にもコミュニケーションを取りやすくするための取り組みが盛んに行われています。 1日誰とも会話していない...なんてことも解決するかも!? LIFULLでは一緒に働く仲間を募集しております。 もし興味を持っていただけたら、募集求人やカジュアル面談のページもご覧ください。 hrmos.co hrmos.co
こんにちは、エンジニアの加藤です。LIFULL HOME'Sの注文住宅領域を支えるエンジニアチームのマネジメントを担当しています。 皆さん、技術的負債の解消やリファクタリングなどどのように行っていますか? 長年の開発業務により蓄積された技術的負債は、開発生産性を低下させる要因として多くの方の頭を悩ませているかと思います。 私の所属する部署では開発生産性の向上をミッションとして掲げており、技術的負債の解消はミッションを達成するための重要な要素となっています。 そのような中、私たちのチームでは「リファクタDays」という取り組みを通じ、約半年間技術的負債の解消を含むシステム改善に努めてきたので、今回はそちらについて紹介したいと思います。 技術的負債の解消を行う上での課題 開発生産性を上げるため技術的負債の解消が重要である一方、LIFULL HOME'S 注文住宅の機能開発を担当するエンジニアであるため、常にプロジェクトに配置されておりサービス開発を行う必要があります。 そのため、負債解消とサービス開発を両立させるためには、限られた時間の中でバランスよく実行することが重要となります。 昨期以前は組織で技術的負債の解消計画を立てつつ、実行は担当するプロジェクトの状況を加味しつつ各メンバーの裁量に任せておりました。 しかし、ときにはプロジェクトを優先して負債解消への取り組みを劣後せざるを得ない状況もあり、計画に対し思うように進捗させるのが難しい場面もありました。 上記の結果を踏まえ、一番の課題は負債解消に取り組む時間を十分に確保できないことであると捉え、仕組み化により課題解決を図る方法を検討しました。 リファクタDaysという取り組み プロジェクトと両立させるための仕組み 前述の通り、サービスを成長させるためプロジェクトを遂行することも重要な職務であるため、プロジェクトと両立させることは不可欠です。 そのため、どのように負債解消に取り組む時間を確保するかが重要となります。 プロジェクトを計画する上で、不確定な要素はなるべく排除しておきたいものです。 エンジニアがプロジェクト外の開発をいつどれだけ行うか不明瞭である状態では計画も立てづらく、プロジェクトの遂行にも影響を及ぼします。 これらの影響を抑えるよう、負債解消への取り組みは一定周期ごと一定期間実施することとし、あらかじめ半期分時間を確保することとしました。 また、負債解消に取り組む上でも効率化は重要です。 タスクにより粒度や規模は異なるため、1日で完遂するものもあれば数日に及ぶものもあります。 開発途中で手を止めることは開発効率を低下させる要因となるため、連続した数日間を集中して取り組むことができる期間として確保することとしました。 これらをもとに以下のルールを定め、この期間を「リファクタDays」と名付けました。 3週毎3日間利用し実施 実施日は水、木、金の連続した3日間 開始日の朝11時にキックオフを実施し、期間内で実施するタスクを各自ピックアップする 原則この期間はプロジェクトに纏わる活動(開発・MTGなど)は行わない 原則スケジュールの変更は行わない(休暇・祝日が被る場合も) 目的は開発生産性を上げること 開発生産性を上げるためには技術的負債の解消以外にも様々なアプローチがあります。 例えば、運用業務の効率化やリファクタリングによりソースコードの保守性を高めること、システムコストを削減することで人的リソースのコストに回すなど。 リファクタDaysの目的は開発生産性を向上させることであるため、技術的負債の解消に限定せず上記を含めたシステム改善全般を取り組むべきものとして位置付けています。 周囲の協力を得ることが重要 これらの取り組みを考えても周囲の関係者の理解と協力を得ることなしに実行はできません。 特にプロジェクトをともに遂行するプロダクトマネージャーや企画職のメンバーの協力は不可欠です。 リファクタDaysの目的や効果を伝えるだけでなく、ルールのすり合わせや実施後のヒアリング、実施内容の見える化など様々な取り組みを行いました。 これらにより理解を得られ快く協力してもらえたことが、リファクタDaysを遂行するための大きな後押しとなっています。 リファクタDaysでの効果 現在約半年間リファクタDaysを実施してきましたが、時間確保の課題は解消され、プロジェクトと両立しつつ一定のペースでシステム改善を積み上げることができています。 システム改善数の推移 また、LIFULL HOME'S 注文住宅へのリリース数も昨期半年間と比較して一月あたり平均約1.5倍に増加し、高い水準で安定していることから開発生産性向上への効果も感じられます。 LIFULL HOME'S 注文住宅 月別リリース数 まとめ 技術的負債の解消や開発生産性向上は多くの組織で抱える課題であり、重要な取り組みの一つであると思います。 今回紹介させていただいたリファクタDaysの事例が、皆さんの課題解決に少しでもお役に立てたら嬉しいです。 また最後にLIFULLでは一緒に働く仲間も募集しているので、よろしければこちらも併せてご覧ください。 hrmos.co hrmos.co
プロダクトエンジニアリング部の二宮です。 LIFULL では「エンジニアいつでも相談」という名前で、 GitHub Discussions を使った社内向けの Q&A フォーラムを有志で運営しています 🙌 このフォーラムは「あるシステムについて誰か詳しい人に相談したい」とか「設計についてチーム外にも相談したい」とか、エンジニアリングで困ったことをなんでも聞ける窓口になることを目指しています。最近ではアーキテクトチームや QA チームなどの公式の窓口としても利用でき、質問の内容に応じて適切な部署や人がアサインされる体制も整い始めました。 従来は相談相手を見つけるのにも苦労したり、そもそも窓口が用意されていなかったりすることもあり、社内アンケート調査等でよく情報共有が課題に挙がっていました。そこで、社内向けの Q&A フォーラムを用意することで、その問題の一部を解消しつつあります。 エンジニアいつでも相談の利用方法 まず利用方法を紹介します。エンジニアいつでも相談の GitHub リポジトリが用意されていて、その Discussions にフォーラムが用意されています。 ここで過去の質問を検索・起票できます。詳しい案内はトップのハウスルールが掲載されており、初めての人でもあまり迷わずに操作できると思います。ハウスルールには次のような内容が記載されています。 GitHub Discussion 上で過去の質問の検索を行う 解決した場合、Vote をする 既存の質問で解決しなかった場合、「Q&A🙏 」カテゴリで起票する フォーラムに質問が投稿されると、質問の回答者となるチームに通知されます。GitHub Actions によって、タイトルや内容によって各チームにメンションを付けたり、Slack 通知を飛ばす機能が実装されています。もちろん、それ以外の社員も回答できます。 質問者は、問題が解決したら、回答の中からベストアンサー(Mark as answer)を選んでクローズします。 このように、一般的に想像するフォーラムの機能はそろっており、通知の自動化なども必要に応じてすぐに実装できます。 GitHub Discussions を利用するメリット 過去のツールの変遷 実は、エンジニアいつでも相談は、発足当初から以下のような思いは一貫しています。しかし、ツール面ではいくつかのものを渡り歩いてきました。 社内のドメイン知識や社内ルールが分からず悩んでほしくない 将来的にエンジニアの共助・評価・成長につなげたい 具体的には以下のような変遷がありました。 Google グループをフォーラムとして利用する フォーラムを使わずに有志でチャット上で質問・回答をする GitHub Discussions でストック化を促進 まず、Google グループではなかなか質問自体が集まりませんでした。これは、普段利用しているツールではなく、業務の導線にないからだったと思っています。 (ただし、Google グループは、 GitHub アカウントを持っていない社員からの質問も受け付けられる点でメリットがあると思います。発足当初は職種からエンジニアへの質問も想定していて、現在はそこのコミットメントは諦めた形になります) また今から考えると、アサインや通知の自動化がやりづらく、この状態でスケールさせることも難しかったと思います。 次に「普段利用しているサービス上なら質問・回答がやりやすい」という仮説のもと、専用のチャットルームを用意して、有志でそこで質問・回答するようにしました。これはコンスタントに質問が行われるようにはなったものの、「あれ?どれが回答済みなんだっけ?」というやや混乱した状態にもなっていました。またせっかく回答しても、その場限りでナレッジにならないという歯がゆさもありました。 Discussions を利用するメリット それらと比較して、Discussions を利用することについて、以下のメリットを感じています。 業務で普段利用しているサービスであること Q&A が直接ナレッジとして蓄積できること GitHub Actions で自動化ができ、Pull Request で変更を受け入れられること 内容がオープンであること 1, 2 は、ほかのツールとの比較で自然にわかると思います。3 について補足すると、たとえば「GitHub Actions によって各チームに通知を飛ばす」機能は、Discussions 起票時に以下のようなシェルスクリプトを起動することで実現しています。 if [[ "$CATEGORY" = "Q&A" ]]; then ( regexp="([kK]eel|KEEL|[dD]ocker|[kK]ubernetes|ECS|EKS|[pP]rometheus|[gG]rafana|[vV]irtual[[:space:]]?[sS]ervice|[dD]ev[oO]ps|[vV]1[cC]luster[bB]ootstrap|[sS]pinnaker|[sS]elf([-]|[[:space:]])?[hH]osted([-]|[[:space:]])?[rR]unner|J-?SOX)" if [[ "$TITLE" =~ $regexp ]] || [[ "$BODY" =~ $regexp ]]; then addDiscussionComment "$ID" "KEEL: ${KEEL_TEAM}" fi ) ( regexp="([aA]rchitect|アーキ|設計相談|[bB]ff|BFF|[nN]c[aA]pp|[nN]ext[cC]ore|lhv5|[pP]roject[xX]|PJX|pjx|[fF]ront|ベストプラクティス)" if [[ "$TITLE" =~ $regexp ]] || [[ "$BODY" =~ $regexp ]]; then addDiscussionComment "$ID" "Architect: ${ARCHITECT_TEAM}" fi ) # 以下略 この通知スクリプトに各チームが通知内容を設定するようにしています。チーム側からこれらの修正を Pull Request として送ってもらうことで、運営チームはあまり負荷を感じることなくメンテナンスできます。 また、一度の投稿で、複数のチームに相談できるというメリットもあります。たとえば「何かのプログラムの問題について QA とアーキテクトに相談したい」というとき、以前はそれぞれの jira で起票する必要があったのですが、今では統一されたフォーラム上で一度に相談できます。 今後の展望とまとめ このように、GitHub Discussions を利用することで、あまり負担なく便利な社内フォーラムが用意できます。 当初は何人かで集まって「誰に質問すればよいか分からんから俺らで作ろうぜ」と勝手にやっていただけなのですが、投稿されたほとんどの質問は何らかの形で解決でき、上記のような便利な状態を実現できました。これは、運営メンバー外で質問をチェックや運営へのフィードバックをしてくれている社員も多くいてくれたおかげだと思っています。 また、従来はチーム内で閉じていた技術的な議論がチーム外も巻き込んだ形で行われているなど、想定していた以外のところでもうれしい事例も生まれています。引き続きよりよい開発文化のために貢献できればうれしいです。 最後に、LIFULL では一緒に働くエンジニアの募集をしています。この記事だけでは普段の開発の様子は分からないと思いますが、ぜひほかの記事も読んで興味を持っていただけたらうれしいです。カジュアル面談もあります。 hrmos.co hrmos.co
プロダクトエンジニアリング3Uの二宮です。 LIFULLにはチームビルディングの制度があり、半年〜1年に一度、同じチームのメンバーで半日〜1日単位で交流の機会を設けています。内容も各部署内で決めることができ、多種多様な企画が行われています。クリエイターズブログでも、過去に「 エンジニアのためのチームビルディング!コードで語れ 頭を使って 謎を解け 」や「 独自企画「浅草BINGO鬼ごっこ」でチームビルディングしてみた! 」などが紹介されています。 LIFULLでは新型コロナウイルスの流行をきっかけにリモートワーク主体の働き方になっており、チームビルディングもリモートで行うようになり、自分たちのチームでもいろいろ苦慮しながら実施しました。おそらく他の会社の方もそうなのではないでしょうか? そこで、この記事では私たちのチームではどう企画して、どう実施・今後に活かしていこうと考えたかをまとめました。ぜひ一つの知見として役立てて頂けると嬉しいです🙌 チームの現状と目的 我々のユニットでは、その中にあるグループ(下位チーム)が別々のプロダクトを担当していて、普段の業務での関わりは多くありません。ただ、現在は極端にチーム外とのコミュニケーションが薄くなり、サポートも得られづらい状態なのでなんとかしたいと考えていました。特徴的なエピソードとして、ある新卒に「直属の上司とは実際に会ったことがあるが、2つ上の上司とはネット越しでしか会話したことがない」とか「社内でもグループ外の知り合いがほとんどいない」と言われ、コミュニケーションのやり方や密度が以前と大きく違うことにショックを受けたことがあります。 9月にもチームビルディングを実施したのですが、その時は都合によって限られた時間で自己紹介と簡単なゲームをすることしかできませんでした。また、それからメンバーの入れ替わりもあって、はじめましての人も何人かいました。 ユニット全体では11人在籍していて、各グループは次のようなプロダクトを見ています。 同一プロダクトを見ているチームほど密に連携する必要はないが、各々小さなプロダクトを見ているので悩み事の相談などはできるはずだと考え、以下のゴールと方向性に決めました。 ゴール: 普段からグループ間で相談(実装面、スキル面など)ができるような信頼関係が作られている 方向性: 相談や意見を交わしながら「一緒に共通のゴールを目指す」ようなアクティビティを実施する 実施準備 結果として、1日を使って、次のようなアクティビティを実施することになりました。 アイスブレイク: 共通点探しゲーム メインコンテンツ: オンラインリアル脱出ゲーム×サマーウォーズ「AIによる世界支配からの脱出」 オンライン懇親会 まずアイスブレイクとして自己紹介を兼ねたゲームを行い、次にいくつかのチームに分かれて、「一緒に共通のゴールを目指す」ことのできるオンラインリアル脱出ゲームを実施しました。 「AIによる世界支配からの脱出」 を選んだのは、他のチームから「以前やってみてプログラマー向けな内容で面白かった」という評判を聞いたことが一番の要因です。また、運営チームで他のゲームやコンテンツもできるだけ探して検討したのですが、オンラインで11人が一緒にできるものが見つからなったという理由もあります。 また、懇親会ではフードデリバリーサービスの nonpi を利用しました。今までは、各々が別々に用意するやり方だったのですが、「オフラインの懇親会と同じく同じメニューのものを食べればチームの一体感にもつながるんじゃないか」と「食事の準備をなくして気楽に楽しめるようにしよう」ということを期待して試してみました。 当日の様子 ①アイスブレイク アイスブレイクで行った「共通点探しゲーム」は次のようなものです。『 リモートワークでの相互理解を深める(共通点探しゲーム) 』という記事から引用させていただきます。 「共通点探しゲーム」とは、その名の通り、制限時間内に対話を通してグループの仲間と共通点を見つけるゲームです。またコミュニケーション能力で重要な共通点を探す力を養うことができるグループワークでもあります。ゲームの目的は共通点を知ることではなく、内容を伝え合うことで、一体感を感じて相手の特徴をより知ることを目的としています。結果としてチームの協力(コラボレーション)を生まれやすくし、相互に助け合える環境を築くことを目標とした、チームビルディングのための一つの手段でもあります。 今回は「脱出ゲームを行うチームに分かれ、20分で『意外な共通点』を見つけよう」という形式で実施しました。 とあるチームは、途中で読書が共通してそうだと気づき、そこから本の共通点を探したところ全員がミステリ小説が好きということがわかり、チーム内でミステリ小説の話をしていたそうです。 運営側は「せっかく自己紹介をするなら、ゲームにしたほうが楽しくない?」という軽い理由だったのですが、後述するように、後日実施したアンケートでは予想以上に評判がよく驚きました。 ②メインコンテンツ: オンラインリアル脱出ゲーム メインコンテンツのオンラインリアル脱出ゲームは、うまく裏をついて問題を解いていくような内容で、前評判の通りたしかにエンジニア向けだったように思います。 ただ、どこまで解答をメンバー間で共有していいか分からなくて困惑したチームがあったり、完答するまでの時間がチームごとにバラツキが大きかったりして、運営側としてはもう少しうまくファシリテーションできたんじゃないかと反省点はありました。 ③オンライン懇親会 オンライン懇親会では、nonpiのフードとお酒を楽しみながら、 ボードゲームアリーナ で遊びました。自分たちは他のオンライン懇親会でもボードゲームアリーナを利用していて、特に「 イラストリー 」が恒例になりつつあります。これはイラストにこじつけて言葉を考える"しりとり"で、「よくこれ思いついたね」とか「いやこれは無理やりでしょ」とか会話も盛り上がるゲームです。 結果・振り返り 最後に、次回の実施内容やチームのあり方に活かせることが無いか、後日アンケートを取って振り返りを行いました。 メインコンテンツでは、楽しかったという意見は多かったものの、次のような課題も挙げられ「一緒に共通のゴールを目指す」というところから外れてしまっていた部分もあったようです。 解くことに集中して無言になってしまった どこまで解答をやり取りしていいか分からなかった 一部メンバーが解きまくって後からついていくことが多かった この辺りは運営に課題があったように思います。次回は次のように対処しようと考えています。 「積極的に話し合ってほしい」みたいに期待することを明確に案内する 他の脱出ゲームの中には人の案内役がいるものや、「AさんとBさんが別々の問題を解かなければ脱出できない」というコンテンツもある。それらを検討してもいいかも また、運営側の予想からは外れ、「共通点探しゲーム」の評判が良かったことです。「コミュニケーションが取れて良かった」という意見が多くありました。 おそらくリモート以前の時代より、我々が思っていた以上に「普段の雑談」とか「同じ開発チーム外の会話の機会」が減っていて、特に新規メンバーは他の人の人となりを知る機会が減っているからなんじゃないかと推測しています。こういうような「ゲームをしながら楽しくお互いを知る」のは他のチームでも需要が大きいのかもしれません。 フードデリバリーはやはり準備の手間が省ける点や、「どのメニュー選んだ?」というような話題で話が生まれる点が喜ばれていました。実は運営メンバーが共通している全社のイベントでもフードデリバリーを利用されるようです。ただ、飲み会向けのメニューが多いので、事情があって飲めない人はメニュー選びに困っていたようでした。 また懇親会では「同時に1人しかしゃべれないので会話に困る」という回答が複数あり、もっと積極的にブレイクアウトセッションを利用し、話題のためにコンテンツを用意して…というように、オフラインより事前の準備が必要な印象があります。また、他の社内イベントで使われていた oVice や Gather などのツールも検討してもいいのかもしれません。 このチームの個別の話でいうと、総じて「共通のゴールを目指そう」というよりは、まずは相互理解を目指すような内容がよかったんじゃないかと思います。例えば、他のチームで行われていた中では「 カラーバリューカード 」や「 アンガーマネジメントゲーム 」などがそういった選択肢になりそうだと思っています。 まとめ 他のチームでも共通するような知見をまとめると、次のようなものがあるかなと思います。 「共通点探しゲーム」のように、楽しく自己開示するゲームは、リモート時代のコミュニケーション不足の補完にいいのかもしれない コミュニケーションがスムーズに行われるように準備が大事だ。特にファシリテーション方法や部屋分けはもっと工夫の余地がありそうだ フードデリバリーは各々の準備の手間が省けるのが嬉しい また、今の所はユニット内でチャットでの会話が多少は生まれてきて、チームビルディングがそのきっかけにはなっていると思うものの、「普段からグループ間で相談(実装面、スキル面など)ができるような信頼関係が作られている」というゴールを見返すとまだまだな点も多いと感じています。チームビルディング以外でも、普段からどうコミュニケーションを取ればいいのか試行錯誤が必要そうです。 そして、企画時からオンラインでの交流の難しさは感じていたのですが、企画メンバー以外からも「やっぱりオフラインのほうが仲良くなれそう。今はムリだが、コロナが収束したら、せめてチームビルディングのときは集まりたい」という意見も出ました。 オンライン主体のチームのあり方は難しいですが、試行錯誤しながらがんばっていきましょう🙌 最後になりますが、LIFULLでは一緒に働く仲間を募集しております。もし興味を持っていただけたら、募集求人やカジュアル面談のページもご覧ください。 hrmos.co hrmos.co
エンジニアの島です。AI戦略室でバックエンドシステムの開発をしています。 本記事ではPrometheusを利用して、独自のメトリクスを計測することで監視を効率よく行えることを紹介します。 背景 チームで作っているもの 社内共通基盤の活用 効果的な監視で得られるもの 問題の予兆に気付けるようになる 問題の原因特定につながる 時系列での傾向を把握できる Prometheusとは 思想 メトリクスの公開 custom metricsを追加しよう Prometheusで監視しよう custom metricsで計測すると嬉しいもの 外部IOに関して 内部状態に関して 外部起因ではないアプリケーションのエラーの数 有効データのうち、モデルが値を返せている割合 機械学習モデルのスコア(histogramを利用) そのほか 終わりに 最後に宣伝 背景 チームで作っているもの LIFULLのAIチームでは、いくつかの機械学習プロダクトを本番運用しています。 2022年2月にAIホームズくんᴮᴱᵀᴬをリリースしました!(SPサイトのみです) https://www.homes.co.jp/ai-homeskun/ また、3D間取りも2021年にリリースしています。 https://www.homes.co.jp/3dmadori/ その他には、LIFULL HOME'Sのレコメンド機能でも機械学習を活用しています。 https://www.homes.co.jp/chintai/tokyo/list/ それ以外の開発プロジェクトもいくつか進行中です! 社内共通基盤の活用 これらのプロダクトは社内共通基盤チームが開発したKEELという、 In-house PaaSとして各種機能を提供するKubernetesベースのアプリケーション実行基盤で動いています。 www.lifull.blog KEELチームが開発しているコードジェネレータ(keelctl)によって、Production Readyなアラートが自動的に設定されます。 例えば下記が監視され、しきい値を検知すると通知されます。 サクセスレート低下 レスポンスタイム CPU・メモリ使用量 www.lifull.blog success rateやresponse timeなどの基本的な指標は、ダッシュボードで閲覧できます。また、それらの通知も生成されるため、基本的な指標の悪化に気付けます。 そしてKEELチームが運用するPrometheus,AlertManager,Grafanaといったソフトウェアからアラートの受け取り、収集したメトリクスを確認できます。 www.lifull.blog アプリケーション開発者はこの仕組みを活用しながら、 DevOpsの考え方に従い、自分たちでアプリケーション固有のエラー対応や監視を行うことが出来ます。 開発したプロダクトが増えていくにつれ、運用コストも増えていくため、自動化できるところは自動化したいモチベーションがあります。 効果的な監視で得られるもの 問題の予兆に気付けるようになる 監視の恩恵としてここが一番大きいです。 本番サーバが突然落ちて、それにより割り込み対応や残業を余儀なくされるというのは、開発者体験として最悪ですよね。 バグの早期発見により対応コストが劇的に下がるのと同様、障害対応も早期解決・顕在化前の解決が最も効率的です。 適切に監視をすることで、サービス利用者への価値提供を継続できるだけでなく、あなたや同僚の時間を守る事にもつながります。 問題の原因特定につながる custom metricsを作成することの恩恵はこちらになります。 問題が発生したときに、手がかりがないと調査から始めないといけません。 custom metricsが手がかりとなれば、問題を迅速に切り分けることができます。 仮に問題がなかったとしても、「問題はそこではない」という貴重な情報が得られます。 結果的に初動が早くなり、問題を迅速に解決できるでしょう。 時系列での傾向を把握できる こちらはメトリクス値を蓄積することの恩恵になります。 通知を設定しなかったとしても、蓄積したデータを調べることで、システムの長期的な傾向を知ることができます。 リリースしてから、サーバのメモリは増加していないか 依存サービスのタイムアウトは一時的なのか周期的なのか catchして握りつぶしている例外の数は規定内に収まっているか 機械学習スコアの傾向に変わりはないか さまざまな情報を知ることで、サービス開発・運用に役立てることができます。 Prometheusとは 一言でいうとシステム状態の収集・可視化と監視ができるOSSです。 prometheus.io 元はCNCF(Cloud Native Computing Foundation)プロジェクトとして始まりました。 今ではAWSマネージドサービスも出ており、監視標準と言って良いでしょう。 aws.amazon.com 思想 Zen of Prometheus が分かりやすいので紹介します。(非公式サイトですが) https://the-zen-of-prometheus.netlify.app/ 3行でまとめると、 メトリクス取得は安価に行えるので、どんどん取得しよう。 ログを取ったり、可視化をしたりするのであれば、そのメトリクスを計測してアラートさせるように作っておこう。 やっかいな問題へと深刻化する前に、すぐ気付いて早期対処しよう。 といったところでしょうか メトリクスの公開 Prometheus公式にて、いくつかのプログラミング言語用のライブラリがサポートされています。 こちらを利用するだけで、簡単に実装できます。 github.com PythonのFastAPIフレームワークであれば、例えば以下のように記載するだけでデフォルトのメトリクスを公開できます。 import prometheus_client ... @app.get('/my_prometheus_metrics') def prometheus_metrics(): return fastapi.responses.PlainTextResponse( prometheus_client.generate_latest() ) その上で設定したパス /my_prometheus_metrics にアクセスすると、計測しているメトリクスを次のようなプレーンテキストで取得できます。 # HELP process_start_time_seconds Start time of the process since unix epoch in seconds. # TYPE process_start_time_seconds gauge process_start_time_seconds 1.64446715949e+09 # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. # TYPE process_cpu_seconds_total counter process_cpu_seconds_total 260.51 custom metricsをプログラム側で追加すると、このプレーンテキストに行が追加されていくことになります。 Prometheusが設定したエンドポイントをポーリングし、メトリクスを読み込みます。したがって追加されたcustom metricsも連携することができます。 custom metricsを追加しよう 利用方法もPrometheusのライブラリ側に書いてあるので、非常に親切です。 たとえば下記のように記載するとタイムアウトがどれくらい起きているかのメトリクスを追加できます。 ※異なるアプリケーション間でのメトリクス名を明確に区別するために、プレフィックスを付けています。 PREFIX = 'your_awesome_app' TIMEOUT_REDIS_COUNTER = prometheus_client.Counter(f'{PREFIX}_timeout_redis_counter', 'redis timeout counts') try: # some redis execution ... except redis.exceptions.TimeoutError: my_prometheus.TIMEOUT_REDIS_COUNTER.inc() Prometheusで監視しよう PrometheusではPromQLという記法で条件式を表現できます。 例えば下記のように割合を表現できます。入力から機械学習モデルのイレギュラー値の割合を、モデルに渡さない除外データの数を除外して計算しています。 これにより「有効データのうち、モデルが値を返せている割合」を監視できます。 (sum(increase(your_awesome_app_zero_score{app="your-awesome-app"}[10m])) - sum(increase(your_awesome_app_exclude{app="your-awesome-app"}[10m]))) / (sum(increase(your_awesome_app_input_records{app="your-awesome-app"}[10m])) - sum(increase(your_awesome_app_exclude{app="your-awesome-app"}[10m]))) < 0.0025 このPromQLによる検知がPrometheusのAlertmanagerに渡され、事前に設定した通知設定でSlackに通知されます。 custom metricsで計測すると嬉しいもの 以下のように外部IOや、アプリケーションの内部状態を計測しています。 外部IOに関して 複数の外部IOに接続して、レスポンス低下が起こっている場合に、どこで問題が起きているかが特定できて便利です。 response time(histogramを利用)やnetwork timeout数を計測しています。 分散トレーシングに関してはJaegerが得意なので、そちらで可視化しても良いです。 Prometheusで取得することで、PromQLで他メトリクスと同じように扱えたり、アラート通知が行えたりとメリットがあるのでこちらで計測しています。 内部状態に関して 注視しておきたい値を計測しておくと、時系列で追えるので便利です。 外部起因ではないアプリケーションのエラーの数 単純なsuccess rateだと外部起因エラーと内部起因エラーが交じるため、分離して監視しています。 今の所、安定して値を返せています。このような安定した数値は手動確認だと見なくなる傾向があるため、自動監視の恩恵が大きいです。 有効データのうち、モデルが値を返せている割合 単純なsuccess rateだと異常値は0点スコアとして200 OKで返すため、このメトリクスを監視しています。 監視することでモデルや入力データの異常に気付くことができます。 こちらも同様に普段発生しないため、自動監視に任せています。 機械学習モデルのスコア(histogramを利用) GrafanaでPromQLを記述し、Prometheusのメトリクスを可視化できます。 機械学習スコアの推移 こちらは問題が発生した場合の調査用に計測しています。 ※スコア自体は、相対的な順序が正しければそれでよく、絶対的な数値で正常・異常を測ることができないと判断しています。 機械学習スコアの比率は、細かなブレはありますが長期で見て変動ないことを確認できます。 ※年末年始に不動産会社がお休みのタイミングのみ微減しており、これは新鮮な物件広告の供給が途絶えていたためと考えられます。 モデルの継続的な品質担保は別の方法で行う必要があり、ABテストによるサイトのCTRやCVRを目視しています。 ※これはPrometheusで監視していませんが、サイトパフォーマンスのデータは別系統で集計されているためです。 Google Analyticsで計測されたものを、Data Studioのダッシュボードに表示しています。 そのほか こういうメトリクスを計測すると良いというものがあれば、ぜひブコメなどで教えてください! 終わりに Prometheusのcustom metricsを計測して通知すると、監視を効率よく行えることを紹介しました。 問題がやっかいなものになる前に、早めの対処で良いサービスを提供していきましょう! 最後に宣伝 このようにバックエンドサービスの開発から共通基盤開発まで、さまざまな職種を募集しています!よろしければぜひこちらのページもご覧ください! hrmos.co カジュアル面談もお待ちしております!ぜひぜひどうぞ! hrmos.co
プロダクトエンジニアリング部の海老澤です。 LIFULLでは2020年3月頃から自宅からのリモートワークが主体の働き方となっていますが、弊社が運営しているコミュニティ 「LivingAnywhere Commons」 の全国の拠点での就業も可能です。 これは従業員自らが働き方や働く場所を選択でき自分らしい働き方を実現することが、一人ひとりのWell-Beingやパフォーマンスの向上・イノベーションの種の発見に繋がると考えられているためです。 自宅だけでなく旅先の遊休施設で仕事をする、いわゆるワーケーションも行えます。 lifull.com 今回は 「LivingAnywhere Commons」 で二泊三日のワーケーションをしてきました。 控えめに言って最高だったので紹介させてください。 「LivingAnywhere Commons」 とは LIFULLは「あらゆるLIFEを、FULLに。」をコーポレートメッセージとして掲げ、さまざまな社会課題に取り組んでいます。 その中でも「自分らしくを、もっと自由に」をテーマに、ライフラインの限界から解放された本当の意味での自由な生き方を目指す取り組みが「LivingAnywhere」です。 そういった生き方を実践するコミュニティとして2019年に 「LivingAnywhere Commons」 の運営が開始されました。 コミュニティにはコワーキングスペース・レジデンススペースが完備されており、全国に拠点があるため自分の好きな場所で仕事・したい暮らしができます。(2022年1月現在29拠点・続々増えてます!) LIFULLの社員はこれらの拠点を格安・あるいは無料で利用でき、中には毎月利用されている方もいます。 ワーケーションレポート 今回は山梨県にある 「八ヶ岳北杜」 拠点を利用しました。 最寄は小淵沢駅、JR新宿駅から特急で2時間です。 ホームズくんも一緒にワーケーションしてきました 周辺のようす 駅から車で20分ほどの場所に拠点があります。 八ヶ岳北杜拠点 周辺 八ヶ岳北杜拠点 エントランス もともとは民間企業の研修施設だったようで、会議室や大浴場など設備はとても充実していました。 山の上(標高1000m)にあるため開放感がすごいです。富士山もバッチリ見られます🗻 個人的に夕暮れのオレンジと山々の青のコントラストが最高でした。 夕方の富士山 放し飼いにされているヤギもいます。 ヤギのニーナちゃん ワーキング 拠点はWi-Fiがしっかり飛んでいるのでどこでも自由にお仕事ができます。 コワーキングスペースも充実しており、各々作業環境を整えておりました。 二面ディスプレイの作業環境 分割キーボード勢の作業環境 ホームズくんの作業環境 バケーション 業務後はバケーションも楽しめます。 弊社はフレックスタイムを導入しているため、早めに退勤してお買い物にいったりサウナを楽しむメンバーもいました。 サウナーホームズくん 拠点にはサウナカーがあり、セルフロウリュも可能です。 ととのい環境も完璧で、水風呂はなんと 近くの川に飛び込むスタイル です。ワイルド〜! 晴れている日は満天の星空を眺めながら完全優勝しましょう。 圧倒的星空 サウナ後にバーベキューもできます。天才! 11月下旬の山でバーベキューは寒かった 感想 わくわくしながら働ける 普段と違う環境にそわそわすると思いきや、意外と集中して業務に取り組めました。 いつものリモートワークだと1日外に出ないこともよくあるのですが、 業務前の早朝にお散歩したり、地元のお店のおいしいケーキを食べたりQOLが爆上がりしました💣。 最高の朝 合宿で利用したい 今回は「Living Anywhere Commons 行ってみたい!」という好奇心からさまざまな部署の有志が集まって利用したのですが、チームビルディングや開発合宿にも最適な環境だと感じました。 働くのにはまったく不自由しない環境ですし、普段とは違うアクティビティも楽しめるので次回は部署単位で利用してみたいです。 自分らしくを、もっと自由に LIFULLではともに働く仲間を募集しています。 「自分らしくを、もっと自由に」を実現したい方、カジュアル面談という形で気軽にお話をさせていただくということも可能ですので、ご興味がある方は以下のページをご覧ください。 hrmos.co hrmos.co
エンジニアの松尾です。LIFULL HOME'Sの売買領域を支えるエンジニアチームのマネジメントを担当しています。 私の部署を始め、LIFULLでは複数の部門でエンジニア採用を行っています。人事部門の採用担当と現場で連携し、書類審査と複数回の面接により選考を行います。 今回はエンジニア採用を進める上で感じた課題とその解決への取り組みについて紹介したいと思います。 採用において抱えていたモヤモヤ いくつかの書類審査と面接を終えて、日々似たような作業を繰り返しながらいくつかのモヤモヤを抱えていました。 モヤ1: 書類審査に時間がかかる 打率よりもまずは打数。より良い候補者様を見つけ出すために、できるだけ多くの書類に目を通すようにしています。ただしどの方も真剣に経歴を書いてくださっており、すべてに目を通すにはなかなか時間がかかります。 採用以外にもやるべき仕事は多くあります。書類審査に時間をかけすぎることで、ほかの業務の質を下げてしまうリスクもあります。 モヤ2: 面接の時間を有効に使えない 実際に候補者様と対面する面接は、時間を無駄にしないよう慎重に行います。しかし結果を出すためには聞き出したい情報が多くあり、すべてを質問しているとすぐに終了時刻になります。 事前に職務経歴書内の掘り下げたい箇所については確認しつつも、自分の中で要点が定まっていない状態でした。 モヤ3: 自分で評価した結果が腹に落ちない 全力で書類チェックと面接をした結果として、手元には多くの判断材料があります。ですが「この点は物足りないけど、この部分がすごく良いからOKにしようかなあ…」と評価ポイントや基準が定まっておらず、結論を出すのに時間がかかります。そしてほかの評価者とすり合わせると意見が割れ、合議での結果出しにまた時間を要します。 最終的には合議で正しい結論を出せていると思っていますが、個人での評価には不備があり、納得に至るまでのプロセスに時間がかかりすぎている状況でした。 取り組んだこと 何かもう少しうまくやれる方法を模索できないか…と人事や上司に相談しようかと考えていたときに、 下記リンクの記事を発見しました。 現場メンバーの知識を人材要件定義に活かす手法「Job Analysis」の紹介 参考文献をもとに選考プロセスの設計について記載されていますが、私の部署の採用では以下の2点がまだ不十分である印象を持ちました。 採用したい人の人材要件を定義する 人材要件のうち、見極めたい能力を特定する そこで、ブログの内容を参考に求める人材の像を明らかにし、求人ページの応募資格を再設定するための取り組みを進めました。 業務上発生するタスクの洗い出し 採用したい人材とポジションが似たメンバーに協力してもらい、業務内でどのようなタスクを行っているかを洗い出しました。エンジニアにとっては設計、プログラミング、テストなどが主たる業務ですが、ほかの職種とのやりとりやメンバー育成など、タスクは多岐に渡ります。 私は比較的現場に近いポジションなのである程度は把握していましたが、あらためて眺めてみると気付きがあります。 実装よりもレビューの比重が大きそう 他のメンバーに何かを教えたり協力したりするタスクが多い ネットワークやDBの設定をスクラッチで行う機会は少ない 求められている能力(コンピテンシー)の洗い出し タスクとは別に、どのようなスキル/経験を求めているかを洗い出します。 言語、OSS、専門分野などのリファレンスとして、 Qiita の人気のタグを抽出して使用しました。これらからノイズを除去し、残った項目から現場で必要になり得る項目をまとめていきました。 弊社には新旧含めて多くのシステムが存在するため関わる技術は多く、項目全体で見るとなかなかの数になります。重要度の低いものはこのあとの工程で削ぎ落とされるため、現段階ではすべて含めておきます。 スコアリングと文章化 ブログの内容を参考に、タスクとコンピテンシーのそれぞれにスコアをつけていきます。頻度や重要度などの観点で点数を付け、それぞれに序列ができます。スコアリングはほかのマネージャーと相談しながらプランニングポーカーのような要領で進めました。 タスクとコンピテンシーの上位項目を突き合わせて、結果をもとに徹底的に議論します。 「今いるメンバーの立ち回りを考慮すると、PJ管理経験は必須だね」 「言語の具体的な知識より、設計力を優先したいですね」 「〇〇は面接で質問してたけど、入社してから覚えるでも問題ないね」 というようなやりとりを経て、人材要件が新しく定義されました。結果として、応募資格に記載していたスキルを下記のように変更しています。 応募資格の変更 人材要件を見直して改善したこと 実際に現場で必要としているタスクや求めている能力を見つめ直すことで、以前とは違った人材要件ができました。洗い出しただけではなくそれぞれの優先度も確認したため、採用活動の中で候補者様を評価する順序や観点も違ってきます。 見直し前のモヤモヤと比較して、改善した点についてまとめます。 書類選考でチェックできる人数が増える 要件ごとの優先度が決まったことで、書類の中で確認する箇所が明確になり、チェックの所要時間が削減できました。優先度の高い要件を満たしていない場合は早めに候補から外したり、なんとなく魅力的に見えてしまうスキルに目移りしなくなったことで、書類選考の量と質の両方が改善したと感じています。 面接が時間内に完了しやすくなる 優先度の高い要件から早めに質問していくことで、面接内で過不足なくヒアリングを終えられることが多くなりました。要件ごとの重要度が頭に入っているおかげで、質問ごとにかける時間の判断がしやすくなります。また我々からの質問が手短に終えられることで、候補者様からの質問も多く受け付けられます。 評価時のすり合わせがスムーズになる ターゲットとなる人材の像を文書化して認識を合わせたため、複数の評価者で議論して結論を出す場合にも意見が割れづらくなりました。「評価項目Aは文句なしですが、Bは満たしていないですよね」という項目ごとの評価に関する会話もしやすくなり、合否の理由付けも以前より明確になっています。 まとめ 採用活動は非常に重要な仕事ですが、本業務であるエンジニアリングと同時に進めるためには効率化が必須であると感じています。今回はスタート地点にあたる人材要件の作成に手間をかけることで、数ある書類選考や面接をスムーズに迷いなく進められるようになりました。 結果をすばやく正確に出せることは、採用をする我々だけではなく候補者様の転職活動のためにも有意義です。今後もより多くの方とお話をし、ともに働く仲間をみつけるために、妥協のない採用を続けていきたいと思います。 このように選考内容の改善も考えながら、一緒に働く仲間を募集してます。よろしければぜひこちらのページもご覧ください。 hrmos.co hrmos.co
事業基盤ユニットアーキテクトグループのyoshikawaです。 今回のブログではLIFULL HOME'Sを構成するレガシーシステムのリアーキテクティングについて書いていきます。 2年前にリアーキテクティングプロジェクトが発足し、ソフトウェアアーキテクチャのベースにClean Architecture、言語にTypeScriptを採用し 新たなAPI(Backend For Frontend)を開発してきました。 「コードの品質」と「プロダクト開発エンジニアとのコミュニケーション」が鍵となっていた本プロジェクトですが、 このブログ記事では「コードの品質」を主題として取り組みをオムニバス的に紹介していきます。 この記事で伝えること 想定する対象読者 過去のブログの紹介 データフローに注目したLIFULL HOME'Sのシステム概観 リアーキテクティングプロジェクトについて アーキテクトチーム(イネイブリングチーム)とプロジェクトの概要 新BFFへのリアーキテクティング対象機能 機能の特性と深刻な内部品質の劣化 エンジニア組織と横断的な機能 プロジェクト序盤:新BFFのアーキテクチャ選定、技術選定、PoC プロジェクト中盤〜現在:品質維持・改善 ユニットテスト コード量増加とBFF特有処理 モジュールの特徴を理解し、高凝集疎結合に 凝集度が高いモジュールを厚く、低いモジュールを薄く 凝集度に着目した解決策の効果 結合テスト・回帰テスト 機能系のテスト パフォーマンステスト 負荷テスト テスト結果の蓄積 リリース後の品質維持と検証とメトリクス 内部品質: 技術的負債の可視化 外部品質: パフォーマンスの可視化 リアーキテクティングの現在と今後:ノウハウの蓄積とリプレイスに向けて 終わりに Clean Architectureの考えを継承しつつ、アーキテクチャ内製化へ 内製ソフトウェアアーキテクチャを普及させる仕組みと教育 理想とこれからの課題 データ整備の課題とその解決のために 求人情報 この記事で伝えること LIFULLのレガシーシステムである参照系モノリシックアプリケーションの機能を新たなAPI(Backend For Frontend)へとリアーキテクトするまでの取り組み リアーキテクティングを支えた品質維持のためのツール、テスト、コーディング コードの品質、ソフトウェアアーキテクチャ、リファクタリング、Clean Architectureに関するプラクティス 想定する対象読者 十数年以上稼働し技術的負債を多く抱えるWebサービスにおけるレガシーシステムの改善について知りたい人 リアーキテクティング(リアーキテクチャ)やリファクタリング、コードの品質に関する実践的な取り組みを知りたい人 コードの品質やソフトウェアアーキテクチャに興味がある人 過去のブログの紹介 プロジェクト発足の経緯や新たに開発したBFFのアーキテクチャ選定、技術選定理由などプロジェクト初期の内容は過去のブログにまとめています。 気になった方はそちらもご覧ください。(読まなくともこのブログの内容は理解できます) www.lifull.blog データフローに注目したLIFULL HOME'Sのシステム概観 本題へと入る前に、LIFULL HOME'Sのシステムの概観をお伝えします。 BtoBtoC型の事業に類されるLIFULL HOME'Sでは多様なシステムから全体が構成されています。 toB用の書き込み系システムから物件データが入稿され、バッチ・DBなどのシステムを経て処理・蓄積された後、 物件検索機能などLIFULL HOME'Sの各種サービスで物件情報が利用可能となります。 そのデータフローを簡潔に示したシステム構成図が下記です。 LIFULL HOME'S の物件情報参照系システム概観 なお、リアーキテクティングプロジェクトでは参照系システムの技術的負債解消を目的としているので、 その対象外となるシステムや詳細なネットワーク構成、インフラ構成については省略しています。 図中の「モノリシックアプリケーション」こそがリアーキテクティングプロジェクトでの改修対象となるレガシーシステムであり、 「新BFF」がモノリシックアプリケーション上に実装された諸機能の移行先となります。 リアーキテクティングプロジェクトについて LIFULL HOME'Sを構成するシステムの概観をつかめたところで、本題であるレガシーシステムのリアーキテクティングおよびプロジェクトについて紹介します。 アーキテクトチーム(イネイブリングチーム)とプロジェクトの概要 筆者が在籍しているアーキテクトチーム(イネイブリングチームの一つ)の業務は2種類に分けることができます。 一つは、プロダクト開発チームで発生した設計や実装に関する問題の相談および解決策の提供です。 もう一つはプロダクト開発チームでの実行が難しい横断的な問題への取り組みです。 いずれの業務も、プロダクト開発エンジニアの生産性向上に寄与し続けることを目的としています。 そして2年前、後者の業務の一環としてLIFULL HOME'Sの参照系モノリシックアプリケーションにおける技術的負債の解消を目指すリアーキテクティングプロジェクトが発足しました。 このプロジェクトのミッションは、モノリシックアプリケーションが担っていた機能のフロントエンド部分とバックエンド部分の処理のうち、 バックエンド処理のリアーキテクティングを完了させることです。 そのリアーキテクティング先として、新たなBackend For Frontend(新BFF)の開発をすることとなりました。 新BFFへのリアーキテクティング対象機能 その膨大なLOCと影響範囲の大きさゆえ、モノリシックアプリケーションのすべてがリアーキテクティング対象になるわけではありません。 移行予定の機能を構想した後、リアーキテクティングによる事業上のインパクトや機能の特性、プロダクト開発チームとの調整ごとを加味して新BFFへ移行される機能を決定しました。 新BFFへのリアーキテクティング構想:巨大モノレポを複数のGitHub Repositoryから構成された新BFFに移行する その一つが「物件一覧機能」で、「検索条件の設定・変更」から好きな条件を入力し、入力完了と同時に検索が非同期的に実行されて条件に合致した物件情報を一覧できるという機能です。 100万件超の不動産・住宅情報を取り扱っており、派生系の機能も含めて100通り以上の導線(URL)を有していることからリアーキテクティングによる対外的な影響が大きい機能です。 そして横断的に情報が検索可能という特性上、複数のプロダクト開発チームで横断的に開発されている機能でもあります。 機能の特性と深刻な内部品質の劣化 物件一覧機能では下記のような内部品質の劣化が深刻でした。 入力した物件検索条件をパースする処理や、取得した物件情報を整形する処理がモノリシックアプリケーション内のControllerやViewなどに散乱しており、コードのトレーサビリティが低い ソフトウェアアーキテクチャや実装規約の陳腐化、責務が多過ぎるモジュール(いわゆる神クラス)の存在、コードのトレーサビリティの低さが相まって、機能改修・追加による影響範囲特定が困難 古めのバージョンのPHPで実装されており、型付けが行われておらずユニットテストの機構もないので可読性やテスタビリティが低く、潜在的なデグレーションが多い ドキュメントが機能していないので社内有識者へのヒアリングが頻発し、新規開発者にとって実装完了までのオーバーヘッドが大きい(最悪の場合、有識者が退職しており調査が困難) 内部品質の劣化はモノリシックアプリケーションの機能にも多く当てはまりましたが、物件一覧機能においては顕著でありフロー効率の低下を招いていました。 このような理由から、モノリシックアプリケーションのみを対象としたリファクリングや新BFFへの移行を伴わないリアーキテクティングだけでは技術的負債の解消には不十分と判断されました。 エンジニア組織と横断的な機能 LIFULL HOME'Sでは「不動産・住宅情報」というドメインの関心を起点として「賃貸」や「売買」など不動産のマーケット別にプロダクト開発チームが分割されています。 そして「物件一覧機能」では賃貸用の物件や売買用の物件など、複数の不動産マーケットの情報を横断的に一覧可能です。 つまり物件一覧機能は機能単体としての技術的負債だけでなく、責務が分割された横断的な機能であることからプロダクト開発チームとの横断的な連携を要する、という性質を備えていました。 横断的な機能かつ新規APIの開発を伴うプロジェクトということもあり、開発に対するステークホルダーが多いため、 横断的な基盤開発の可能なアーキテクトチームが開発の中心となりました。 LIFULLのエンジニア組織の概観:チームトポロジーの4つの基本的なチームタイプにより分類 プロジェクト序盤:新BFFのアーキテクチャ選定、技術選定、PoC 技術的負債を解決すべく、 Clean Architecture をベースにしたソフトウェアアーキテクチャで 新たなBackend For Frontend API(新BFF)を開発することが決定されました。 言語には学習コストの低さと型システムの存在から TypeScript が選ばれ、OASを備えたミニマルなWeb API Frameworkとして Loopback が採用されました。 技術スタックの選定など、プロジェクト序盤のより詳細な内容は冒頭でお伝えした過去のブログをご覧ください。 新BFFの技術スタック アーキテクチャと技術選定が完了した後は、PoC(Proof of Concept)の一環として「不動産用語集」機能という実在の機能を新BFFへリアーキテクトしました。 その後検証プロセスを経て新BFFが技術的負債の解消に寄与することを確認し、プロジェクトの本格始動となりました。 プロジェクト中盤〜現在:品質維持・改善 初期段階で正しいアーキテクチャ選定や技術選定をすること、あるいは初期のベストな実装のみによって技術的負債の解消や予防になるわけではありません。 「負債」というアナロジーの通り、初期段階では事業の成長を支える資産とも言える技術基盤であっても、継続的な品質維持のための改善を欠いてしまうと負債へと転じ得ります。 継続的な改善を実施するために、内部品質(可読性に問題はないか・保守性は高いかetc)と外部品質(仕様通りに動作するか・速度劣化が生じていないかetc)の両方の点で ソフトウェアテストを徹底して行い、同時にテストがしやすくなるような改善も行ってきました。 ユニットテスト 新BFFではユニットテストとAPIテスト用のテスティングフレームワークとしてJestを使用しています。 jestjs.io 主にテストランナーやテストカバレッジの出力、CI/CDでの自動テストという用途で利用しています。 Clean Architectureベースということもあり、モッキングについてはJestの機能を利用しておらずモック用のコードを作成しています。 コード量の少なかったリアーキテクティング初期フェーズではユニットテストの運用は順調でしたが、コード量が増えるにつれある問題が顕在化しました。 コード量増加とBFF特有処理 テストは重要です。しかしコード量が増えるにつれ、何を担保するテストなのか目的が分からなくなるほど冗長なテストコードを書いてしまう、というケースも目立ち始めました。 特に顕著だったのはDTO変換処理です。 新BFFにおける物件一覧機能用APIでは物件情報を含めたDTO(Data Transfer Object)を変換する処理が頻出します。 それらは以下のように、Domainを除く3つの層(Gateway, UseCase, Presenter)間および外部コンポーネントとのIn/Outの2通り計8パターンで分類できます。 外部データソース(=LSUDs API)のレスポンスオブジェクトをBFF内のGateway(Repository) DTOに変換する処理と、Repository DTOを外部データソースへのリクエストオブジェクトに変換する処理 Repository用DTOとUseCase用DTOとの相互変換処理 UseCase用DTOとPresenter用DTO(検索条件DTOとView Model)との相互変換処理 UI(フロントエンド、モノリシックアプリケーション)から送信されたリクエストオブジェクトをController用DTOに変換する処理、ViewModelをUIへのレスポンスオブジェクトに変換する処理 新BFF内のデータフロー図:Domain以外の層ではDTOを介してデータを送受信 DTO変換処理はレイヤー間の責務の違いによる差分こそありますが、大部分は似たような実装となってしまいます。 下記はそのサンプルコードで、PresenterにおいてInputDtoのプロパティ(ValueObjec)からOutputDtoが要求するプロパティを作成し詰め替える処理です。 export class Presenter { constructor(private readonly input: UseCaseInputDto ) {} present () : OutputDto { return new OutputrDto ( { money: this .input.money ? helper ( this .input.money , this .input.unit , this .input.house_type ) : 'default price' , houseName: // ワンライナーやヘルパー関数の呼び出しなど houseAddress: // // ワンライナーやヘルパー関数の呼び出しなど } ); } helper ( money?: MoneyValueObject , unit?: UnitValueObject , houseType?: HouseTypeValueObject ) : string { // money(金額)のフォーマット処理を行うヘルパー関数 } } リアーキテクティング初期段階ではDTOやプロパティの変換処理は単純なものであったため、ワンライナーや即時的なヘルパー関数への分割でも問題ありませんでした。 やがてモノリシックアプリケーションに存在していた機能の移行が進むと、BFFに実装する処理も複雑になりテストのし辛さも目立ち始めました。 その辛さをカバーすべく冗長なテストコードおよび巨大なモックが増えてしまいました。 この状況を見直すべく実装パターンの見直しを行います。 モジュールの特徴を理解し、高凝集疎結合に そもそもDTO変換処理はフロントエンドの要求に従って必要なプロパティを寄せ集め、用途に沿った加工を施し、扱いやすいよう集約する処理とも言えます。 よってフロントエンドの要求を受け入れるだけのBFFから見れば、偶発的に選ばれたプロパティに対し特に規則性のない処理を施し、一ヵ所に凝集させる処理とみなせます。 そのため注意して実装しなければ必然的に偶発的凝集・論理的凝集が生じ、凝集度の低いモジュールが出来上がってしまいます。 実際に上記のコードからわかるように、凝集度と結合度の観点でDTO変換処理には改善の余地があります。 OutputDtoのconstructorの引数の複雑さ・統一性の無さや、Presenterクラスの責務の多さを見ての通り、 実装の観点で似たような処理をただ集めた論理的凝集、つまり凝集度の低い状態が生じています。 これまでの新BFFではClean Architectureが示した責務別のレイヤー分割を忠実に採用し、 dependency-cruiser による依存関係違反の検知でモジュールの集合間(=レイヤー)の健全性は担保されていました。 しかし、一つのレイヤー内でのモジュール間の結合、および単一モジュールの凝集性は原理原則をヒントにしつつ自分たちで考える必要があったのです。 凝集度が高いモジュールを厚く、低いモジュールを薄く 凝集度とテストの辛さが相まったDTO変換処理問題の解決策として、Humble Objectパターンにヒントを見出しました。 テストの書きやすさと凝集度を両立させるべく、DTO変換処理を「凝集度を高くすべき部分」と「凝集度が低くても良い部分」に分離したのです。 「凝集度を高くすべき部分」では、テストすべきロジック(フォーマット、バリデーションなど)や再利用すべきロジックを集約させるとともに、テストカバレッジ100%を目指すなどしてテストコードを充実させます。 「凝集度が低くても良い部分」では、テストコードをほぼ書かずともTypeScriptの型システムだけで品質が担保可能となるような実装に限定します。 つまり、「凝集度を高くすべき部分」に渡す値とその戻り値を列挙するインタフェースとしてのコードを記述するだけにしました。 簡単な例ですが、具体的には下記のように実装しています。 凝集度が低くても良い部分 // 凝集度が低くても良い部分の実装、テストは薄くていい export class PresenterDtoConverter { constructor(private readonly input: UseCaseInputDto ) {} // (BFF的には)偶発的に必要とされるプロパティは列挙するだけ covert () : PresenterDto { return new PresenterDto ( { // テストすべき凝集度の高い処理(実際のPresentation処理)を呼び出し money: MoneyPresenter.format ( this .input.money , this .input.unit , this .input.house_type ), houseName: HouseNamePresenter.format ( this .input.name , this .input.house_type ), houseAddress: HouseAddressPresenter.format ( this .input.address , this .input.house_type , ), } ); } } 凝集度を高くすべき部分 // 凝集度を高くすべき部分の実装、テストを厚くする export class MoneyPresenter { private static readonly defaultPrice = 'default price' ; // 引数はBFFの最小構成単位であるValue Objectだけ static format ( money?: MoneyValueObject , unit?: UnitValueObject , houseType?: HouseTypeValueObject ) : string { // 複雑なPresentation処理 } } 凝集度に着目した解決策の効果 凝集度を起点に実装パターンを定めたことにより、テストと可読性の両観点でメリットがあります。 可読性の観点では、個別の値に関する仕様については「凝集度を高くすべき部分」を、 フロントエンドが要求する値の一覧については「凝集度が低くても良い部分」を見れば良いという共通認識が形成されます。 テストの観点では、「凝集度を高くすべき部分」は網羅性の高いテストを、「凝集度が低くても良い部分」は全体の結果の成否を確認する程度のテストを記述して テストのしやすさと保守性が担保できました。 もちろんデメリットもあり、それは実装のLOC(Lines Of Code)の増加です。 複雑なコードに慣れ親しんだ熟練者から見れば、変更前のコードこそ行数が少なくシンプルで良いと言えましょうが、今回は民主的にコードの品質を担保することを優先しました。 テストコードの冗長化に端を発する一連の問題でしたが、凝集度に注目したコード品質の向上というアプローチで解決できました。 結合テスト・回帰テスト フロントエンド(モノリシックアプリケーション)とバックエンド(新BFF)およびデータソース(LSUDs API)との結合の際には 複数の観点で結合テスト・回帰テストを実施して参照系アプリケーション全体の品質を担保しています。 しかし、ユニットテストの機構が整備されていないモノリシックアプリケーションがテスト対象に含まれているため、CI/CDでのテスト自動実行だけでは担保しきれない項目も多いです。 そのため、専用のテスト実行スクリプトや各種ツールのグルーコードを集約したライブラリを作成し、 テスト自動実行とローカルでのスクリプト実行とを交えてテストを実施しています。 以下では、ほぼすべてのテスト項目とその効率化のための取り組みについて紹介していきます。 機能系のテスト リアーキテクティングにおいてはその実施前後で、外部から見た挙動や機能が損なわれないことを担保することが必須です。 物件一覧機能においては表示される物件情報に差分が生じず、検索の挙動が仕様どおりで変化しないことを担保します。 その方法自体は以下の通りナイーブなアプローチです。 リアーキテクティング前後のテスト用の環境をそれぞれ用意する それぞれの環境で最終的にserveされるhtmlファイルをcurlによって取得する htmlから不要な要素・メタデータをスクリプトでクレンジングする クレンジングされたhtmlのdiffの有無を検知する diffが生じなければテスト成功 各プロセスのスクリプト化、 Playwright による画面操作の自動化など テスト効率化のための取り組みに加え、1.のテスト環境の用意では自社のアプリケーション実行基盤を活用し効率化しています。 テスト用の環境を用意する際には、Kubernetesベースの内製アプリケーション実行基盤により提供されているエフェメラルな開発環境を利用しています。 こうすることでテスト用環境の整備・管理の時間を削減するとともに、ローカル環境の差分など属人的な要因を排除し、再現性のあるテスト実行環境を用意できます。 テスト用環境はPull Request単位で作成可能で、Pull Request内での特定ラベル付与をトリガとしたGitHub Actionsが実行され、24時間だけ提供されます。 "preview"ラベルをPull Request内で指定するだけでテスト用環境を作成 自社アプリケーション実行基盤については下記などのLIFULL Creators Blogをご覧ください。 www.lifull.blog パフォーマンステスト 複数のコンポーネントが結合された参照系アプリケーションでのパフォーマンステストでは、 エンドユーザーに一番近いフロントエンド部分のレスポンスタイムのパーセンタイル値(p95)をメトリクスとします。 そのパーセンタイル値とSLAを基準にした速度劣化の許容値を比較し成否を判断します。 テスト実行や計測は前述のテスト用スクリプトやエフェメラルな環境を用いて実施しています。 許容できない速度劣化を計測した際など、詳細なパフォーマンス解析が必要になった場合にはFlameGraphを活用したスタックトレーシングにより原因の特定を行います。 開発途中である新BFFにおいては 0x でローカルでの解析を実施し、 それ以外の成熟したコンポーネントでは Datadog APM 上で解析を行いました。 負荷テスト 負荷テストではAmazon CloudWatchから移行対象機能の平常時/ピーク時アクセス数など過去の数値を収集し、 それらを基準として、秒間リクエスト数やリクエスト送信期間などを変えた複数のシナリオを作成します。 新BFFはKubernetesベースの自社アプリケーション実行基盤をインフラとして動作しているため、 そのシナリオ下の負荷でも機能が正常にアクセスできる、あるいは期待通りにスケールアウトするような Podの性能、Podのスケーラビリティなどのリソース調整を完了させることが負荷試験のゴールです。 シナリオベースで負荷テストを実施すべく、負荷テストのツールはHTTP通信用の負荷テストツール Vegeta をベースに作られた Kubernetes ControllerであるVegetaControllerを使用しています。 github.com 下記のようなyamlファイルにシナリオを記述し、 kubectl apply 実行時の引数にシナリオファイルを指定することで実行が可能です。 # シナリオ例: 30req/sec * 60sec のスパイクテスト metadata : name : attack-bff-ephemeral spec : scenario : |- GET bff-ephemeral/v1 GET bff-ephemeral/v1?param=1&flg= true output : text option : duration : 60s rate : 30 結果解析フェーズではサクセスレートや消費メモリの推移、スケールに伴うpod数の推移などをVegetaControllerの出力とGrafanaから取得し、 各シナリオの合否を判定します。 grafana.com Grafanaによる負荷テストの分析(図はPod数の推移) テスト結果の蓄積 これまで紹介したテストの成否やテストケースおよびそのカバレッジ、テスト実行方法、テスト実行時の条件、発生したバグの詳細など、 テスト結果に関する事柄は内製のテスト管理ツールを活用することでダッシュボード化するとともに一ヵ所に集約しています。 内製テスト管理ツール:テストに関するデータとダッシュボードが集約されている このようにして過去のテスト結果を蓄積し活用しやすくすることは、長期間になるリアーキテクティングプロジェクトにとって重要なことです。 リアーキテクティングプロジェクトは ストラングラーパターン というアプローチを執っているため、 対象となる機能すべての移行作業が完了するまでには複数回のリリースが必要となります。 完了には時間にして2年要するとされていました。 そして、その複数回のリリースのいずれにおいても上記のテストプロセスが含まれています。 将来のテストプロセスを効率化するという点で、過去のテストプロセスを活用できるようにしておくことには大きな意味がありました。 また知見を一ヵ所に蓄積し誰でもアクセス可能にすることで、テストに必要な知見を属人化させずにSSOT化できます。(Single Source Of Truth: 信頼できる単一の情報源) SSOTを構築することで、プロジェクト期間中にチームメンバーの入れ替わりが発生した際でもオンボーディング時のオーバーヘッドを最小化し、プロジェクト完遂へのリスクを抑えることができます。 リリース後の品質維持と検証とメトリクス それぞれのテストプロセス後、無事リリースされた後も品質維持のための取り組みは続きます。 内部品質と外部品質の両方の観点で技術的負債の解決を示す指標を計測し、リアーキテクティングによる影響分析を行っています。 その主たるものとして、技術的負債の可視化とパフォーマンスの可視化を紹介します。 内部品質: 技術的負債の可視化 LIFULLでは技術的負債の状況をリアルタイムに反映しているダッシュボードを構築しています。 エンジニアなら誰でも・いつでも・専用の申請なしで・同じ情報にアクセスでき、これもまたSSOTの一つです。 仕組みとしては、GitHub API、CodeClimateQuality APIの2つからコードの品質に関するデータを取得し、それらのデータを Metabase で可視化するというものです。 可視化ダッシュボードや技術的負債に関する指標については、過去のブログをご覧ください。 www.lifull.blog 以下の図のように、GitHub Repository単位で技術的負債を可視化しております。 技術的負債の推移の可視化イメージ リアーキテクティング先の新BFFは技術的負債については、具体的な数字をお見せすることはできませんがほぼ負債を抱えることなく開発できています。 技術的負債比率(図中左上のパーセンテージ)は、Code Climate Quality の MaintainabilityでA相当と低く抑えることができております。 docs.codeclimate.com 一方、リアーキテクティング元のモノリシックアプリケーションの技術的負債については、モノリスゆえの難しさが存在します。 モノリスゆえ特定機能に絞った改善を計測することが難しく、それに加えて物件一覧機能のリアーキテクティング実施中にも別のリファクタリングプロジェクトも進行しています。 そのため、ダッシュボードだけから物件一覧機能のリアーキテクティングに絞って技術的負債解消への寄与度合いを計測することは難しいです。 しかしながら、膨大な推定修復時間(=技術的負債を返済するまでかかる時間)を要するとされたモノリシックアプリケーションの主機能の一つである物件一覧機能を ほぼ技術的負債が見られない新BFFに移行できていることから、本プロジェクトが技術的負債解消の大きな一歩になっていると言えます。 外部品質: パフォーマンスの可視化 既出の通り、外部品質についてはDatadogでのパフォーマンス可視化やGrafanaでのインフラリソース状況推移の可視化を実施しています。 これらに加え、総合的なパフォーマンス推移を計測するためにLIFULL HOME'SのWebサイトのパフォーマンスの推移をSpeedCurveで計測・可視化しています。 www.speedcurve.com 下記は賃貸物件一覧機能(物件一覧機能の一つ)の昨年のパフォーマンスの推移を示した図です。 SpeedCurveによる物件一覧機能Webサイトのパフォーマンス推移 外部品質の点でも別プロジェクトによる軽微な影響は存在し、実際の数字をお見せすることはできませんがリアーキテクティングによってパフォーマンスは維持どころか総じて改善できています。 リアーキテクティングの現在と今後:ノウハウの蓄積とリプレイスに向けて 2022年1月現在、かつてモノリシックアプリケーションに存在した物件一覧機能の多くが新BFFへと移行されました。 プロジェクト発足当初のアーキテクチャ選定、技術選定から2年近くが経過した後も、新BFFおよび物件一覧機能においてインシデントはほぼ発生せず安定稼働を実現できています。 リアーキテクティングプロジェクトはもう少し続きますが、新BFFへのリアーキテクティングも終盤に差し掛かり、今春に予定していた移行作業が完了する見込みです。 しかし、事業の成長の陰に蓄積され続けたモノリシックアプリケーションの技術的負債の完全解決にはまだまだ時間がかかり、2年の時間をかけたリアーキテクティングプロジェクトはその一歩に過ぎません。 とはいえ、リアーキテクティングプロジェクトで得られたコード品質やアーキテクチャに関するノウハウとそれらを活用した後発プロジェクトの存在もあり、可視化ダッシュボード上の数字ほどは途方もない作業ではないと言えます。 フロントエンド部分を含めてモノリシックアプリケーションのリプレイスを実現すべく、プロダクト開発チームによるリファクタリング・リアーキテクティングおよび品質維持が促進されゆく予定です。 終わりに 技術的負債を解決および予防し、継続的にフロー効率の高い開発を行うためにも内製ソフトウェアアーキテクチャを含めた「コードの品質」のための取り組みは今後も続きます。 最後に、今後のLIFULL HOME'Sのシステムにおけるコード品質の今後の展望と、リアーキテクティングプロジェクトを通じて見えたデータの課題をお伝えします。 Clean Architectureの考えを継承しつつ、アーキテクチャ内製化へ Clean Architectureをベースに開発が開始した新BFFのソフトウェアアーキテクチャですが、 アーキテクトチームではClean Architectureが伝えているものはあくまでプリミティブな原理原則であるという認識で開発しています。 凝集度の例にあるように、実際にどのように実装しパターン化するかは機能の特性をもって判断しています。 そのパターンの中には、凝集度の項でお伝えしたような比較的一般化可能なものから、LIFULL独自の制約に由来したことで場合によってはアンチパターンと呼ばれてしまうものもあるかもしれません。 また、新BFFのソフトウェアアーキテクチャは物件一覧機能のリアーキテクティングを行ったプロジェクトおよびその当事者であるアーキテクトチームだけで完結するものではありません。 コードの品質向上に対する成果が認められ、複数の新機能実装プロジェクトや別のリアーキテクティングプロジェクトにおいても新BFFのソフトウェアアーキテクチャが採用・応用されています。 今後は幅広いプロジェクトでの利用に耐え得るように、Clean Architectureの考えを継承しつつ、LIFULL独自のパターンとノウハウを備えた内製ソフトウェアアーキテクチャを正しく普及させ運用することが求められます。 内製ソフトウェアアーキテクチャを普及させる仕組みと教育 内製ソフトウェアアーキテクチャの普及のためには、ドキュメンテーションや開発者コミュニティづくりなど、 プロダクト開発チームが自律的に開発可能になることを補助するための仕組みおよび教育が必要です。 後日公開予定のブログにて、その仕組みづくりなど「プロダクト開発エンジニアとのコミュニケーション」においてアーキテクトチームが実施したことを詳しくお伝えする予定です。 理想とこれからの課題 LIFULL HOME'S の物件情報参照系システム概観:モノリシックアプリケーションの技術的負債が解消した場合の理想形 上記は冒頭に載せたデータフロー図とほぼ同じですが、リアーキテクティングプロジェクト等のモノリシックアプリケーション上の技術的負債解消の取り組みによって、参照系アプリケーション開発の分散統治が可能になった将来的な理想形です。 開発の度に全社的な調整を要することもあるモノリシックアプリケーションから、部署レベルでの自治(self-service)が可能な単位で機能が切り離される、という構図です。 その端緒であり、技術的負債解消という当初の目的を果たしつつあるリアーキテクティングプロジェクトですが、self-serviceの障壁となり得る課題がプロジェクトを通じて顕になりました。 それがデータ整備です。 図中でLIFULL HOME'Sのシステムを「データ分析システム」・「データ利用システム」・「データ提供システム」の3つに分類しましたが、 その3つを通じて運用されるデータの品質には依然として課題があり、整備する余地があると考えています。 データ整備の課題とその解決のために データ分析・活用の文脈で語られることの多いデータ整備ですが、LIFULLのように一定以上の規模と歴史を持つ業務用アプリケーション開発においてもデータ整備の課題は顕著であると考えています。 その中でリアーキテクティングプロジェクトにおいて体感した課題はデータの発見可能性です。 既存システムの理解のためにコードリーディングを行う機会は多々ありましたが、 改修対象のモノリシックアプリケーションのコードリーディングに加え、大元のデータソースであるLSUDs APIやデータベースを対象とした利用すべきデータの発掘やデータ仕様調査にも多くの時間を要しました。 つまり、「データ提供システム」で生成されるデータが「データ利用システム」で利用可能になるまでに属人的な取り組みが必要だったのです。 リアーキテクティングプロジェクトとは別の調査で判明していることですが、上記以外にも以下のような課題があると考えています。 分析用データ(OLAP)と、アプリケーション用データ(OLTP)の一貫性の問題(→「データ分析システム」と「データ利用システム」間のデータ相互運用性が低い) 特定のアプリケーション向けに加工されたデータを再加工する必要性の存在(→「データ利用システム」間のデータ相互運用性が低い) 再利用すべき大元のデータおよびそのデータに至る経路が見つけられない、見つけられないので似たようなデータを使うか自作してしまう(→システムを通じたデータ系統樹:Data Lineageの問題) データ整備が起因する課題はドキュメンテーションや有識者へのヒアリングなど、静的なコンテンツの整備や属人的な努力によって一時的には解決可能な問題です。 しかし、大規模なデータを抱えるLIFULLにおいて持続可能性のある解決策を実現するためには、データをマネジメント・発見・一覧可能な基盤づくりが必要と考え現在はその検証が進行中です。 求人情報 LIFULLではエンジニアの募集をしております。 このブログで紹介させていただいたような、Clean ArchitectureとTypeScriptで堅牢なアプリケーション開発を行う業務も可能ですので、募集中の職種や詳細などは下記をご覧ください。 hrmos.co hrmos.co
みなさん、こんにちは。品質改善推進ユニット クオリティエンジニアリンググループの平野です。 2020年4月に新卒で入社し、現在はセキュリティ/テスト自動化に関する推進、支援などを中心に取り組んでいます。 私事ではありますが、所属するグループでの業務の性質などもありプロダクトをゼロからしっかりと作るという経験をしたことがありませんでした。 そんな私がLIFULLでの新卒エンジニア2年目研修【SET】を受講して何を得たかについて、研修の紹介と合わせて説明します。 目次 SETとは 開発サービス紹介 インフラ フロントエンド バックエンド 学び・反省点 学び 反省点 おわりに SETとは はじめに申し上げますと、ここでいうSETとは社内での造語で「Sophomore Engineers Training」の略です。 テストの自動化などを推進するエンジニアであるSET(Software Engineer in Test)とは全くの別物です。 LIFULLの「理想のエンジニア像」のひとつは、バックエンドからフロントまで一通りこなせるWebアプリケーションエンジニアです。 しかし、業務で触れるスコープが限られているケースが多く幅広く業務を行う機会を得られない、という課題もありました。 そのような背景から生まれたのがこの研修であり、開始から7年ほど行われています。 以下が研修の目的です。 サービスをスクラッチから開発する過程を通してサービスを動かすために必要な要素を学ぶ 今まで触れる機会の少なかった分野を経験する機会を作り出す 研修では数人一組のチームでサービスをゼロから創り上げることが課題として与えられ、参加者は普段の業務から離れ集中的に取り組みます。 開発サービス紹介 今年の研修では私たちを含め計3チームおりましたが、私たちはQuoraを模したQ&Aサービスを開発しました。 トップページ Q&Aサービスを選んだ理由はいくつかありますが、一番の理由は設計が比較的容易かつ認証やデータベースなどWebアプリケーション開発で必要不可欠な技術に触れられるからです。 jp.quora.com 開発は大まかに以下の3つに分けて行い、私はその中でもバックエンドを主に担当しました。 なお、チームメンバーそれぞれが未経験の分野を担当しています。 インフラ(AWSを利用) フロントエンド(Vue.js) バックエンド(Go+Gin+GORM) インフラ 開発環境と本番環境の2種類を用意し、それぞれをAWSの提供するIaC(Infrastructure as Code)サービスであるAWS CloudFormationでコード化しました。 開発環境 本番環境 フロントエンド Vue.jsを用いてSPAに対応させたことにより、質問や回答追加ページ、一覧表示ページをシームレスに遷移できます。 バックエンド(APIサーバ)へのPOSTリクエストは、JSON形式でデータが送信されます。 バックエンド APIサーバを構築し、フロントエンドから指定したURL(質問追加、回答一覧表示など)にリクエストが来た際にJSON形式でデータを返却するようにしました。その際にDBを操作するORMとしてGORMを利用しています。 以下は回答一覧表示の返却値サンプルですが、 results の中に回答IDや回答内容、質問に紐づく回答IDなどを配列として入れることで一括返却ができるようにしています。 { "results": [ { "user_id": 15, "question_id": 6, "question_title": "Vue.jsが分かりません", "question_body": "おすすめの学習方法はありますか?", "question_rate": 2, "answer_ids": [ 10 ], "n_answers": 1, "answer_id": 10, "comment": "ますは公式ドキュメントを読みましょう", "answer_rate": 3, "user": { "user_id": 15, "user_name": "homes-kun" } }, { .... } ] } 学び・反省点 学び 個人としては、研修を通して3つのノウハウを得ることができました。 API設計の基礎 アーキテクチャを意識した開発スキル DB設計・操作の知識 1つ目のAPI設計の基礎について、私自身APIの概要や良し悪しは把握していたものの実際に設計したことはありませんでした。 普段の業務でもこれまで触れることのなかった箇所にしっかりと触れることができ、大きな学びとなりました。 2つ目のアーキテクチャを意識した開発スキルについて、今回の開発では代表的なアーキテクチャの一つであるMVCを採用しました。 知識として基本的なことは知っていてもそれを利用した開発経験に乏しかった私にとって、実装は苦労したもののMVCの恩恵を身をもって享受できスキル向上につながりました。 3つ目のDB設計・操作の知識についても、座学で理解するだけでは得られないものを実践を通して得る良い機会となりました。 なお、チームメンバーからは以下のような声がありました。 ちゃんとしたフロントエンドの開発がはじめてだったので、学びになった(フロントエンド担当) デプロイを意識した本番環境構築ができた(インフラ担当) 反省点 個人としての反省点は以下の2つです。 つまずき調査する時間が研修期間の多くを占めてしまい、予定した箇所まで実装が完了しなかった フロントエンド側との連携がうまくできなかった 1つ目について、分からないことを調査すること自体は自身の学びにつながります。 一方で、調査に時間を使いすぎてしまい、そこでストップし続けてしまうのはよくありません。 今回は研修だったので期日までにすべて実装できなくても問題ありませんでしたが、実際の業務でそうはいきません。結果的に早めに相談した方がスムーズに進むということは多々あるかと思いますので、調査と相談のバランスをうまく取りながら今後の業務をしていきたいと強く感じました。 2つ目について、開発期間中はフロントエンドとバックエンドそれぞれで開発しておりました。 ですので、つなぎ合わせての動作確認を自身の担当だったバックエンドの開発がある程度進んでからしようと考えていたところ、開発の遅れから研修最終日にすることとなってしまいました。 いざつなぎ合わせてみると、フロントエンドから送られてくるデータとバックエンド側で受け取るデータの形式が違うことによるエラーなど単体では発生しなかった問題が複数発生しました。そして、設計の重要性を痛感するとともにもっと早くから確認できていればと感じました。このことは、今後の業務に活かしていきたいと思います。 おわりに 今回の記事では、LIFULLでの新卒エンジニア2年目研修【SET】の説明とそこで得たことについて紹介いたしました。 2週間超も普段の業務から離れてスキルアップに充てる機会をいただけたのは大変ありがたく、結果として多くの学びを得ることができました。今後も研修で得たことを忘れず、業務や自己研鑽等でスキルをアップし続け、一人前のエンジニアを目指していきます。 最後になりますが、LIFULLでは一緒に働く仲間を募集しております。よろしければぜひこちらのページもご覧ください。 hrmos.co hrmos.co
LIFULL札幌開発拠点で働くエンジニアの村田です。 本エントリーは LIFULL Advent Calendar2021 、12月20日の記事になります。 私が働く札幌では、この時期雪が積もり始め寒さも厳しくなってきます。 東京本社から札幌に職場を移してから早3年が経ちましたが、ようやく札幌の寒さにも慣れてきた今日この頃です。 私が所属する部署は東京本社と札幌支社のエンジニアで構成された部署になり、社内では通称KEELチームと呼ばれています。 KEELとは、LIFULLグループ全体で利用することを目的としたKubernetesベースの内製のアプリケーション実行基盤です。 詳しくは以下のエントリーをご覧ください。 www.lifull.blog KEELはLIFULLのアプリケーションの開発・運用に必要な多くの機能を提供しています。 本エントリーでは、KEELが提供する監視基盤の一部であるURI毎のサクセスレート可視化機能のお話しをしたいと思います。 背景 LIFULLの主要サービスであるLIFULL HOME'Sは20年以上続いているサービスであり、非常に多くのコンテンツを保有したサービスに成長しています。 このモノリスな巨大アプリケーションを運用するにあたり、障害検知に関するとある問題が発生していました。 ことLIFULL HOME'Sにおいては、サイト全体に影響を及ぼすような、ある程度規模の大きい障害であればすぐに検知できるのですが 特定のコンテンツのみで障害が発生した場合、アプリケーション全体のサクセスレートが閾値まで押し下がらずアラート通知されないまま、その不具合が見過ごされてしまうといった事がありました。 URI毎のサクセスレートの開発 KEELチームが問題解決のアプローチとして導き出した答えは、URI毎にサクセスレートを確認できるダッシュボード機能の開発でした。 説明するよりもまずは現在運用されている実物の画面を見てもらう方がイメージがつきやすいと思います。 アプリケーションダッシュボード アプリケーションのダッシュボードの上部には、ステータスコード毎のRPSや、パフォーマンスのパーセンタイル値、その下には各URIのRPS・パフォーマンス・サクセスレートが表示されています。サクセスレートが正常であれば緑で表示されますが、低下している状態だと赤くハイライトされ一目でどのコンテンツに異常が起きているかわかるようになっています。 上記のイメージに表示されていませんが、CPUやメモリのリソースの状態やPod数の推移などのパネルも用意されており、アプリ開発者はこのダッシュボードを見るだけでアプリケーションの状態を把握することができます。アプリケーションによっては、アプリケーションサーバーのworker数なども確認することができます。 どのように実現したか URI毎のサクセスレートの可視化は、以下のようなステップで実現しています。 コンテナから出力されたアクセスログをFluentdにて集計しPrometheusにメトリクスを送信 ダッシュボードで使用するメトリクスをRecording Ruleで予め集計して用意しておく Grafanaのダッシュボードで集計したメトリクスを可視化する アラートルールを設定する まず、コンテナが出力したアプリケーションのアクセスログをFluentdにて集計し、Prometheusにメトリクスを送信しています。 ここで作成されるメトリクスはラベルにURIやHTTPメソッドを持ち、リクエストを識別できるようにしています。 メトリクスタイプはヒストグラムを利用しており、パフォーマンスをパーセンタイル値で表示するのに適した形になっています。 ここで注意したいのが、全てのURIをラベルに含んでしまうとカーディナリティが高くなりPrometheusのリソースを大量に消費してしまいます。 URIにIDといったパラメータが含まれている場合、それだけで無数のURIが生まれてしまいますので、そうならないように、アプリケーション毎に「ラベルとして登録できるURIのプレフィックスリスト」を定義しておき、集計対象となるURIを限定しています。 これで必要最低限のメトリクスの準備はできましたが、実際はこれをベースに様々なPromQL式を評価して目的とするデータを得る必要があります。PrometheusにはあらかじめPromQL式を評価しその結果を新たなメトリクスとして保持することができるRecording Ruleという機能があります。この機能を利用し、必要なデータを前もって計算しておくことで処理の高速化をはかっています。 メトリクスの可視化にはGrafanaを利用しています。 Grafanaのダッシュボードは、UIを利用して手動でパネルを組み合わせて構築することも可能ですが、アプリケーション毎に手動で構築するのは運用の面から考えても避けたいものです。 そこでGrafanaのダッシュボードをJsonnetでコード管理することにしました。 当初Jsonnetの用意は開発者が手動で行っていましたが、コードジェネレーターである keelctl が開発されてからは、上記のJsonnetファイルがコマンド一発で自動生成されるようになり、容易にダッシュボードの作成ができるようになりました。 最後はアラートの設定です。 閾値を調整したり、アラート発生時のRunbookを設定することがURIそれぞれで可能になりました。アラートルールも上記と同様にJsonnetで管理されており、keelctlを利用して開発者は容易にアラート設定を行うことができます。 何が変わったか アプリケーションのURI毎のサクセスレートが可視化された結果、どのような変化がLIFULLにもたらされたでしょうか? 一番大きく変わったのは、今まで見えてこなかった細かな不具合が見つかるようになりました。 URI毎にサクセスレートを計測できることになったことで、それぞれのURI単位でアラートを通知できるようになりました。 今まではサイト全体のサクセスレートが閾値を割らないとアラートが通知されず、細かい不具合は露呈されませんでしたが パス毎にアラートを飛ばすことができるようになったため、今まで見過ごされてきた多くの不具合を見つけることができました。 結果LIFULLのサービスの品質向上にかなり寄与できたと思います。 さらに、障害調査の点でも効率が上がる結果となりました。 従来、障害が発生した際に、まずは影響範囲を調査する必要がありましたが、ダッシュボードを確認するだけでアプリケーションのどの部分でエラーが発生しているのかすぐに把握できるようになっています。 URI毎のアラートにRunbookを設定できるようになっていますので、例えばDBにアクセスしているコンテンツでサクセスレートが低下しているなら、対応するURIのアラートにDBの障害を疑うといったヒントを記述しておくといったようなことができ、調査効率が飛躍的に向上しました。 slackに通知されるアラート 障害がどのURIで発生しているのかを明確にしたことで、障害対応のフローにも変化が起きました。 LIFULL HOME'Sは一つのアプリケーションに多くのコンテンツが含まれており、それを管轄する部署が多岐に渡ります。 仮に障害が発生した場合、どこの部分で障害が発生したかで対応する部署が変わってきます。 KEELチームが障害を検知したとしても、それをどこの部署に報告すれば良いか判断が難しい場合がありました。 そこでURIのパターンによって管轄部署を定義することで、障害発生時のエスカレーションを無駄なく行うことができるようになりました。 具体的には、障害が発生した際にBot経由でGitHubに障害チケットを作成し、その対象URIに対応した部署のラベルを自動で付与します。 開発者は自分が所属する部署のラベルが付与された障害チケットが発行されると、その障害の調査・解消にあたる、といった障害対応フローが確立されるようになりました。 自動起票されたissue まとめ LIFULLを支える監視基盤を構成する要素の一つであるURI毎のサクセスレート可視化について紹介させていただきました。 アプリケーションのURI毎に細かい情報を可視化することで、今まで見過ごされてきた思わぬ不具合を見つけることができ、障害発生時にも効率良い調査が可能になりました。 障害対応フローも整備され、今では細かい不具合も見逃さず検知し、うまく対応できるような体制が構築されました。 結果、URI毎のサクセスレート可視化を起点にBPRに繋がる形にまで発展させられたことを嬉しく思います。 KEELチームはLIFULLが掲げる「あらゆるLIFEを、FULLに。」の実現に向けて、LIFULLのものづくりを加速させるためのプラットフォームを革進し続けています。今回お話しさせていただいた機能以外の取り組みについては、以下のエントリー一覧をご覧ください。 www.lifull.blog 最後にLIFULLの採用について少し触れさせてください。 LIFULLでは、「あらゆるLIFEを、FULLに。」に実現を目指して共に働いていただける仲間を募集しています。 カジュアル面談という形で、まずは気軽にお話をさせていただく、ということも可能ですので、ご興味がある方は以下のページをご覧ください。 hrmos.co hrmos.co
こんにちは!Ltech運営チームの井上です。今回は2021年12月15日(水)に開催した「Kubernetesを用いたアプリケーション実行基盤の取り組み」についてレポートします。 lifull.connpass.com Ltechとは Ltech(エルテック)とは、LIFULLがお送りする、技術欲をFULLにするイベントです。特定の技術に偏らず、様々な技術の話を展開していく予定です。 LIFULLの全社アプリケーション実行基盤 KEEL について LIFULLではKubernetesベースのアプリケーション実行基盤を内製しており、KEELと呼んでいます。KEELは社内ですでに3年の本番環境での運用実績があり、LIFULL HOME'Sの大部分はKEEL上で稼働しています。 LIFULL HOME'Sの全トラフィックの約9割がこのKEEL上で稼働しているアプリケーションにより処理されています。 そんなLIFULL内製PaaSであるKEELがなぜ生まれたのか、そしてどのような課題を解決しようとしているのかについてのお話です。 LIFULLの全社アプリケーション実行基盤 KEEL について from LIFULL Co., Ltd. www.slideshare.net KEELができる以前のLIFULLでは、 マイクロサービス化を推進しており、たくさんのアプリケーションが稼働していました。マイクロサービス化を進めていくことによって開発効率の向上に成功した一方で、監視やデプロイの仕組みの「車輪の再発明」が頻発するなど、新たな課題が顕在化していました。これらの課題を解決するために、インフラストラクチャの中央集権化を決意したのがKEELの始まりでした。 KEELはすでに開発者の負担を軽減する多くの便利な機能を有していますが、更に開発効率の向上を実現する機能を追加するため、KEELチームでは開発者へのヒアリングなども都度行い、追加する機能の選定や優先度付けを行なっています。 私もLIFULLの開発者の1人として、今後の機能追加が楽しみだと改めて感じる発表でした! Kubernetesセキュリティの歩き方 LIFULLではマルチテナントのKubernetesクラスタを運用しています。様々なアプリケーションが1つのクラスタに混在する中で、OPA GatekeeperやConftest を用いて、セキュアなKubernetesクラスタを実現している方法についてのお話でした。 Kubernetesセキュリティの歩き方 from LIFULL Co., Ltd. www.slideshare.net 以前のKEELでは、不適切な設定や悪意のある設定を含むマニフェストがデプロイ可能な状態になっていました。また、マニフェストのチェックを人力で行なっていたため、チェックのコストも少なくありませんし、見落としの可能性をゼロにできていませんでした。 セキュリティについては情報の流れがとても早く、開発者全員が全てを理解することはとても困難ですよね。GitHub Actions で Pull Request ごとにマニフェストのチェックを自動化することで、チェックのコストがほぼ lint の実行時間だけになり、また見落としのリスクをゼロにすることができました。開発者が感じる不安の大部分を解消することができていて、私もLIFULLの開発者の一人としてその恩恵を享受することができています。 Kubernetesクラスタバージョンアップを支える技術 LIFULLのKubernetesクラスタでは、安全にバージョンアップを行うためにKubernetesクラスタ構築とE2Eテストの自動化を行っています。またAdmission Webhookを利用し後方互換を保ちながらバージョンアップを行う仕組みも導入しています。これらの自動化の手法についてのお話でした。 Kubernetesクラスタバージョンアップを支える技術 from LIFULL Co., Ltd. www.slideshare.net アプリケーション開発において切っても切れないのがバージョンアップ。このような運用作業はミスが許されない為、頻繁に行うことを避けがちになってしまいます。またメンバー入れ替えでの作業手順の引継ぎなどがうまくいかず、苦労するケースは少なくないですよね。 作業手順のスクリプト化によってとにかく手作業をなくし、誰でも低コスト高頻度でバージョンアップ作業ができるようにすることは、安全なアプリケーション運用をしていく中では、Kubernetesクラスタ以外にも必要不可欠なことだと思います。自動テストも含めた自動アップデートの仕組みを作って、健全なサービス運用を更に進めていきたいと感じさせられる発表でした! まとめ 今回はLIFULLの内製アプリケーション実行基盤であるKEELについて、3名のエンジニアに発表いただきました。KEELについてはチームメンバーが随時 LIFULL Creators Blog にて情報を発信しています。興味を持っていただいた方にはぜひ1度ご覧いただきたい記事ばかりになっています! www.lifull.blog Ltechでは、LIFULLのエンジニアが中心になって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。今後も Ltech を積極的に開催していきますので、ぜひ気になった方は、connpass で LIFULL のメンバー登録をよろしくお願いします! lifull.connpass.com また、LIFULLでは今回紹介したアプリケーション実行基盤に関わるものを含め、数多くの職種の仲間を募集しています。 よろしければこちらのページもご覧ください。 hrmos.co hrmos.co