TECH PLAY

株式会社LIFULL

株式会社LIFULL の技術ブログ

656

技術開発部改めKEELチームの相原です。 今回はLIFULLの全社アプリケーション実行基盤 KEEL について紹介いたします。 全社アプリケーション実行基盤 KEEL とは KEELとはLIFULLグループ全体で利用することを目的としたKubernetesベースのアプリケーション実行基盤です。 keel は船の竜骨を意味する英単語で、 spinnaker/keel や keel-hq/keel と名前が被ってしまっていますが、LIFULLという船を支える屋台骨となるため2018年初頭から開発・運用を続けている内製のプロジェクトです。 マルチテナントなシングルクラスタで、 コンテナオーケストレーション ネットワーク サービスメッシュ デプロイ メトリクス ログ 分散トレーシング セキュリティ ワークフローエンジン をはじめとしてアプリケーションの運用で必要になる多くのものを責任範囲として提供しています。 その他にも各種マニフェスト生成ツールや認証基盤の開発にProxySQLやRedis, memcachedクラスタの提供、アプリケーションフレームワークの提供とKEELへのアプリケーション受け入れなど広範的に開発者を支援しています。 既にLIFULLのアプリケーションの大部分がこのKEEL上で稼働しており、新規開発のアプリケーションの多くもこのKEELに載せることを前提に開発されてきました。 背景 LIFULL HOME'S サービス開始から20年以上が経ち、コードベースも次第に巨大になってきました。 そしてコードベースが巨大になるにつれて、デプロイ速度の鈍化やメンテナンス性の低下が目立つようになり、開発速度が低下していきました。 そうした変化を受けて LIFULL では、数年前のオンプレミスからの AWS 移行を契機にマイクロサービス化に踏み切ります。 サービスを適切な単位で切り分けてデプロイを独立化し、開発チームに権限を移譲することで分業化に成功しました。 しかし、年月が経ち新たな課題が見え始めました。 それはマイクロサービス化による車輪の再発明と分散システムとしての難しさです。 それぞれのチームがロギング・監視基盤やデプロイフローを個別に構築したり、各アプリケーションごとに Retrying や Timeout を実装することにより、従来の体制と比較して重複する機能が多くなってしまいました。 加えて、下流のサービスに巻き込まれる形での障害も目立つようになり、分散したアプリケーションをうまく運用するという難しさにも直面することになったのです。 そこで我々は、統一されたアプリケーション実行基盤を開発して分散システムの難しさを解決すると同時に車輪の再発明を防ぐことを狙うことにしました。 結果として開発者がアプリケーションをローンチするまでの負荷が大きく下がり、効率を落とすことなくシステムの分離度を適切に保つことができるようになりました。 KEELチームとこれまでのアウトプット もともとは私一人で開始したこのプロジェクトも今では4人のメンバーがジョインして大きくなってきました。 我々のミッションは「 LIFULLのものづくりを加速させるアプリケーション実行基盤を実現する 」ことです。 LIFULLのものづくりを加速させることで、LIFULLの目指す「 あらゆるLIFEを、FULLに。 」という世界観実現にアプリケーション実行基盤というスケーラブルなアプローチで貢献します。 KEELチームにはその実現にあたって必要なスペシャリティを持ったメンバーが集まっていて、今後チームからのアウトプットを増やしていくためその紹介としてこのエントリを書くことにしました。 これまでは以下のようなエントリを書いてきました。 www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog www.lifull.blog まとめ LIFULLにはKEELという全社アプリケーション実行基盤があり、アプリケーションの運用に必要な多くのものを提供しながら広範的に開発者を支援しています。 今後我々KEELチームからのアウトプットを増やしていきますのでご期待いただけると幸いです。 カジュアル面談もやっていますので、一緒に「 LIFULLのものづくりを加速させるアプリケーション実行基盤を実現する 」、ひいてはLIFULLが目指している「 あらゆるLIFEを、FULLに。 」することに興味がある方は是非お話しましょう! hrmos.co
品質改善推進ユニットの中野です。 LIFULLでは、2015年に開発プロジェクトの支援を目的としたQAチームを立ち上げ、これまで様々な活動を行なってきました。 この記事では、QAチームの現在の取り組みや実行に至った経緯や考えなどを書いていきたいと思います。 組織の変遷に関しては、以前弊社の藤澤が投稿したブログがありますので、そちらもよろしければ、あわせてご参照ください。 www.lifull.blog QAのミッション QAチームは、プロダクト開発に関わるものづくりのメンバーが、安全かつ高速にリリースを繰り返すことを支援し、安心して開発に取り組める状況をつくることにあります。 さらにその先には、プロダクトライフサイクルにおけるステージ、サービスの特性、開発チームのプロセスや成熟度に合わせて、各チームにあったテスト戦略を見出し、改善を後押しすることで、ストレスの少ないものづくりが行われていくための仕組み作りを継続していきたいと考えています。 プロジェクトへのQAの関わり方 社内には異なる規模、異なるスケジュールで様々な開発や保守のプロジェクトが動いています。 QAは、LIFULLの各事業領域のサービスやプロジェクトの品質を向上させることを目指しています。 全てのプロジェクトへ均等な支援を行うのではなく、支援内容は、テスト技術の不足を補う視点で、プロジェクトの状況をモニタリングしつつ決定しています。 全体の活動イメージは下記の通りです。 各支援内容の目的は下記の通りです。 リスク分析・・・プロジェクトの施策内容、開発要件などを確認して事業インパクトやプロダクトリスクを把握し懸念があればサポートする テスト計画コンシェルジュ・・・テスト計画の作成を支援することでテスト戦略やアプローチを整理し、テストの効果や効率を向上させる リリース前リスク分析・・・プロジェクトの状況やテスト内容を把握しQA側でリスク低減のアクションの必要有無を判断する QAテスト・・・リリース前のテスト(主に探索的テスト)を実施し問題があれば開発側へフィードバックする QAサポート・・・開発プロジェクトにQAとして参加し、テスト全体、もしくは、一部分を担うことでプロジェクトのQCDを向上させる パフォーマンス監視・・・リリース後のパフォーマンスを監視し、問題があれば開発側へフィードバックする 本番障害分析・・・本番運用中に発生した障害情報を分析し、将来の開発に役立つようにテストなどの改善を検討する 関わり方の決定は、リスク分析を起点にQA側でアプローチする場合もあれば、ものづくりからの支援依頼を元に、テスト計画コンシェルジュや、QAサポートを行う場合もあります。 QAサポートの支援内容はプロジェクトによって様々で、相談だけで完結するものもありますし、レビューや特定のタスクだけを請け負う場合もあれば、プロジェクト全体を通してテストマネージメントを行う場合もあります。 テスト計画コンシェルジュ ユーザーにとってちょうど良い品質作りを効率よく行うために、テストのアプローチに過不足が出ないように「テスト計画コンシェルジュ」というサービスにより、テスト計画の作成代行やレビューの支援などにも力を入れています。テスト計画をサービスとして切り出している理由は、テスト計画の中で適切なアプローチの決定が、テストプロジェクトの明暗を分ける要因だと考えているからです。 言い換えれば、テスト計画の精度が高ければ、後工程にQAチームが関わらなくても開発チームのメンバーでテストを効率よく進めることができるのではないかと思っています。 余談ですが、このテスト計画コンシェルジュを始めた頃に比べると、数年たった今では、必要に応じて開発側でテスト計画を作ってテストの検討を進めてくれることも多くなったと感じています。 下記はテスト計画コンシェルジュの効果の期待を表したイメージです。 リリース前リスク分析を起点としたQAのアクション プロジェクトに参加しない場合でも、直近のリリース情報を元にQA側でリスクに応じて成果物の確認などを行います。 さらに必要に応じてリリース前のQAテスト(探索的テスト)を実施し問題があれば開発チームにフィードバックします。 テストにおける改善活動 開発チームの状況によって対応は様々ですが、成熟度が高いチームでは、品質に関わる活動をチームで考え、最適なテストやレビューなどを実践していきます。 また、安心して開発に集中できるようなストレスが少ない環境作りもQAチームの重要な役割だと考えています。 QAの活動としては以下のような取り組みを実施しています。 新卒エンジニアや様々な職種向けの研修の実施 探索的テストのチャーターの保守 テストツールの開発 テストデータの提供 システムテスト標準の作成 最後に 年々、支援を求められるプロジェクトの数も増え、難易度も上がり続けていますが、現場におけるテストの最適化や、テスト資産の利活用などまだまだ改善できる領域がありますので、現場に寄り添い継続的に改善に努めたいと考えています。 また、この記事では概要の説明に留めましたが、個々の取り組みについても、また別の機会に記事を公開する予定でいます。
AI戦略室の椎橋です。弊社で取り組んでいるディープラーニングの活用事例を紹介します。 空飛ぶホームズくん 空飛ぶホームズくんとは、平面の間取り図から3Dの部屋を生成する技術を用い(※特許取得済み)、バーチャル内見できるVRサービスです。詳細は以下のリンクに書いてあります。 lifull.com 平面の間取り図から3Dの部屋を生成する技術では主にディープラーニングを使っていて、今回はその計算処理について紹介します。 先行研究 間取り図の画像解析の先行研究では"Deep Floor Plan Recognition Using a Multi-Task Network with Room-Boundary-Guided Attention"があります。 https://openaccess.thecvf.com/content_ICCV_2019/papers/Zeng_Deep_Floor_Plan_Recognition_Using_a_Multi-Task_Network_With_Room-Boundary-Guided_ICCV_2019_paper.pdf これは間取り図のセマンティックセグメンテーションタスクの研究で、論文の資料を抜粋すると下図で(a)の入力画像に対して(b)が正解ラベルがになり(c)が推論結果として出力するディープラーニングモデルをつくるというものです。 論文の添付画像から抜粋 ニューラルネットワークの構築の考え方は下図にあるように部屋の種別(room type)か部屋を構成する境界(room boundary)かで2つの出力層を設けることできれいに壁とドアの位置を推論できるというものです。 論文の添付画像から抜粋, ニューラルネットワーク構築の考え方 LIFULLでの実装 LIFULLでは上記の先行研究のベースのアルゴリズムを踏襲しつつ、3Dモデルを作るためにいくつか変更を加えました。最も大きな変更は部屋の種別(room type)と境界(room boundary)に加えて、キッチンカウンターやトイレなどのiconを第3の出力層として新たに追加しました。下の画像だと左が元画像、中央がroom typeとroom boundaryのラベル、右がアイコンのラベルになります。セマンティックセグメンテーションではピクセル単位に分類タスクを行うので、画像の中央と右は各ピクセルにラベルを0,1,2,...と割り当てて可視化のために対応するRGB値で塗ってある画像になります。セマンティックセグメンテーションタスクの出力データ、すなわち、ピクセル単位にラベルを割り当てたデータのことを本記事ではセマンティックデータと呼ぶことにします。 LIFULLでのニューラルネットワーク構築の考え方 その他の変更点については本記事の最後に添付するslideshareをご覧ください。 推論後の後処理 後処理としてセマンティックデータから輪郭抽出して3Dモデルの生成に必要なデータ形式に変換します。opencvのfindcontours関数で輪郭抽出します。下の画像で左がセマンティックデータで1ピクセルごとにラベルが割り当てられていて、右が輪郭抽出後のデータで、白点で表したポリゴンの端点情報のみから可視化したデータになります。セマンティックデータは画像サイズ数の値を保持していて、変換後では白い点の数だけの値を保持していることになります。 推論結果(左)と輪郭抽出結果(右) 輪郭抽出することで間取り図のどこに何があるかをデータに落とし込むことができました。そこから平易な計算をすることで人間が間取り図をみて解釈できる情報を得られます。具体的には以下の項目です。 アイコンの向き 下図でキッチンカウンター、トイレ、洗面台を使うときに人間が位置する方向に白丸をつけました。これがないと3Dにしたときに違和感のある配置になってしまいます。 アイコンの向き判定結果 導線生成 人間が部屋間を行き来するための導線を計算できます。google mapにあるようなウォークスルーを実現するのに必要です。 導線生成 バルコニーの壁と室内の壁の判別 画像で見るとバルコニーの壁と部屋の壁は区別がつきませんが、常識的に考えてバルコニーは外の景気がみられるように高さが低くなっています。一方で室内の壁は天井まで高さがあります。下図でバルコニーの壁(緑)と室内の壁(赤)を色分けできています。 バルコニーの壁と室内壁の判定(右) グラフ構造 下図で廊下(corridor, 黒で囲ったノード)からldk(DK),west(洋室),out(家の外),bath_toiket_washing_room(洗面所)にエッジが引かれているように部屋がどのように結合されているかをグラフ構造にして知ることができます。2LDKの間取りで1つの部屋がリビングとつながっていないほうがいい、バルコニーに行き来できる部屋が2つある、などの2LDKよりもさらに細かい条件を検索できるようになります。 その他 その他としては縮尺を概算できたり、窓とドアの区別ができたりして、これらの人間が解釈できる要素を取り出していくことでより現実に近い3Dモデルの生成が可能になります。 最後に 間取り図のディープラーニング活用事例を紹介しました。間取り図の解析は機械学習界隈では頻繁に出てくるテーマではないので目新しさがあったと思います。弊社ではレコメンドやチャットボットなどの汎用性の高い技術でなく不動産のドメインに特化した研究開発も行っています。ドメイン特化の研究開発は世界で事例が少ないこともあり、難易度は低くないですが、その分やりがいはあるかと思います。 弊社では、執筆日(2020年11月)時点で機械学習エンジニアを募集しています。カジュアルな面談で弊社の様子をお伝えすることもできます。興味ありましたらご覧ください。 https://hrmos.co/pages/lifull/jobs/010-0041 hrmos.co LTechでも発表しました 【Ltech#11】ディープラーニングで間取り図を3Dにする from LIFULL Co., Ltd. www.slideshare.net
こんにちは、プロダクトエンジニアリング部の二宮です。 昨年に引き続き、今年も LIFULLのQiita Organization で企業アドベントカレンダーを行います🎉 LIFULL Advent Calendar 2020 LIFULL その2 Advent Calendar 2020 LIFULL 統計・機械学習編 Advent Calendar 2020 「株式会社LIFULLってどんなメンバーがいるの?」「どんな技術が使われてるの?」「どんな風に仕事しているの?」と興味を持たれている方は、それぞれの記事をご覧いただけると想像頂けると思います。 このLIFULL Creators Blogに比べて、Qiitaではより技術職メンバー個人の情報発信・共有にフォーカスしており、アドベントカレンダーでもそれぞれの工夫や発見を共有します。 それでは、12月1日からの更新をお楽しみに!
お久しぶりです、Ltech運営チームの秀野です! 今回は、2020年10月29日(木)に開催した『 Ltech#11 不動産領域のAI活用最前線 〜初完全リモート開催〜 』についてレポートします! Ltechとは Ltech(エルテック)とは、LIFULLがお送りする、技術欲をFULLにするイベントです。特定の技術に偏らず、様々な技術の話を展開していく予定です。 今回はなんと、Ltech初のリモート開催です! インターネット万歳!! 不動産領域のAI活用最前線 記念すべき初リモート開催となる今回のテーマは、『不動産領域のAI活用最前線』です。LIFULLの社長直轄のAI部門であるAI戦略室のみなさんから、ディープな話をしてもらいました。 AI戦略室については、こちらの記事でも触れていますので是非ご覧ください。 www.lifull.blog それでは各発表のレポートです。 ディープラーニングで間取り図を3Dにする 【Ltech#11】ディープラーニングで間取り図を3Dにする from LIFULL Co., Ltd. 最初の発表は、「空飛ぶホームズくん」の裏側で間取り図を3Dにするアルゴリズムについてのお話です。「空飛ぶホームズくん」は、3Dの街を移動しながら気になる部屋の中を見ることができる VR x AI のプロトタイプアプリです。 japan.cnet.com 間取り図をディープラーニングを使ってセマンティック画像に変換し、そこからポリゴンデータを生成することで3D化していきます。 セマンティックセグメンテーションのタスクで工夫した点として、壁/ドアなどの線と部屋をわけて処理する点があります。また、部屋をグラフ構造で持っていたり、非常に面白い内容でした。 人の作った間取り図ですから、機械学習といえども人による地道な作業が必要なんですね。ドアのない部屋、不動産会社のロゴ入り画像、などなど色々あります… 余談ですが、長時間のアノテーション作業で身体を壊しそうだったけど、筋トレをしていたことで救われた話には感動しました! 住まい探しにおける対話AIの自然言語解析技術 【Ltech#11】住まい探しにおける 対話AIの自然言語解析技術 from LIFULL Co., Ltd. 続いて、自然言語による物件検索・地域検索を目指して開発している自然言語解析器についてのお話です。対話形式で物件を探すため、会話を検索条件に落とし込んでいきます。 形態素解析は行わず、シンプルに先頭から辞書を引いて解析しています。私もLIFULL HOME'Sのフリーワード検索で辞書を整備したことがありますが、画像解析の話と同じようにこちらも地道な作業が必要です。 結果を見てみると、ルールベースでもそれなりの結果が出ているようですね。 Q&Aでは、不動産関係のコーパスがないという話も出ていました。 LIFULL HOME'Sの住まいの窓口というサービスでの対話を使えないかと思いましたが、センシティブな内容が多いので使うのは難しそうだな…と思い直しました。 ガウス過程回帰を用いた広宣費予測と可視化 【Ltech#11】ガウス過程回帰を用いた広宣費予測と可視化 from LIFULL Co., Ltd. 休憩を挟んで次の発表です。 マクロな視点で広宣費を月あたりどれくらいかければ、目標を達成できるのかを可視化するツールを作成したお話です。 今回の発表の中で、私が最も理解できなかった発表となります!難しいぶん詳細に発表して頂けました。ざっくり言うと予算とリターンを軸にした関数を知りたい、ということです。 時系列予測のタスクを解くため、ガウス過程を使った回帰モデルを使っています。 ドメイン知識を入れ込みやすい 予測が分布で得られるので不確実性がわかる 過学習しない と、いった特徴があるようです。 私はチンプンカンプンだったのですが、発表後のQ&Aでは参加者の方からたくさんの質問があがっており、アンケートの結果などからも満足頂けたようで良かったです。 Kubernetesを利用した機械学習モデルの本番適用例 【Ltech#11】Kubernetesを利用した機械学習モデルの本番適用例 from LIFULL Co., Ltd. 大トリは、少し趣向を変えてインフラも交えたお話です。 LIFULLではKubernetesチームが開発・運用支援ツール「KEEL」を作ってくれています。そちらを活用しながら、物件の「おすすめ順」生成に機械学習を活用しました。 www.lifull.blog 機械学習のモデルを運用する上で、最初の選択肢としてAWSのSageMakerを利用する方法もありますが、柔軟なAPIを提供するために前述の「KEEL」を利用しました。 物件の検索結果を「おすすめ順」でソートするために、事前推論でスコアを検索エンジンに取り込んでおきます。 検索エンジンへのデータ投入処理がこちらのAPIに依存している以上、大量のデータが投入された時の安定性が課題でしょうか。現在は、APIのスケールしきい値は小さめに、CPIリミットは大きめにすることで、負荷のバラつきにうまく対応しています。 アフタートーク 最後に、登壇者全員でざっくばらんにアフタートークをしました! コロナ禍が予測に与えた影響のような時事的な話題や、AI戦略室を有効活用してもらうために事業部側とどのように付き合っていくのか、など組織的な課題も聞けました。 専門的な領域であるほど、その活用は難しくなっていきます。 「AIコンサルタント」という職種を用意することで、ビジネスとの橋渡し役を置くアイデアは、今後AIの民主化を進め事業を加速してくれるだろう、と感じました。 最後に Ltech では、LIFULLエンジニアが中心となって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。 今後もLtechを積極的に開催していきますので、 ぜひ気になった方は、connpassでLIFULLのメンバー登録をよろしくお願いします! lifull.connpass.com
こんにちは! LIFULLのSETエンジニアの Ruey です! 今年の3月にISTQBの自動化エンジニア資格 CTAL-TAE (Advanced Level Test Automation Engineer)を取得しました。TAEの勉強で自動テストの効果を測るメトリクスが幾つかあることが分かりました。その中で工数を測るメトリクスをEMTE(Equivalent Manual Test Effort)単位で表現することが推奨されています。しかし、その時は説明を見てもこれに換算すれば何か嬉しいか分かりませんでした。 ちょうどある開発グループで自動テストを導入する案件がありましたので、実際のプロジェクトでメトリクスを計測し検証してみました。様々な知見が得られたので、今回はこの単位の紹介と使用例を紹介したいと思います。 目次 はじめに 自動テストのメトリクス EMTEとは EMTEを使って表すことができるメトリクス 支援案件 概要 自動テストの導入目的 テスト作業の効率化と工数の削減 テスト作業におけるヒューマンエラーの排除 品質の維持 支援方法と内容 結果検証と分析 EMTEに換算する 実行時間を換算する メトリクスを換算する EMTE使う際の注意点 工数と節約の費用対効果 最後に はじめに SETチームはLIFULLにある他の開発チームの自動テスト導入支援を行っています。 支援メニューは以下のとおりです: テストフレームワークの使い方紹介 テストケース作成のサポート 自動テスト環境構築のサポート 自動テスト実装のサポート CI/CD構築のサポート 自動テスト運用支援 自動化関するその他の疑問の相談 今回は依頼案件で構築した自動テストを使って、メトリクスを実際に測定して検証してみたいと思います。 自動テストのメトリクス ISTQB CTAL-TAEの シラバス では、自動テストのモニタリング、効率、効果を測るためのメトリクスとして以下が紹介されています。(細かい説明はシラバスを参照してください) External TAS metrics Automation benefits Effort to build automated tests  ⬅︎ 今回使うメトリクス Effort to analyze automated test incidents  ⬅︎ 今回使うメトリクス Effort to maintain automated tests  ⬅︎ 今回使うメトリクス Ratio of failures to defects Time to execute automated tests Number of automated test cases Number of pass and fail results Number of false-fail and false-pass results Code coverage Internal TAS metrics Tool scripting metrics Automation code defect density Speed and efficiency of TAS components 補足 : TAS(Test Automation Solution)は本文で「自動テスト」を表現しています。 数は多いので、今回は特定のメトリクスのみ取ってみます。 EMTEとは EMTEはEquivalent Manual Test Effortの略で、 いわゆる自動テスト全ケースを全て手動で行う場合の工数です。工数を測るメトリクスの単位として推奨されています。 EMTEは時間の単位として扱います。 例: 自動テスト実行時間→30分 全ケースを手動で行った場合→180分 であったとすると、 180分が1EMTE になります。 自動テスト実行時間をEMTEで表すと 0.16 EMTE になります。 EMTEを使って表すことができるメトリクス EMTEは工数関連のメトリクスに使われており、下記の三つになります 自動テストの構築工数 (Effort to build automated tests): 自動テスト実行する環境構築、テストケース設計、テストケース実装などの 初期コスト 。 自動テストの結果分析工数 (Effort to analyze automated test incidents): 自動テスト実行後の結果確認。Flakyのテストの再実行やデグレーションが発生しているとかの確認と分析などの 運用コスト 。 自動テストのメンテナンス工数 (Effort to maintain automated tests): 自動テストのテストケースの修正やテストデータの整備などの 運用コスト 。 これから支援案件で構築した自動テストについてこの三つのメトリクスを計測して、検証と分析したいと思います。 支援案件 概要 まだ自動テストがないTチームに自動システムテストフレームワークBuckyを使ったE2Eテストシステムの構築を提案し、テストケースの選定戦略やテストケースの作成などの支援、またはメンバーにE2Eテストの知識やメンテナンスの方法を教えていきます。最終目標はSETチームの支援なしで自動システムテストが運用・保守される状態を目指します。 自動テストの導入目的 テスト作業の効率化と工数の削減 テストを自動実行できれば手動で行っていたテスト工数を大幅削減できる。複雑なシナリオや準備に時間がかかってしまうテストも何度でも繰り返して実行することができます。 テスト作業におけるヒューマンエラーの排除 テスト作業の漏れや見落としを防ぎます。 品質の維持 障害になるとビジネスに多大な影響を及ぼす機能について継続的に自動回帰テストを実行することでソフトウェア(サイト)の品質を維持させます。 リリース前にデグレを発見することで、素早く、絶えずソフトウェア(サイト)を改善を行えます。 支援方法と内容 週定例を開催: ・定期的に相談できる窓口を作る ・構築状況の共有 ・自動テスト知識の教育 ・ペアプロでテストケース作成と実装 システム構築: ・自動システムテストフレームワークBuckyの実行環境構築 ・構成や実行方法などを教える ・CIとの連携設定 結果検証と分析 支援内容が無事に完了し、テストケースが自動で実行されています。 リリースフローにも自動システムテスト結果の確認する工程を組み込むことで必ずチェックされる仕組みになりました。 実行時間について: 自動テスト実行時間は 531s 全ケースを手動で行う時間は 5650s ( 1 EMTE = 5650s ) EMTEを使って表すことができるメトリクス を使って分析します: メトリクス 時間 自動テストの構築工数 349200s 自動テストの結果分析工数 1800s 自動テストのメンテナンス工数 1800s 工数は時間を出しましたが、時間のみだと実際の効果が分かり辛い状態でした。 EMTEに換算する 1 EMTE = 5650s 実行時間を換算する 自動テスト実行時間は 0.094 EMTE 計算式【 531 ÷ 5650 ≒ 0.094 】 全ケースを手動で行う時間はもちろん 1 EMTE EMTEに変換したら、手動で実行する時の工数と相対的に比較できます。すぐに分かったことは二つあります。 自動テスト実行時間は0.094 EMTE、手動テストの0.094倍の時間となりかなり効果がある 一回の自動テスト実行は手動より0.906 EMTEの時間が節約ができる。 計算式【 1- 0.094 = 0.906 】 節約された時間を他の開発やテストに充てられるので、自動テスト還元効果になります。 メトリクスを換算する メトリクス 計算式 EMTE 自動テストの構築工数 349200s (構築工数) ÷ 5650s (1EMTE) 61.81 自動テストの結果分析工数 1800s (結果分析工数) ÷ 5650s (1EMTE) 0.32 自動テストのメンテナンス工数 1800s (メンテナンス工数) ÷ 5650s (1EMTE) 0.32 メトリクスから分かったことは、初期コストの自動テストの構築工数は一見自動テストを全て手動で行う場合の61倍大きい数字ですが、これは節約された時間で割ると 68回 の自動テストが運用されれば、構築工数が還元されることが分かります。毎日実行で考えたら、二ヶ月くらいの運用でプラス効果になると思います。 計算式: 【 自動テストの構築工数 ÷ 一度の自動テスト実行で節約できる工数 = 何回の自動テストで還元できるか 】 【 61.81 ÷ 0.906 ≒ 68.22 】 さらに運用コストも考慮した場合、自動テストの結果分析工数と自動テストのメンテナンス工数が毎回発生するとは限りませんが、仮に毎回両方発生しても節約時間を超えていないので、自動テストはマイナス効果が出ないと思います。 判定式: 【 一度の自動テスト実行で節約できる工数は結果分析工数とメンテナンス工数の和より大きいのか 】 【 0.906 > (0.32 + 0.32) → True 】 EMTE使う際の注意点 自動テストは実行すればするほど節約された時間として還元されますが、通常の運用以外の実行では還元されません。 例えば開発フローにおいて1リリースに対して1回自動テストを実行する運用(通常の運用)なら、この1回の実行が節約された時間として還元ができます。それ以外の再実行などは最初のテスト結果と同じなので、テスト自体の効果はなく節約された時間として還元できません。 参考記事: Automation benefit measured by EMTE - good or bad? 工数と節約の費用対効果 先の節約時間と還元を図にすると、費用対効果がより分かりやすく表示できます。 (仮で毎回発生)運用コスト + 初期コスト と 削減工数 初期コストと運用コストを計算すると自動テストが233回運用されれば、工数が還元されます 初期コスト と 削減工数 初期コストのみ計算すると自動テストが68回運用されれば、工数が還元されます 最後に EMTEを実際に使ってみたら、自動テストの効果が分かりやすく伝えられることがわかりました。 自動テストはよく初期導入コスト、学習コスト、運用コスト、メンテナスコストが高いから導入しないことが多いですが、どのくらい高いのかはあまり具体に表現できないケースが多いです。それは普段の工数は時間で表現していますので、長いか短いのかが分からないためです。EMTEで換算すれば手動で実行する場合と相対的に比較できるので、実際に自動テストは消費した工数より、プラス効果になるのかがすぐ分かります。 もしくは何回分の実行で初期コストの還元の目標を立てて、自動テストの実行時間を逆算し、導入したい自動テストが目標時間に満たせるかの判断材料としても使えるかなと思います。 みなさんも是非EMTEをご活用していただければと思います。
こんにちは! LIFULLのエンジニアの孫です。 メールやLINEを利用した開発作業をメインにしています。 今回は自分が担当していた物件更新情報LINE受け取り機能の仕組みについて紹介したいと思います。 物件更新情報LINE受け取り機能とは LIFULL HOME'Sに掲載されている新築マンションでユーザが希望した物件の情報が更新された際にLINEに通知がくる機能です。 ▼物件更新情報LINE受け取り機能紹介ページ https://www.homes.co.jp/smp/mansion/shinchiku/line/update-message/about/ ユーザが求めている情報をより早くより近くに届けるための施策となります。 この施策を進める中で一番気を付けていたLINEから受け取る個人情報の扱いがキーになっていたので その個人情報の扱いを中心にどういう仕組みで開発していたのか記載していきます。 処理概要 機能紹介ページに記載されているステップの裏側で動いている処理を簡単に記載しますと以下の流れになります。 全体の構成図 ※LINE User IDとは 各LINEチャネルでユーザを識別するための識別子。 構成的にLINEユーザ情報を各システム間で連携する必要だったため 機密チームと綿密に相談しながら考えた上、上記のような構成になりました。 詳細は以降述べます。 LINEログイン認証機能の仕組み ▼LINE側の処理については以下を参照ください。 https://developers.line.biz/ja/docs/line-login/integrate-line-login/ AWS KMS、ElasticCached利用について 現状LINE User 情報を連携する方法としてAWS KMS、ElasticCacheを利用しています。 呼び元にPOST APIを用意し直接更新処理を叩くのも可能でしたが、今後の拡張性を考慮すると当機能を呼び元に属しないものにする必要がありました。 なので許容されたIPのみで利用できるGET API用意し、呼び元からはキーにて暗号化されたLINE User 情報を取得・複合化することで独立的で安全に個人情報を連携できる仕組みになったと思います。 Marketing Cloud 配信処理について Marketing Cloudとは Marketing Cloudはセールスフォースが提供するMAツールです。 メールやLINEへの送信自動化や分析する処理を比較的に簡単に作れます。 www.salesforce.com 処理内容 Marketing Cloudではデータを外部からファイルで連携のためにSFTPサイト、SafehouseとGPG暗号化方式などを提供しています。 ※Safehouse とは 認証されたユーザのみがアクセスできるファイル保存場所です。 アクセスユーザはMarketing Cloudとは個別で管理されています。 help.salesforce.com なのでAutomation(Marketing Cloudで言う一連の自動化処理)を作成する際、連携されたGPGファイルをSafehouseへ転送、GPG複合・解凍行うことで個人情報へのアクセスをできるユーザを最大限制限しています。 まとめ 現状この仕組みは「物件更新情報LINE受け取り機能」で使っていますが、他にもLINEを介してユーザへ届けるべき情報があれば活用できるものにしていると思いますので今後、利用される施策が増えていくように頑張りたいです。 また、LIFULLではエンジニアメンバーを募集しております! ご紹介のミッションを担当する求人です。ご興味ある方は是非ご応募ください! https://hrmos.co/pages/lifull/jobs/010-0030 hrmos.co
みなさま、はじめまして。AI戦略室の嶋村です。 我々AI戦略室では、機械学習・深層学習・数理最適化・時系列解析・画像処理・自然言語処理などの技術を活用した様々な研究開発プロジェクトを推進しています。私はそれらのプロジェクトを統括する研究開発マネージャの立場にいます。 今回、LIFULL全社に対して研究開発成果を大々的に公開する『AI成果展示会』を開催しました。その目的や内容、どのような反響を得たのか、皆さまにご紹介します。 AI戦略室とは? はじめに、AI戦略室について簡単に紹介をさせて下さい。 AI戦略室は、2018年に設置された社長直轄のAI部門です。『創造と革進で喜びを届ける』というビジョンを持ち、LIFULLが持つ様々なビッグデータにAI技術を活用し、新体験につながるサービスを創出することを目指しています。将来的な競合他社との差別化を見据えた『AI技術シーズの創出』と、短中期的な事業貢献につながる『AI技術シーズの活用』の、2つのミッションを持ち、AI技術をビジネス実装するべく日々研究開発に取り組んでいます。 組織の設置から早2年が経とうとしており、最初は少人数で始まった組織も、会社とともに成長を続けています。最近では、日本語がネイティブ並みにペラペラな多国籍のメンバも在籍しています。メンバそれぞれの個性や強みを最大限に活かせるように、以下の3つの役割を設定しています。これらの役割同士で円滑に連携することで、研究開発を加速させています。 AIコンサルタント ビジネス課題を抽出して、チーム内で連携することにより、ビジネス課題の解決まで推進する役割 データサイエンスエンジニア ビジネス課題から技術課題を抽出して、課題解決のための技術を開発し、効果検証して導入を促進する役割 AIエンジニア ビジネス課題に適した技術を選定し、実サービス上で、実運用に耐えうるシステムを開発する役割 さらに、社外との連携も深めており、同分野で著名な方々とも協業させていただいています。 日立製作所社 フェロー 矢野 和男氏( AI戦略室エグゼクティブフェロー ) シンギュレイト社 Chief Scientific Officer 鹿内 学氏( AI戦略室データサイエンスパートナー ) 人工知能学会 編集委員長 清田 陽司氏(AI戦略室主席研究員) 以上の体制で研究開発に取り組んでいます。最近の研究開発成果を少し紹介すると、例えば『 VRで「したい暮らし」探しを実現するAndroidアプリ「空飛ぶホームズくん」プロトタイプを不動産テックEXPO(大阪)で公開 』への貢献があります。こちらは深層学習を活用し、間取り図画像から3D表示用ベクトルデータの自動生成システム部分を我々AI戦略室が実装しました。 AI成果展示会 さて、本題である、AI成果展示会に話を移します。 まず、AI成果展示会の目的に触れます。一般論になりますが、研究開発組織はコストセンターになりがちで、事業部と距離が遠いことも珍しくはありません。もしそのように認識され続けると、いずれ組織が解体される恐れもあり、それは会社全体の弱体化につながります。そのため、研究開発組織が近視眼的に売上や利益ばかりを見る必要はないものの、会社全体に対してどのような貢献をする組織なのか、自身でしっかりと認知し、その成果が会社の貢献につながると認知してもらう必要があると考えています。 そこで、AI戦略室の活動や成果を認知してもらい、組織のプレゼンスを向上させ、社内で円滑に連携できる関係性を作り新たなサービスの共創につなげるために、AI成果展示会という形で社内に発信する場を設けました。AI成果展示会の開催後に成功したイメージを明確にするため、以下のスローガンを設定しました。 活動の意義を認めてもらう(全社員に) 投資したいと思ってもらう(経営層に) 活用したいと思ってもらう(実サービスで) この展示会の運営チームは、新卒を含む若手中心で形成しました。それは、新卒のメンバはまだ配属されて数ヶ月ですが、「運営チームの活動を通じて組織全体の活動が俯瞰して見えること」「先輩社員とのコミュニケーションが活発になり組織強化につながること」「重要な役割を持ってもらうことで貴重な経験を積み今後の推進も期待できること」などの面で成長してもらいたいと考えました。こちらの運営チームの奮闘により、部署内のメンバが一丸となって進められたと思います。 今回は「目玉企画となる招待講演」と「各メンバのプロジェクトのセッション」を行い、合計19件の発表を行いました。 目玉企画となる招待講演は、データサイエンスパートナである鹿内さんに『AIって何?研究開発って何?』というテーマで話していただきました。AI技術の最近の動向や、AIが何をしているのか、AIの基本的な用語について説明があり、社内での理解が深まったのではないかと思います。さらに、研究開発の難しさや特徴、研究開発組織との連携方法や信頼関係構築の重要性など、ピープルアナリティクスの専門家としての意見も大変参考になりました。 『AIって何?研究開発って何?』 データサイエンスパートナ鹿内学 招待講演に続いて、パネルディスカッションを開き、『研究開発と技術開発の共通点は?違いは?〜シナジーを生み出すために』のテーマついて座談会がありました。研究開発と技術開発の共通点や相違点について意見が交わされ、研究開発組織であるAI戦略室が他部署からどう見えるのか等、我々にとっても興味深い座談になりました。 『研究開発と技術開発の共通点は?違いは?〜シナジーを生み出すために』 データサイエンスパートナ鹿内学  ×  CTO長沢翼  ×  ジンジニア木村修平 「各メンバのプロジェクトのセッション」の一例として、LIFULL HOME'Sでの物件レコメンドに関する発表を紹介します。この発表は、不動産情報サイトであるLIFULL HOME'Sにおいて、よりユーザに魅力的な物件を提案するためのレコメンドアルゴリズムを開発した取り組みです。発表者はデータサイエンスエンジニアとして仮説検証しながら、率先してシステム開発もした良いプロジェクトですので紹介しました。下図に示すように、機械学習モデルをプロダクトで活用する際の流れが示され、モデル開発・システム開発・実証実験(A/Bテスト)のそれぞれの段階での工夫について発表がされました。図の通り、現在はA/Bテストを繰り返してより良いレコメンドアルゴリズムを開発しており、本運用で稼働できるように日々仮説検証を進めています。 これらの発表の一部は弊社エンジニア向けイベントである Ltech でも10月後半に発表予定ですので、ぜひご参加いただければ嬉しいです。以下の発表が行われます。 深層学習を用いた間取り図画像の解析 広告宣伝費最適化 機械学習を活用したレコメンド 自然言語処理による対話文章解析 これまで写真でご紹介した通り、Zoomを活用してオンラインで開催しました。前回は半蔵門本社でポスターセッションを行い、リアルなフィードバックを得ることができたのですが、今は新型コロナウイルスの影響下のため開催方法には悩みました。弊社では9月30日は期末の多忙な時期なのですが、しっかりと我々の成果がお伝えできたのではないかと思います。また、もっと他部署の社員が気軽に参加でき、有意義な意見交換ができるようにする必要性も感じたため、次回はより良いやり方を模索していきたいと思います。 おわりに 以上がAI戦略室によるAI成果展示会の開催レポートです。いくつか課題は見つかったものの、AI戦略室が一丸となり、期の締めくくりとして盛大にAI成果展示会を開催できて嬉しいです。10月からの新たな期もどんどん研究成果を出していきたいと思います。 今後は社内だけでなく、社外での発信も増やしていきたいと考えています。その際は是非みなさまにもAI戦略室からの発信を届けられればと思います! また、LIFULLではメンバーを募集しております。AI戦略室でAIエンジニアも募集予定です! カジュアル面談もありますのでご興味ある方は是非ご参加ください! hrmos.co
こんにちは!クリエイターの日運営委員の松岡です。 みなさんは「スマートホーム」という言葉をご存知でしょうか? 例えば「家に近づくとエアコンが自動的に起動する」「音声でテレビを操作できる」など、スマートホームとは、様々なデバイスをインターネットに繋ぐことで便利な生活ができる家のことを指します。 LIFULLではコロナの影響もあり在宅ワークが基本の状態になっており、自宅の生活を豊かにする需要が高まっています! そこで「クリエイターの日」のイベントの一環として「おうちハック!」と銘打って最新のテクノロジーを用いたオンラインハッカソンを開催しました! ※クリエイターの日とは? 希望者が、3ヶ月ごとに最大7営業日を使って、好きなものを開発することができるLIFULLの制度です。 LIFULLでは、マーケティング能力や技術開発能力を高めてイノベーションを創造するため、通常業務の枠を離れて、新たな技術や手法に取り組む機会となっています。 開催概要 まずハッカソンのテーマは「スマートホーム関連機器を使って自宅での生活をより便利にする仕組みを作る」としました! また期間としては1週間の中の空いている時間で作業・開発をしてもらい、それぞれの自宅でスマートホーム関連機器を用いた仕掛けを作っていただきました。 最終日では実際に仕掛けを動画に撮った上で発表をしていただき、その結果順位を決定し、優勝者には豪華賞品を贈呈する形としました。 発表内容 それでは発表内容を見ていきましょう! 1.シェアハウスのリビングをキリンに深夜監視させてみた 最初の発表は、こちらのMESH、IFTTT、Nature Remoを使ったアイデアです。 シェアハウスに暮らしていると、誰かが消してくれるだろうと思ってつい電気を消し忘れてしまう。 そんなシェアハウスの課題解決のため、このアイデアが生まれたとのことです。 まず、 MESHで人がリビングにいなくなったこと、及び部屋の明かりが付いていることを検知 します。 次に IFTTT経由で、Nature Remoが照明を消し、LINEがグループに通知を送る という仕組みです。 電気代を節約できたという実績もあり、シェアハウスでなくても活用が可能そうな素晴らしいアイデアだと思います。 ちなみに今回は実験的にMESHを使いましたが、Nature Remoにも人感センサーがあるため、MESHを使わなくても実装は可能です。 2.よく行方不明になるプテラノドンをすぐに見つけられるようにした 続いての発表は、tileとGoogle Homeを使ったアイデアです。 娘さんが大事にしている人形「プテラちゃん」をなくなった時に、手軽に見つけられるようにするアイデアです。 アプリで操作すると音を鳴らせるタグ、 tileをGoogle Homeに連携 させ、「プテラちゃんを鳴らして」と言うと プテラちゃんに付いたtileが鳴る という仕組みです。 tileだけでも便利ではありますが、幼児だけで扱える音声デバイスとあえて連携させたアイデアです。 仕事や家事で忙しい時、手軽に使えるのが魅力的です。 3.私が求めていたのは話し相手でした 3つ目の発表は、在宅だとどうしても座りっぱなしになってしまうため、運動不足を解消したい!というアイデアです。 デモではIoTデバイスの Nature Remoを利用 し、自身の動きを計測することで 座りっぱなしを検知 しておりました。 「立派なお腹ですね。ダラダラ働いていないで外でも走ってきてはいかがですか。」と Google Homeに話しかけられる ことで運動を促す仕組みのようです。 製作者は「運動不足解消を目指していたけど、Google Homeに話しかけられて嬉しかった」とのことで、在宅によって本当に不足していたのは話し相手だったというのはとても共感できる部分です。 AWS LambdaでNature Remoからデータを取得し、アラームでSlackやGoogle Homeに通知するなど、裏側の部分もしっかり作り込まれた作品でした。 4.1分でできる!簡単IoTで防犯対策 最後の発表者は、meshを使うことで誰もが気軽に防犯対策ができるアイデアを考えてきてくれました。 実は空き巣の被害は鍵を閉めていなかったことが原因である割合が最も高いとのことです。 MESHのMoveで 動き傾きなどが検知することができるため、ドアのサムターン(鍵の部分)に貼り付けて 鍵の開閉を検知 します。 設置が終わったらMESHのアプリをダウンロードして、デバイスの傾きとメール通知をアプリ上で簡単に紐づけることができるようです。 アプリ連携からメール通知 まで1分で完了したとのことで、とても手軽に利用できることがわかります。 問題提起から誰でもできることで予防策を提示するところまでしっかり考えられたアイデアでした。 結果発表 優勝は「 私が求めていたのは話し相手でした 」となりました。 在宅での運動不足という課題を解決するだけでなく、Nature Remoから取得したデータをAWSのCloudWatchやLambdaと連携したりするなど技術的にもいろいろ実装されていたのが高く評価されました。 まとめ 今回はハッカソンという形でしたが、エンジニアだけでなく企画の社員にも参加していただけました。また、成果物の発表会にはたくさんの方が参加してくださいました。 最近は、MESHなどをはじめコードを書かなくても簡単なプロダクトが作れてしまったりするので、これを機に興味を持った方が次のイベントに参加して少しずつ社内のこのようなイベントも盛り上げていければいいなと思いました。 開催日:2020年9月18日 弊社では、一緒に働くメンバーも募集しています。 recruit.lifull.com
プロダクトエンジニアリング部のカマトです。 普段はマーケティング・エンジニアとして、LIFULL HOME'SでLINEやメールを活用したサービスの開発に従事しています。 今回は業務でシステムの刷新を行う中で、アーキテクトにクリーンアーキテクチャを採用し初めて経験しましたのでこちらについてお話しをさせていただきます。 新しいアーキテクトに触れるときは、このレイヤーは何を担当しどのような概念でどのような機能を持たせればいいのか?と理解するをするまでいつも苦戦するのですが、クリーンアーキテクチャは特に登場人物が多く今まで以上に大変でした。 このクリーンアーキテクチャの処理の流れを日常のものに置き換えれば、別な視点で理解が深まるのではと考え、各レイヤーの概念を定食屋のフローに落とし込んで表現をし振り返りをしてみようと思います。 参考にしたイメージ図に沿ってのレイヤーと概念ですので、これにそってなければクリーンアーキテクチャではないということはないです。 クリーンアーキテクチャはこうすればいい!や、このような思想でやってください!というものではないので暖かい目で見ていただけれたら嬉しいです。 さてクリーンアーキテクチャというと、この図がよく出てくると思います。 出典:The Clean Code Blog https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html これともう一つ。 出典:図解クリーンアーキテクチャ https://qiita.com/kz_12/items/bc79102247b86626fc72 こちらもよく見ますね。 この図の構成を定食屋さんのフローに置き換えて表現したものがこちらになります。 かなり強引なものですが各概念をレイヤー毎に説明をさせていただきます。 Enterprise Business Rules Entities まず、どの定食屋さんでもお客さんに提供するために必要なものは料理のメニューですね。 唐揚げ定食であれば 唐揚げが5個 サラダ ご飯 味噌汁 といった内容です。 Application Business Rules 調理開始 Use Case Interactor  コックさんが厨房に立ちフロアスタッフが伝票置き場(Input Boundary)へ置いてくれた伝票に書かれた注文情報を見て、メニュー内容(Entities)を思い出し料理をします。 料理に必要な食材の指示を出し(Data Access Interface)、材料が集まり料理(Output Data)が完成したら受け取り口に料理を並べ、横に伝票(Output Boundary)を置いておきます。 注文情報 Input Data お客さんの注文仕方は様々です。 厨房のコックさんが作業しやすいように注文内容を整理した言葉に変換してます。 からてい 一つ → 唐揚げ定食 1人前 伝票置き場 Input Boundary フロアスタッフの人は厨房に入りませんので、整理した言葉(Input Data)で作った伝票をコックさんがメニューを出してくれるところに置いておきます。 必要材料の指示 Data Access Interface コックさんが倉庫・冷蔵庫(Data Access)から用意して欲しい食材を指示します。 受け取り口 Output Data コックさんの元に材料を届けると材料が揃ったので料理を開始します。 ここで完成した料理を受け取り口に料理を並べます。 伝票置き場 Output Boundary ここでフロアスタッフがどの注文に対しての料理なのかをわかるように、料理の横に伝票を置いておきます。 Interface Adapters テーブル(注文をうける) Controller 次にどこのお店でもお客さんがする行動である注文です。 フロアスタッフがお客さんから注文を受け取ります。 ここでうけた注文は伝票を使い(Input Data)、作ってもらいたいメニューを調理場へ伝えます。(Input Boundary) 提供準備 Presenter 厨房から出された料理を受け取り口で受け取り(Output Data)、提供するテーブルを伝票で確認したら(Output Boundary)お客さんが気持ちよく食べられるよう、お盆に食器、箸やスプーン、フォーク味噌汁なども揃えてテーブルへ運びます。 テーブルViewModel お客さん(View)がいるテーブルへ料理を提供します。 倉庫係 Data Access コックさんからの依頼通り(Data Access Interface)に、様々な業者に発注していた食材がある(倉庫・冷蔵庫)から調理に必要な食材を取り出して送ります。 倉庫・冷蔵庫 Data Base 倉庫や冷蔵庫には様々な業者に発注した食材や調味料が並んでいます。 倉庫係さん(Data Access)が必要なものを発注をしたり、取り出したりします。 お客さん View 注文された料理が来たらお客さんは食事を開始します。 依存関係について クリーンアーキテクチャで重要になると思われる依存関係(上位のモジュールは下位のモジュールに依存してはならない。)ですが、以下のように表現しています。 メニュー内容(Entities)が唐揚げ5個から3個になったらコックさんの振る舞いも変わり、倉庫係の方が倉庫や冷蔵庫から用意する材料も変わります。 コックさんが別な人に変わったら、レシピも変わるので、倉庫や冷蔵庫から出す材料は変わるかもしれません。ですが毎日出しているメニュー内容に変わりはありません。 そして倉庫や冷蔵庫が変わったとしても必要になる材料は変わらないので、コックさんの指示に影響は出ないはずです。 依存関係逆転の原則 もう一つクリーンアーキテクチャで大事な依存関係逆転の原則ですが、こちらは振る舞いを下位モジュールへの作業の依頼(伝票や用意してもらう食材の指示)という形で表現してみました。 これによりフロアスタッフの方や、倉庫係の人に依存せずコックさんは作業を続ける事ができます。 (一応ここでの表現の中での話ですが、上位モジュールが立場が上というわけではありません。) まとめ どうでしょうか?かなり強引でしたので、間違っている表現もあると思いますが、思ったよりいい感じなのではと・・・。 ちなみに自分は学生の頃にファミレスでアルバイトをした経験があるくらいしか料理の経験はありません。 難しい言葉で半分くらい理解して進めるといざという時にどうだったかな?と手が止まってしまいますが、こういった自分が普段使っている言葉に変えて整理してみるとすんなり入ってきませんか? クリーンアーキテクチャに限らず普段の業務などで、ここはこういう表現の方がいい、こうした方がわかりやすいというものを考える機会にしていただけたら嬉しいです。
こんにちは、LIFULLでLINEやメール周りを担当しているエンジニア三宅です。 LIFULL HOME'Sでは、これまでエンドユーザとのコミュニケーションは次のとおりでした。 オフライン:店舗(LIFULL HOME'S 住まいの窓口)、電話 オンライン:Web、メール、チャット しかし、エンドユーザの利用率や利便性を考え、2019年からLINEを使ったコミュニケーションサービスの配信を開始しました。 現在ではLINEで物件相談が出来たり、一人一人の住み替えステップに応じたメッセージ配信をおこない、ユーザのアクションによって適切な情報を配信するサービスを提供するなど、よりオンラインでのコミュニケーションが強化されています。 今回はLIFULLで提供しているLINE活用の取り組みの中から「住み替えサポート」を紹介したいと思います。 住み替えサポートとは? 住み替えステップに合わせた便利機能で、住まい探しから引越しの準備までをLINEでサポートする機能です。 住み替えに役立つ情報やお得なキャンペーン情報もお届けします。 以下詳細です。 物件レコメンドメッセージ LIFULL HOME'Sで問合せをした物件と似た物件をメッセージでお届けします。 住み替えステップに応じたメッセージ 住み替えステップ(物件見学予定、物件見学済み、物件契約済み、転居完了)に応じたメッセージをお届けします。 以下は見学予定の方メッセージです。 賃貸で反響を行うと、自動で画面下部のリッチメニュー が「住み替えサポート」専用のものに変更されます。 以下は見学完了の方のメッセージです。 以下は契約完了の方のメッセージです。 リマインド機能 物件見学日を登録しておくと、前日にリマインドメッセージをお届けします。 お役立ち情報配信 物件見学必要な持ち物チェックリストや引っ越し後の手続きなど住み替え完了までに必要な情報をお届けします。 以下は「引っ越し一括手続きサービス」のお知らせです。 注)上記の画像は2020年10月現在のサービス画像の為、変更の可能性があります どんな風に動いてる? 「住み替えサポート」がどのようにして動いているか少し説明させてください。 住み替えサポートの処理概要は以下となっています。 ①サンクスメッセージ LIFULL HOME'Sで物件問合せをしてくださった方にLINEでメッセージを配信します。 ②ユーザのアクション(友達になった、メッセージのボタンをクリックしたなど)があるとLINE社を通じてwebhook APIへ通知される 「LIFULL HOME'S公式アカウントに友達になった」、「弊社から配信されたメッセージ内のボタンをクリックした」などのアクションがあった場合、LINE社を通じて、webhook APIに通知されます。 ③webhook APIからアクションに応じた処理を行う。 ユーザのアクションによって処理を分けるのですが、大まかには以下の3つになります。 アクションをデータベースに格納する 即時メッセージ配信用のAPIにリクエスト リッチメニュー(*1)の切り替え ④条件に合致したユーザに対してLINEメッセージを配信する メッセージ配信は大きく分けて2つあります。 弊社では即時メッセージ配信は独自APIを使っており、定期メッセージ配信はMarketing Cloud(*2)というツールを使っています。 即時メッセージ配信(ボタンタップ時に即時メッセージ配信) 定期メッセージ配信(ユーザの状況に応じた定期メッセージ配信) LINE株式会社が提供しているMessaging APIを用いて開発を行っています。 次のドキュメントを参考にすれば、さほど開発は難しくありません。 developers.line.biz 「住み替えサポート」は、最適なタイミングで、ユーザが必要とするコンテンツが配信される事に価値がある機能です。 そのため、ユーザのアクション単位で処理を行うことで、セグメントごとに配信するメッセージを切り分けています。 *1 リッチメニュー とは LINE公式アカウントのトークを訪れた際、画面下部に大きく開くメニューです。 「 リッチメニュー|LINE for Business 」より引用 *2 Marketing Cloudとは www.salesforce.com 開発時の小話 上記の処理概要部分でも記載しましたが、メッセージの配信は、LINEの「Messaging API」を利用しています。 「Messaging API」は、JSONでUI・UXを表現しますが、その仕様上、HTML+CSSのように細かいデザインの調整を行うことができません。 できない例 空白行の縦幅の微調整 画像サイズの微調整 文字サイズの微調整 そのため、デザイナーと相談しながら、できる範囲で最適な物をチョイスしながら進めました。 非常に見やすくなっていると思うので、是非見てみて下さい! LINE活用のその他事例紹介 今回は細かくは記載しませんが、その他にも様々な施策があります。 軽く紹介させてください。 サンクスメッセージ 処理概要のところで少し触れましたが、LIFULL HOME'Sで物件問合せをしてくださった方に送るメッセージです。 LINE株式会社が提供する「通知メッセージ」というサービスを使っており、LINEに登録されているユーザの電話番号と、LIFULL HOME'Sで物件問合せをする際に入力されたユーザの電話番号とを照合させることで、友だち登録していないユーザーに対してもメッセージを送ることができます。 LINEで問合せた物件が確認できるのでLINEをよく使う方には便利な機能となっています。 AIおウチ診断 検索条件を決めることなく理想の物件をAIが学習・提案してくれる機能です。 質問に答えていくだけで理想の住まいが楽しく検索できる機能となっています。こちらの診断を元により理想の住まいへのイメージを膨らませていただければ幸いです。 物件更新情報LINE受け取り機能 現状は新築分譲マンション領域において、情報の更新があったらLINEで通知してくれる機能です。 新築分譲マンションは完成までに時間がかかるので、未完成の状態でLIFULL HOME'Sのような物件検索サイトに掲載されます。 随時情報が更新されるのですが、物件の情報に更新が入るとLINEで通知してくれるので非常に便利な機能です。 どれも便利・面白い機能ですので、是非使ってみてください! 最後に 今では公式アカウントの友達数は180万人を超えています。 もっと一人一人に沿ったタイミングで、最適なコンテンツを届けられるように「ユーザに寄り添ってサポートできる」「もっと痒いところに手が届く」サービスにしていきたいと思います。 今後、新たなLINE活用も進めていく予定ですので、是非「LIFULL HOME'SのLINE公式アカウント」をご活用ください。 LINE公式アカウントは こちら から
技術開発部の相馬です。好きな JS モジュールバンドラーは Rollup です。 表題のとおりですが、今回は Node.js を使って PHP のテンプレートエンジンである Twig のプリプロセッサーを作り、言語機能の拡張をしてみた話についてご紹介したいと思います。 はじめに 弊社のメイン事業である LIFULL HOME'S の開発の歴史は長く、技術的負債と呼ばれるモノも多く存在しています。 これらの問題に対し、現在弊社ではエンジニアが組織として負債の解消に取り組むような体制が整っています。 フロントエンドの開発環境の改善については、以前ご紹介したので次の記事をご覧ください。 www.lifull.blog 今回は、テンプレートエンジンにまつわる改善についてご紹介したいと思います。 LIFULL HOME'S のサーバーサイドは PHP(Symfony)で構築されており、テンプレートエンジンには Twig を採用しています。 Twig には構文拡張の機構が備わっており、対応するトークンパーサーやノードなどを PHP のコードとして記述し、エクステンションとして登録することで独自のタグを解釈させることなどが可能です。 twig.symfony.com しかし、当然のことながらこれらは Twig コードが PHP を生成するタイミングでのコンパイル時にしか干渉できず、ツールとしての再利用性はほとんど存在しません。 そこで、時代は AST(Abstract syntax tree)ということで「Node.js で Twig の parser/traverser/codegen を作ってしまおう!」という決断をしました。 Twig の三種の神器(parser/traverser/codegen)作成に関する詳細は、次の記事をご覧ください。 www.lifull.blog 作成言語に Node.js を採用した理由については、 以前 Node.js 環境を整えたのでそのまま利用できたこと 開発陣が JavaScript の取り扱いに長けていた のが主な要因でした。 神器が整えば、あとは lint なり format なり好きにし放題ということで、手始めに言語のプリプロセッサーを作ってみることにしました。 なぜプリプロセッサーを作るのか? Twig のバージョンを上げず に、擬似的に上位バージョンの API やメインストリームには存在しない API などを実装することができるからです。 一般的に、言語のメジャーバージョンアップなどビッグチェンジを含むようなインフラ寄りの改修にはテストを含め多くの工数がかかると思います。 これは弊社の Twig にも当てはまることで、歴史的な理由でアップデートが非常に困難(年単位での改修コストがかかる)な状態にあります。 そのため、開発者は数年前の機能(開発効率)のまま、現在も開発せざるを得ないという状況です。 開発効率の他にも、言語特性による脆弱性など LTS ではないバージョンを使い続けることのデメリットは多く考えられます。 このような状況でも、なんとかして開発効率をよくしたい、実装/レビューコスト削減など DX を高めたいという想いの元で生まれたのがプリプロセッサーを作るという考えでした。 プリプロセッサーを挟むことで実際のランタイムのバージョンでは扱えない構文が存在していても、実際のランタイムで扱えるよう機械的に変換することで、ランタイムへと干渉せずとも擬似的に機能拡張を行うことが可能です。 JS における Babel のように、特定のランタイム環境においても実行可能な状態として最新の構文をダウングレードコンパイルするように、Twig のプリプロセッサーにおいても特定の Twig のランタイムバージョンに合わせて出力を変更できるよう設計しました。 作ったプリプロセッサーについて ここからは、作成したプリプロセッサーがどのようなものかについて触れてゆきたいと思います。 初期構想 PJ 初期段階で実装/導入したい内容としては次のようなことを考えていました。 Single File Component 構文拡張 xembed lint plugin ベースの拡張 Single File Component Vue.js や Svelte のようなモノを想像していただければ問題ないと思います。 テンプレートと同一のファイル内に style と script を記述し、影響範囲を狭めてそれぞれのファイル間の物理的距離を縮めるのが狙いです。 CSS に関しては Scoped CSS などで知られているように、テンプレート側と CSS の AST Node をマッチさせることで煩わしい class 命名からの開放なども可能だと考えていました。 構文拡張: xembed Twig には embed という構文が存在していて、これがそれなりに便利で開発サイドからも需要の高い構文でした。 twig.symfony.com しかし、LIFULL HOME'S で導入されている Twig バージョンは embed に未対応のバージョンで利用することはできませんでした。 embed を利用できないため、似たようなテンプレートを作成したい時にテンプレートの複製を強いられてしまい、開発効率にも大きく寄与する構文であったため、これとほぼ同等の機能をプリプロセッサー側で実装することにしました。 <!-- コンパイル元のファイル --> {% xembed 'Bundle::tmp/overlay.base.html.twig' only %} {% block modal %} {% include 'Bundle::tmp/modal.html.twig' only %} {% endblock%} {% endxembed %} <!-- コンパイル後のファイル --> {% include "Bundle::xembed/88e0f115ebf99c3d31d738856b176767d0c229e7.html.twig" only %} <!-- 88e0f115ebf99c3d31d738856b176767d0c229e7.html.twig --> {% extends "Bundle::tmp/overlay.base.html.twig" %} {% block modal %} {% include "Bundle::tmp/modal.html.twig" only %} {% endblock modal %} やっていることは単純で、手動で行うテンプレートの複製をプログラムで透過的に自動で行えるようにしました。 また、仮に Twig のバージョンアップがあった際、本家の embed をそのまま置換可能なように embed の構文と同じインターフェイスをとるようにしました。 lint Twig 開発上で起こしてしまいがちなミスを事前に防ぐことができるよう lint ツールを統合しています。 onSave でファイルのコンパイルと同時に lint を走らせることで、早いタイミングで開発者にフィードバックを与えるのが目的です。 用意した lint の種類としては次の 2 つです。 use only keyword in includeBlock avoid Dynamic include in includeBlock use only keyword in includeBlock Twig には include というキーワードで他のテンプレートを利用することができるのですが、この際に only というキーワードを使って変数スコープを指定することができます。 <!-- 変数スコープを指定しない -> children.html から現在のテンプレート上の全ての変数を参照可能 --> {% include 'children.html' %} <!-- 変数スコープを指定する -> children.html では with によって渡された foo のみが参照可能 --> {% include 'children.html' with {'foo': 'bar'} only %} only をつけていないことで、変数スコープの特定が非常に難しく、修正やリファクタの際に調査コストが大きく膨む要因となってしまいます。 これを、 only をつけていない実装があれば、自動で標準出力へと表示するようにしています。 warning: not exist only keyword in IncludeBlock at: tmp/parent.twig - {% include 'children.html' with {'foo': 'bar'} %} avoid Dynamic include in includeBlock こちらも include に関する内容で、動的なテンプレート名の構築を避けて欲しいという内容のものです。 <!-- このように template 名に変数を指定することが可能です --> {% include params.template.view {"foo": "bar"} only %} パラメータ名に読み込むテンプレート名を入れることで、場合によってはサーバサイドのかなーり深いところまで遡る必要があるため、こちらも調査コストが高くつきやすいです。 また、ファイル検索する際に grep で引っかからず影響調査から漏れてしまう可能性も高いです。 これらの理由から、動的な名前解決は非推奨として次のような出力をするようにしています。 warning: dynamic include was detected in IncludeBlock at: tmp/parent.twig - {% include params.template.view {"foo": "bar"} only %} plugin ベースの拡張 プラグインによって機能拡張がしやすい設計としました。 plugin 設計は Rollup を参考にしました。型ファイルをお見せするとこんな感じです。 export interface IPlugin extends PluginCtx { name: string ; postbuild?: ( metaOrRootAST: SourceMapMeta | any , path: string ) => Promise < void >; postGenerateAll?: () => Promise < void >; } export type LifeCycleValue = 'postbuild' | 'postGenerateAll' ; import type { SourceMapMeta } from '@/core' ; import type { PluginCtx } from '@/plugins/pluginCxt' ; ファイルの build(parse)が終わったタイミングで hook する function を記述し、ソースコードを生成する前に AST へ干渉できるようにしているのでアウトプットされるコードを変更することが可能です。 先ほどの lint の plugin はこんな感じで実装されています。 import { extractWithoutOnlyIncludeNode , generate } from '@/ast/twig' ; import { log } from '@/util/console' ; export default ( { silent } : { silent: boolean } ) : IPlugin => { return { name: 'warnWithoutOnly' , postbuild: async ( ast: any , path: string ) => { if ( silent || ast === null ) { return; } const res = extractWithoutOnlyIncludeNode ( ast ); if ( !res?. length ) { return; } log ( `warning:` , `not exist only keyword in IncludeBlock \n at: ${path}` , 'yellowBright' ); res.forEach (( node ) => { log ( ` -` , `${generate(node)}` , 'yellowBright' ); } ); } , } ; } ; // types import type { IPlugin } from '@/plugins' ; (AST 側が TS で実装されていないので、Node の型情報がないので現状は any で濁しています) ボツ案 初期構想から実際にリリースするまでに削られた機能たちとその背景について触れてゆきたいと思います。 Single File Component Style や Script を DOM 側と連携/制御させることが難しかったので諦めることにしました。 JSX などは HTML タグを JS オブジェクトとして扱うことができる一方、Twig では Twig の構文上 HTML タグをそれぞれ AST Node として扱うことは難しいです(unnkown な filter などが HTML タグの中に混在する可能性があり、構文解釈が難しい) よって、Twig の Parser では HTML 部分はほとんど Raw string として扱うことしかできず、HTML Node に対してプログラムによる高度な制御ができませんでした。 Twig にはファイルの継承機能も備わっており、継承が発生した際の script の変数/実装スコープ制御もかなり大変そうな(導入しても扱うことがかなり大変そう)ことがわかったので諦めることにしました。 想定していたリスク 「技術的負債を解消するために言語やフレームワークを拡張することで新たな技術的負債を生んでしまわないか」ということは常に考慮していました。 オレオレ実装や秘伝のタレとして負の遺産的に継承されることは避けられるように、後方互換性や前方互換性についても留意して設計/開発を行いました。 戻しやすく捨てやすい、これをモットーに開発できたことが、途中オーバーエンジニアリングで道を踏み外しそうになった時の支えとなりました。 独自言語(?)を作ってみてわかった感想 テンプレートエンジン +α ライクなモノを作ろうとしてみてはじめて分かった知見もいくつか紹介してみたいと思います。 拡張子とハイライト問題 初期構想時はファイルの拡張子も変えてみようかという話もありました。 その際、Github にプッシュしてコードを見たときにまったくコードハイライトがされていないということが発生しました。 Github 側の実装に当てはまらない拡張子はプレーンテキスト(?)のように扱われてしまうようで、とてもコードレビューできる状態ではありませんでした。 ソフトウェア開発において、Github は大きな役割を担うインフラ的存在になってしまっているため、これを無視することはできませんでした。 (後日知ったのですが、Github にはハイライトを管理するリポジトリが存在しているらしく、ここに PR を送れば独自拡張子などにもハイライトを当てることができるようです github/linguist ) まとめ 実のところ、ほとんどの実装は Twig の Parser 側が占めているので、プリプロセッサー側の処理はほとんどなくかなり薄い実装です。 紆余曲折あり当初の設計からはだいぶ機能を削っての導入になりましたが、今回の PJ を通して普段のアプリケーション開発では味わうことができないよい経験ができたと思います。 レガシーなテンプレートエンジンにもリッチな開発体験を、というキャッチフレーズで今後も邁進して参りたいと思います。
こんにちは! プロダクトエンジニアリング部の吉永です。 LIFULLには2020年8月に入社しました。 今回は入社後、早々に任せていただいた仕事について記事を書きたいと思います。 内容としては、静的サイトをホスティングしている、とあるサービスのAWS構成を刷新し、CI/CDを導入したプロジェクトについて、どんな理由でどんなことに考慮して刷新していったのかについてご紹介していきます。 アジェンダ 刷新対象サイトの旧AWS構成図 AWS構成刷新の背景 新AWS構成について Lambda@Edgeについて インフラのコード化について CI/CDについて まとめ 刷新対象サイトの旧AWS構成図 まずは今回刷新の対象となったサイトの旧AWS構成図を見てください。 静的サイトをホスティングしているだけなのですが、EC2インスタンスがいたり、S3のバケットも複数あったりで実現している機能に対して、構成がやや複雑に見えます。 この構成のポイントを要約すると下記になります。 S3のバケットが二つあり、それぞれPC用ページ、SP用ページのリソース類(html/css/jsなど)が格納されていた。 サイトにアクセスしてきたデバイスに応じて、どちらのS3からコンテンツを返却するかをEC2インスタンス内で稼働しているnginxで振り分けていた。 デバイス判定にはHTTPリクエストヘッダーのユーザーエージェントを使用。 また、上記サイトのローカル開発環境は下記のようになっていました。 サイトのローカル開発環境はRuby on Rails。 サイトの更新を行うエンジニアはローカルで更新後、Railsアプリケーションを起動し、シェルスクリプトを実行して静的コンテンツをローカルに保存、保存した静的コンテンツをS3にデプロイ、その後リポジトリを更新して、リモートへプッシュしていた。 AWS構成刷新の背景 今回、AWS構成を刷新した理由は下記2点です。 Amazon Linux AMI のサポート期間終了に伴う対応が必要だったから。 https://aws.amazon.com/jp/blogs/news/update-on-amazon-linux-ami-end-of-life/ 上記ページにもあるように、EC2インスタンスを更新するなり、何かしらの対応を2020年中に行う必要があった。 また、旧AWS構成を手動で構築したこともあり、テスト環境と本番環境の設定が微妙に異なっているなどが発生していた。 生産性の観点から、ビルドやテストだけでなくリリースプロセス全体を自動化したかったから。 必須ではなかったが、先述したようにローカルで更新したリソースをほぼ手動でデプロイしており、作業担当者がリポジトリのコミット、プッシュを忘れると、リポジトリの内容とデプロイされている静的コンテンツの内容が一致しない可能性があった。 また、ローカル開発環境が作業者PCに直接環境を構築する前提だったこともあり、環境構築手順書のメンテナンスや、引継ぎ時の環境再現コストなどがかかっており、このあたりも改善したかった。 新AWS構成について これらを踏まえ、現在使用できるAWSマネージドサービスから最適かつシンプルな組み合わせを模索して、新構成を設計しました。 AWS構成の大きな変更点は下記になります。 EC2インスタンス内で稼働していたnginxの役割をCloudFront前段で動作するLambda@Edgeに変更。 EC2インスタンスが不要になったので、前段にいたALBも一緒に削除。 S3バケットも一つにまとめ、バケット内に/pc、/spフォルダを設け、それぞれのページリソースを格納。 CloudFrontはS3の内容をそのままキャッシュするように変更。 EC2が構成からなくなったことにより、ランニングコストが事前の試算では従来の1/3くらいにまで削減できそうだということもこの構成にした大きな理由です。 Lambda@Edgeについて Lambda@EdgeはCloudFrontのビューワーリクエストをトリガーにして動作するように設定し、HTTPリクエストに含まれるリクエストパスをユーザーエージェントに応じて書き換えるようになっています。 イメージが湧きやすいように設定したLamda@Edgeソースの一部を下記に記します。 // User-AgentからPC・SP判定を行ないリクエストURIを変換する exports.handler = ( event , context, callback) => { const request = event .Records [ 0 ] .cf.request; const headers = request.headers; if (headers [ 'user-agent' ] ) { var uri = request.uri; // UA判定 if (isSpBrowser(headers [ 'user-agent' ] )) { // スマホ uri = '/sp' + uri; } else { // PC uri = '/pc' + uri; } request.uri = uri; callback( null , request); return ; } callback( null , request); } ; インフラのコード化について 旧AWS構成が手作業で構築した環境だったので、テスト環境と本番環境で微妙に差異がありましたが、今回1からインフラ構成を作ったのでCloudFormationを用いてインフラのコード化を行いました。 コード化したことにより、テスト環境で構築した構成を本番環境で再現するのが容易でしたし、今後何かしらの変更を加える際にもコードベースで管理しておけば、テストと本番で設定が異なるなどの状態には陥りにくいと思います。 ※実際には少しの変更ならAWS管理画面から直接行いたくなりますが・・・それをやってしまうとせっかくコード化した意味がないので、手動設定はなるべく排除しましょう。 CloudFormationについては別途Qiitaにて、この案件を通じて学んだ内容を備忘録代わりに投稿した記事があるので、もし興味があれば参照してみてください。 AWS CloudFormation入門 CI/CDについて 今回改善したかったもう一つの個所がローカルでサイトを更新してから、デプロイするまでの流れでした。 改善点をまとめると下記になります。 ローカル開発環境をDockerで構築し、環境再現コストを削減。 masterブランチにマージされたら、GitHub Actionsでデプロイ実行。 デプロイ作業を自動化したことでヒューマンエラーが混入しなくなり、作業者も安心してリリースできるようになりました。 また、副産物として、GitHub Actionsにてバージョン管理TAGの自動付加も行えるようにしたので、その件についてもQiitaに投稿しました。 もし興味があれば参照してみてください。 GitHub ActionsでX.Y.Z形式のバージョニング自動タグ付けを行う まとめ AWSについては前職では少し触った程度の浅い知識しかなく、入社早々任せていただいた仕事がAWS構成の刷新だったので一抹の不安はありましたが、最終的にはかなり色々なものを吸収させていただき、とても良い経験になりました。 今回の業務を通じて得られたものを下記にまとめました。 AWS構成でどこにどれくらいのコストがかかっているのか?調べる力が身についた。 AWSマネージドサービスは常に進化しており、数年前は実現できなかったことが近年ではシンプルな構成で実現できるようになっていたりするので、ベストプラクティスは常に変化していることを知れた。 インフラのコード化を初めて行ったが、テスト環境で構築した環境を本番環境に簡単に構築できるメリットを実感できた 将来的に似たような構成を作る際に今回作ったCloudFormationが流用できる可能性を感じたので、インフラのコード化は業務効率化や標準化の観点からみても非常に有益な作業であると実感できた。 CI/CDを導入することでリリース作業の負担を減らすことのメリットを実感でき、かつリリース作業を属人化することなく、だれでも簡単な操作でできるようになったので、リリース作業の心理的負担もだいぶ和らいだ。 以上となります。 最後までご覧いただき、ありがとうございました。
はじめ こんにちは、アプリケーションエンジニアとして働いてます。キム ソンジュです。 今回の記事では自分が参加したPJで利用した、インフラ構成から、CI/CD環境を利用して簡単にアプリケーション開発ができる方法について紹介しようと思います。 システム投入・設計背景 既存のレガシーシステムには、次の問題がありました。 デプロイの手順が複雑で時間かかり、面倒な作業が多い 環境ごとにミドルウェアのバージョンが異なる この問題を解決し、かつ新しい技術にチャレンジするために、チーム内で次の内容で進めるようチームで決めました。 Dockerを活用して環境ごとの差をなくす GitHubでソースコードを管理するので、CI/CDにはGitHub Actionsを採用 Dockerを利用することによる、ECRとECSを活用 入る前に 本記事で話したい内容は「このような方法で、こんなに簡単にアプリの開発からデプロイまでできる」といった紹介をするのが目的です。 案内してるAWSの各技術の細かい使い方、テストで使ってるGo言語の深い話については紹介しませんのでその点をご了承ください。 登場人物 AWS IAM AWS ECR AWS ECS AWS ALB(※1) AWS Parameter Store(※2) Github Actions Docker Go ( Go以外のアプリケーションも利用可能です) ※1. ALBはFargateを利用する時の必須技術になります。 ※2. Parameter Storeは、Dockerを起動させる時に環境変数を利用して敏感な情報をアプリで利用するため使います。 ※その他の登場人物については、上記で決めたことを元にして登場しました。 作業結果の予想図 上記の登場人物を利用する場合、下記のような構成が出ます。 作業の流れ Goを利用したアプリ作成 Dockerを利用したContainer環境構築 Local環境起動確認・テスト AWS設定 Github Actions設定 実装テスト こちらの流れで作業を進めて行く予定です。 それでは始めましょう! 1. Goを利用したアプリ作成 go-json-reset のModuleを利用します。 この記事では上記の例文をそのまま利用する予定です。 go module を利用します。 参考コード はこちらです。 2. Dockerを利用したContainer環境構築 goが設定されてるAlphine Linuxを利用します。 TimeZone設定がDefault UTCなので調整します(ログ書くときに時間がずれることを予防します) go moduleの設定と、Install作業を行います。 buildした後、実行させます。 dockerfile ## get alphine + go image ver.1.14 FROM golang:1.14.2-alpine3.11 ## pakcage update & install RUN apk add --update curl git pkgconfig curl-dev ## modified timezone RUN apk add tzdata ENV TZ=Asia/Tokyo ## setup env variables for go module ENV GO111MODULE "on" ## source code copy from host disk WORKDIR /go COPY . /go/src ## module install ## If You didn't set up go.mod in your local workspace, You can not use command go install WORKDIR /go/src RUN go install ## go build RUN go build ./main.go ## container listen port EXPOSE 8080 ## command ## start CMD [ "./main" ] ここまで来たら下記のようなディレクトリ構成になります。 . ├── Dockerfile ├── go.mod // go module 設定ファイルになります。 ├── go.sum // なくても構いません。 └── main.go 3. Local環境起動確認・テスト docker build postman, curl などを利用して、テスト docker build -t lifull_test . docker run -p 8080:8080 qiita_test:latest 自分はPostmanを利用して見ました。 アクセスログが出力されているか見てみましょう?! よし、ここまで来たら準備は完了です。 4. AWS設定 AWSの環境を設定しましょう、ALB,SGの細かい設定についてはこの記事では案内しません、必要最低限の設定で作成します IAM 設定 Github Actionsが利用するDeploy用ユーザーを作成 必要権限は ECR,ECSに関連する権限を付与します。 作成時 AccesToken、Keyを保存しましょう。 FargateのTaskが使うRoleを設定します。 ecsTaskExecutionRole この名がDefaultです。 権限は、ECR,ECSの権限に更に、CloudWatch,Parameter Storeへの利用権限が必要です。 Parameter Store 設定 アプリで利用する各種環境変数周りがあります(Laravelの場合.env周りに設定する環境変数です)こちらをGo+Dockerで利用する場合、環境変数をOSで扱うのが一般的で、こちらを実現するためにAWSでは SystemManager > Parameter Storeに設定します。 key-valueで設定します。暗号化された文字列として保存するのがより安全ですね! Security Group 作成 利用するポートを許可します。 今回の場合は8080をOpenしましょう! ALB 作成 Public Subetを設定します。 Public DNSが使える状態にします。もしくはHTTPS設定を利用して使える場合DNS設定を行います。(ACMなどが登場しますね) ECR 作成 Repositoryを作成します。(Docker-hubのPrivate版的な感じで、AWSでDockerを利用する時よく使います。) ECS 設定 ECSの構成について細かい説明は行いません。下記の設定は注意してください。 task定義が必要です。 まだRepositoryにアップしたイメージがないので適当に書いておいても構いません。   Containerに渡す環境変数の設定が必要です。上記のParameter Storeで設定したパラメーター名を環境変数:パラメーター名構成で作成します。 Container側に必要はPortをOpenする必要もあります。ここでは8080ですね。 clusterを作成します。 serviceを作成します。 5. Github Actions設定 一覧の設定が終わったら、Github Actionsを設定しましょう Github Actionsについては気になる方は以前自分が Qiitaに投稿した記事 がありますので、参考にしてください Trigger push Target Branch master doing docker build task-definition.json を利用したDeploy作業 .github/workflow/main.yml ### main.yml name : test workflow for qiita on : push : # event trigger on push branches : master jobs : build : # job id name : sjkim action # job name runs-on : ubuntu-latest # virtual os steps : - name : set up go 1.14 uses : actions/setup-go@v1 with : go-version : 1.14 - name : Checkout branch go module directory uses : actions/checkout@v2 - name : package install uses : actions/cache@v2 with : path : ~/go/pkg/mod key : ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys : | ${{ runner.os }}-go- - name : Configure AWS credentials uses : aws-actions/configure-aws-credentials@v1 with : aws-access-key-id : ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region : ap-northeast-1 - name : Login to Amazon ECR id : login-ecr uses : aws-actions/amazon-ecr-login@v1 - name : Build, tag, and push image to Amazon ECR id : build-image env : ECR_REGISTRY : ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY : qiita-test IMAGE_TAG : ${{ github.sha }} run : | # Build a docker container and # push it to ECR so that it can # be deployed to ECS. docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" - name : Fill in the new image ID in the Amazon ECS task definition id : task-def uses : aws-actions/amazon-ecs-render-task-definition@v1 with : task-definition : task-definition.json container-name : qiita-container image : ${{ steps.build-image.outputs.image }} - name : Deploy Amazon ECS task definition uses : aws-actions/amazon-ecs-deploy-task-definition@v1 with : task-definition : ${{ steps.task-def.outputs.task-definition }} service : qiita-service cluster : qiita-test-cluster wait-for-service-stability : true Github Actions marketplaceにある ECS Deploy を元に作成してます。 Github Secretsについて Github Actions上で利用する秘密情報や、アクセストークンなどを利用する時に使います。 {{ secrets.AWS_SECRET_ACCESS_KEY }} などで利用可能です。 setting > secrets > new secrets task-definition.json { " requiresCompatibilities ": [ " FARGATE " ] , " inferenceAccelerators ": [] , " containerDefinitions ": [ { " name ": " qiita-container ", " image ": " ***/qiita-test ", " resourceRequirements ": null , " essential ": true , " portMappings ": [ { " hostPort ": 8080 , " containerPort ": " 8080 ", " protocol ": " tcp " } ] , " secrets ": [ { " name ": " ENV ", " valueFrom ": " dev " } ] , " logConfiguration ": { " logDriver ": " awslogs ", " options ": { " awslogs-group ": " /ecs/qiita-test ", " awslogs-region ": " ap-northeast-1 ", " awslogs-stream-prefix ": " qiita " } } } ] , " volumes ": [] , " networkMode ": " awsvpc ", " memory ": " 512 ", " cpu ": " 256 ", " executionRoleArn ": " ****/ecsTaskExecutionRole ", " family ": " qiita-task ", " taskRoleArn ": "", " placementConstraints ": [] } taskは上記AWSの作業手順のなか、Taskを作成したら、Task詳細タブの中にJsonて書かれてる部分があります。 その部分をコピしてLocalのPJ内に配置したらOKです。 Cloud Watchのロググループは存在してない場合、自動的に作成してくれます。(Deployユーザーに権限が無い場合Deploy中にNGになりますので注意) secretsの部分でContainerにわたす環境変数を設定します。nameは渡す環境変数名 valueFromはParameter Storeに指定した名前を入れます。 container name, task name, cluster name, service name など、先に設定しておかない、又はタイポで間違った内容を書くと、Github Actionsの動作中に落ちます。 6. テスト もうほぼ準備は完了です。 ここまでのPJの構成が下記になります。 ├── .github │   └── workflows │   └── main.yml ├── Dockerfile ├── go.mod ├── go.sum ├── main.go └── task-definition.json 実装をしてみましょう! GithubのMasterブランチへPushしたら、Github Actionsが起動されます。 その流れによって、ECSにデプロイ作業が開始されます。 作業が終わったら、AWS管理ページを確認し、EC2>ターゲットグループチェックします。 Public DNSや、利用してるDNSを利用してAPIが叩けるのか確認します! まとめ 今回このような構成でアプリケーションの開発を行ったのは初の試みです。 AWSの知識が浅かったのでかなり苦労した記憶が残ってますが、かなりいい構成かな…と思ってるのでこちらをベースにPJをどんどん拡張していきたいなと思います。 Firelensなどを利用したLog設定や、Github Actions、AWS SNSを利用したアラーム設定、Containerのリソースモニタリングなど、どんどん入れてみたいなと思ってます。 おそらくこの記事の情報だけではそんなに簡単にアプリを作るのは難しいかもしれません。 でもこの記事の内容を参考にしてもらい、皆さんのPJや、悩みへ少しでもHINTになったら嬉しいです。 本日案内したコードは ここ を参考してください。
こんにちは。LIFULL でネイティブアプリのスペシャリストをしている菊地です。 普段は LIFULL HOME'S アプリ(iOS, Android)の開発チームで Tech Lead をしています。 今回、Tech Lead としての活動が5年目となることから、LIFULL HOME’S アプリにおける Tech Lead の事例をご紹介いたします。 ご自身のキャリアパスの一つとして Tech Lead を検討されている方、Tech Lead という役割を導入したい方々の参考になれば幸いです。 はじめに Tech Lead とは Tech Lead はプロダクトに携わるエンジニアチームの技術リーダーになります。 Tech Lead は数年前から浸透してきた役割ですが、会社やチームによって Tech Lead に求められるものが異なるため、明確に「これが Tech Lead」 というものはないと言われています。 Tech Lead の役割 Tech Lead の主な役割(責任範囲)として挙げられるのは以下の3つの要素になります。 コードの品質 チームが作るソフトウェアの品質を守る チームの生産性 チームが設計・実装する上で障害となるものを事前に取り除く アーキテクチャ・設計 チームに技術的なビジョンを示して、そこに導く Tech Lead に求められるスタンス Tech Lead に求められるスタンスなどが書かれた有名な記事がありますので、こちらも参考にしてみてください。 medium.com LIFULL HOME'S アプリの Tech Lead とは LIFULLでは主力サービスである LIFULL HOME'S を iOSアプリ、Androidアプリとして提供しています。 iOS アプリと Android アプリそれぞれに対して専属の開発チームが存在しており、この二つのアプリを開発するチームをまとめてアプリ開発チームとして扱うことが多いです。 アプリ開発チームは以下の三つの職種から構成されています。 企画 デザイナー エンジニア この三つの職種から構成されている LIFULL HOME'S アプリ開発チームに対して 2016年10月に Tech Lead という役割を導入しました。 賃貸物件検索 ホームズ 部屋探し・お家探し・不動産・引越し LIFULL Co., Ltd ナビゲーション 無料 play.google.com Tech Lead を導入するまで Tech Lead を検討した理由 LIFULL HOME'S アプリ開発チームで、Tech Lead の導入を検討した理由はいくつかありますが大きな理由としては、 iOS アプリ開発チームと Android アプリ開発チームに分かれているために iOS アプリと Android アプリという OS を横断した動きというものがとりにくかった ということが挙げられます。 それぞれ普段の業務としては各OSのアプリの開発・運用となるため、各職種の活動範囲や責任範囲がどちらかのアプリに限定されてしまうことがあり、いくつかの課題が上がっていました。 技術的な窓口の分散 各OSアプリ開発チームのエンジニアにはリードエンジニアは存在していましたが、LIFULL HOME'S アプリとして全体をリードするエンジニアは存在していませんでした。 そのため、他部署や他職種(アプリ開発チーム内)からの問い合わせなどへ対応する際に各 OSのエンジニアがそれぞれ対応を行うため LIFULL HOME'S アプリとしての回答に時間がかかる 共通で検討されるべきことがどちらかのプラットフォームのみで話されてしまう といったことがありました。 サービスとしての体験の違い 各OSで開発を行う際に、影響範囲として考慮されるのが所属しているチームの担当 OS の範囲内になってしまうことがあり LIFULL HOME'S アプリとして違う体験になってしまっていることがある どちらかのアプリだけに存在している機能や仕様というものが増えてきた どちらかのプラットフォームのみを利用しているユーザーには影響はないかもしれませんが、両方のプラットフォームを利用しているユーザーやプラットフォームを乗り換えたユーザーにとっては、同じサービスなのに体験が違ってきてしまうという課題がありました。 エンジニアのスキルセット 当たり前のことですが、iOS アプリエンジニアは iOS アプリ、Android アプリエンジニアは Android アプリのスキルセットを持っています。 ですが、iOS アプリと Android アプリの両方の技術についてスキルセットとして持っているエンジニアはいませんでした。 そのため、iOS アプリと Android アプリ で共通の機能開発を行う際に どちらかの OS では実現できるが、どちらかの OS では実現できない スケジュールの都合で、どちらかの OS が先行して機能開発を行った際に、後続の OS の事が考慮されていない API 開発や仕様調整が行われる という課題がありました。 Tech Lead を導入した理由 アプリ開発チームとしてのリードエンジニアの必要性 これらの課題を抱えていたことにより、LIFULL HOME'S としてアプリ(iOS、Android)を成長させていく際に、アプリ(iOS、Android)共通の話や将来的な思想といった部分がまとめにくく、アプリ開発チーム全体としてのレベルをあげることが難しい状態でした。 そこで iOSアプリ開発チーム、Androidアプリ開発チームというOSを飛び越えて動ける存在として Tech Lead という役割を導入し、プロダクト全体としてチームのレベルをあげるために Tech Lead の導入を行いました。 Tech Lead を導入してから Tech Lead として求められたこと LIFULL HOME'S アプリの Tech Lead として求められたことは以下になります。 プロダクトチーム全体の生産性の最大化 技術的負債の管理 設計・開発の妨げになるものの排除 アプリとして共通のビジョンを提示すること OSを限定せず技術でプロダクトチームをリードすること エンジニア以外についても技術視点から意見を伝えて、起案段階から確度の高いものになるようにすること 新たな体験の提供や価値の創造 最新技術の調査・検証・プロトタイプ 最新技術をサービスに落とし込み、チームに展開する チームの技術に対する責任を持つ プロダクトが採用する技術や品質に対する責任 エンジニアの技術に対する責任 技術的な最後の砦になること いることでチームに安心感を与えること Tech Lead としてやってきたこと LIFULL HOME'S アプリの Tech Lead として求められてきたことを実現するために実際にやってきたこと、気をつけてきたことは以下になります。 最新技術の調査・設計・プロトタイピング WWDC、Google I/O などで発表される最新技術などを最新技術を使うだけではなく、アプリの機能や体験にどう落とし込むのか?を検討して、チーム(または各職種)に展開します。 時には技術資料をまとめて、時にはプロトタイプを作ったりして、職種毎にイメージしやすいように展開の仕方を変えるようにして、アプリ開発チームとしてスムーズにサービスに取り入れやすくするために様々な土台づくりをしています。 基本的には、LIFULL HOME'S アプリで提供している「かざして検索」のように事前にプロトタイピングを行った上でアプリに導入することになりますが、場合によっては LIFULL HOME'S アプリとは別アプリとして提供することもあります。別アプリとして提供した例としては Google が提供していた Tango プラットフォームでお部屋の模様替えを体験できるアプリのプロトタイピングを行い、アプリとしてリリースしたという事例もあります。 プロジェクトマネジメント Tech Lead の本来の仕事でないのですが、アプリの共通施策や大規模な機能開発、最新技術の開発といった場合にプロジェクトマネジメントも行うことがあります。 かざして検索のプロジェクトでは全体のプロジェクトマネジメントを行いながら、Android アプリ側での実装を行うといったことも行いました。 技術的負債の管理 iOS アプリ、Android アプリの双方で抱えている負債の把握を行い、将来的なアプリのあるべき姿に向けて施策などが行われる際に合わせて負債も返却できるような提案を行って、返済できるようにしています。 いま出来ることと(負債により)出来ないことを把握して、アプリ開発チームがやりたいことをやりたいときにスムーズに行えるようにするため、障害となり得るものの排除を行っています。 エンジニアの育成 Tech Lead は Enginnering Manager でないということもよく言われていることかと思います。 エンジニアのキャリア形成や人事考課、チームの方向性の評価やキャリアについては Tech Lead の範囲ではなく、技術的な観点についての育成についてについてが Tech Lead の範囲となっています。 具体的には、コードレビューについてとなりますが、普段のやりとりや流れてくる会話の中で技術的な観点でこう考えてほしいなどの助言をしたり、エンジニアとして、他職種と関わる際に意識することでチーム全体でより良い開発ができるような助言を行なっています アーキテクチャの設計 各OSアプリ毎に将来的に必要となるものを導入しやすい下地を作るため、アーキテクチャの選定や、影響の大きいライブラリの選定なども行っています。 Tech Lead が選定したものが導入されるというわけではなく、あくまで議論するための素案となります。最終的には各OSのアプリ開発チームと話し合った上で導入まで進めていきます。 これまで、iOS では Clean Architecture の導入、Android では Instant Apps 対応時の multi module 導入や、Dynamic Feature Module の導入なども行っており、チームとして話すための素案などをまとめてきました。 チームの生産性向上 Tech Lead はエンジニアチームの生産性の向上だけではなく、チーム全体の生産性の向上も求められています。 そのため、LIFULL HOME'S アプリ全体としての技術窓口として、企画やデザイナーと起案段階から技術的な観点で事前に相談を行なったり、ユーザーからの問い合わせなどについても把握しておいて相談がスムーズに行えるようにしたりなども行なってきました。 また、アプリ開発チームにおけるコミュニケーションのルーズボールを率先して拾って、適切なところに受け渡したり、対応を行なったりという一見地味なことも行なっています。 技術的な最後の砦になること Tech Lead の役割として、常に安定していてチームの最後の砦のような存在になるようにするということがよく言われています。 これは言葉としては単純ではあるんですが、とても大事なことなのに難しいなと感じています。 どんな状況、どういった問題に対しても、常に落ち着いて対応をする必要があるため、それまでの状況の把握だけでなく対応するために必要な知識や情報を常にアップデートし続ける必要がありました。 私の場合は、iOS と Android の両方について Tech Lead という役割を持っているため、カバーしなければならない範囲が iOS、Android だけではなく共通で使用する API(マイクロサービスや全社的なもの含む)やそれの裏側の設計、さらには技術的な話以外でそれぞれの業界の動向などとかなり広くなってしまいます。 そのため、Tech Lead として職種間やアプリ開発チームのやりとりをスムーズにするために、技術的な観点以外にも最新の UI / UX、業界の動向やビジネス領域についてもキャッチアップをおこない続ける必要がありました。 一見関係の無いようなものであっても新しい体験を生み出す時に組み合わせられることもあるため、そういったものについてもキャッチアップをするように心がけています。 現時点でもカバーしきれていない領域があるとは思いますが、出来る限り幅広い知見を持つことで、アプリ開発チーム内で起きる問題に対して安定して対応することが出来るように、Tech Lead に聞けばなんとかなると思ってもらえることで安心感を与えるために、常に知見を増やし続けるようにしています。 まとめ 今回、LIFULL の LIFULL HOME'S アプリにおける Tech Lead の役割についてご紹介させていただきました。 既に Tech Lead のようなことをやられている方もいるかと思いますが、Tech Lead という役割を導入することによって、その方のキャリアパスが明確になったり、チームにおける窓口が明確になることで得られるメリットなどもあるかと思います。 もしあなたのチームに Tech Lead という役割がまだないのであれば、Tech Lead の導入を検討されてみてはいかがでしょうか? LIFULLではメンバーを募集しております! カジュアル面談もありますのでご興味ある方は是非ご参加ください! https://hrmos.co/pages/lifull/jobs/010-9999 hrmos.co
こんにちは。エンジニアの加藤です。 普段はLIFULL HOME'Sの注文住宅領域にてエンジニアチームのマネジメントを担当しております。 LIFULL HOME'Sでは日々新機能の開発や機能改修を重ねておりますが、一方でレガシーコードや技術的負債も少なからず抱えており、開発速度低下や開発の幅を狭める一因となっております。 そのような状況の下、ここ数年、機能開発と同様に技術的負債の解消への取り組みにも注力し、注文住宅領域においてもシステム基盤刷新プロジェクトとして、開発効率向上やビジネス成長に耐えうる基盤づくりに取り組んでおります。 今回はそのシステム基盤刷新プロジェクトの一部であるAPIリプレイスを経て学んだ、当初の期待とそれに対するギャップ、そしてそれを踏まえた改善をお伝えしたいと思います。 システム基盤刷新プロジェクトの初期設計 システム基盤刷新プロジェクトでは最終的にはLIFULL HOME'S 注文住宅を構成するそれぞれのシステムのリプレイスを図るものとなっておりますが、領域毎フェーズを分けて実施をしております。 その中でまずは以下のように全体的なシステム設計を行った上、リプレイスに取り組みました。 LIFULL HOME'S 注文住宅には大きく分けて3つのシステムによって構成されております。 一つ目はエンドユーザ向けシステム(以降、web)、二つ目にハウスメーカーや工務店などクライアントへ向けた管理システム(以降、manager)、そして社内用管理システム(以降、client manger)となります。 マイクロサービス化を想定し、それぞれのシステムに対しフロントエンド層とそれに対応するBFF層を構成し、将来的に複数の機能別サービスに対応するAPIを呼び出す可能性を考慮した設計を行いました。 当初の設計時の期待としては以下となります。 期待 機能毎のサービスが増えた際、それらの呼び出しはBFF層で吸収しフロントエンド層をシンプルにする それぞれのAPIにて依存関係や関心の分離を図る BFFは各システムのビジネスロジックや業務ルールに関心を持つ BFFはデータの取得先やDBには関心を持たない db-apiは意味のあるまとまりでDBからデータを取得・更新する db-apiは各システムのビジネスロジックや業務ルールに関心を持たない db-apiの各エンドポイントは特定のシステムによらない設計とし、複数BFFから呼び出し可能とする 同様の処理を各システムにて重複実装することを防ぎ、開発の効率化を図る APIリプレイスを進めて見えてきたギャップ 上記設計に基づき、まずはdb-apiとclient manager-apiのリプレイスを実施致しました。 しかし、開発・運用フェーズを経ることで、徐々に期待に対しての以下のようなギャップが生じました。 ギャップ 機能毎独立したサービス(API)の必要性がない API開発のコストが増加 リリースの複雑性が生じた 一つ目のギャップはマイクロサービス化についてです。 設計当初、将来的には機能毎マイクロサービス化とし、APIを切り出すことを考慮してシステム設計を行っておりました。 しかし、注文住宅領域においてのサービス規模や少人数での開発体制を踏まえると、各機能別にチームを構成し開発を行う必要性が薄く、効率的でないという結論に至りました。 二つ目はdb-apiの再利用性や関心の分離についてです。 理想としてはdb-apiは各システムに依存せず、汎用的で複数BFFから利用可能なエンドポイントを構成するAPIとして期待をしておりました。 しかし、トランザクション等を考慮するとシステムの業務ルールに依存したエンドポイントとする必要性が生じ、汎用的なエンドポイント設計の困難さを感じました。 その結果、各システムに依存するエンドポイントが量産されることが予想され、開発コスト増大の懸念が高まりました。 また、取得処理がメインなweb、更新処理がメインなmanageの双方から利用されるAPIである性質上、ReadモデルとWriteモデルは別々で作成した方がメンテナンスしやすいというDDD的な思想のアンチパターンにも陥っており、開発する上で考慮する観点が増え、こちらも開発コストが増加する一因となっておりました。 三つ目は機能改修時のリリースの複雑性についてです。 機能改修の際は、フロントエンド層、BFF層、db-apiそれぞれに対し開発を行い、リリースの順序によりシステムの整合性を保つ必要がありました。 そのため、リリース時のシステム間での互換性の担保など考慮する部分が増え、結果として開発の複雑性の増大にも繋がりました。 ギャップを踏まえた改善 続くリプレイス対象のシステムとしてweb-apiが控えておりましたが、上記のギャップを踏まえ、当初のシステム設計を見直すこととしました。 その際、見直したポイントとしては以下となります。 見直したポイント 基本的に機能毎のAPI開発を考慮しない db-apiからのデータ取得をやめ、DBから直接データを取得 三層スキーマアーキテクチャにて、業務ルールをViewに集約 新たな設計では、db-apiの廃止や各BFF間でのエンドポイントの再利用性などを排除した代わりに、影響範囲を一つのシステムに限定する構成としました。 また、APIからのデータ取得部分においても一部変更を加えております。 DBに三層スキーマアーキテクチャを導入することで、単一データベースでの簡易的なCQRSを可能な設計としました。 その上で、webでの利用に特化して条件を絞ったViewを作成し、参照することでAPIにて発行するSQLをシンプルにする期待を見込んでおります。 改善点 新たな設計に基づきweb-apiを構築することにより、以下のようなメリットを享受することができました。 開発対象のAPIが一つとなり開発工数が削減 影響するシステムが限定されることで開発効率が向上 Viewにロジックを集約することでAPIのデータ取得ロジックが簡略化され開発コストが低下 まとめ 今回のAPIリプレイスを通じ、結果に対しての振り返りを行い、課題を受け入れ改善することの重要性を学びました。 一度決めたことを変えることはなかなかエネルギーが必要なことではありますが、状況に柔軟に対応しつつ、強い意志を持って変えること、そしてやり遂げることができるチームが強い組織であると考えております。 今回の学びを活かし、今後も技術的負債の解消に向け取り組んで参りたいと思います。
技術開発部の川合です。 この記事ではアプリケーション実行基盤開発を支える視点での取り組みについて紹介したいと思います。 キーワードはKubernetesクラスタE2Eテストと自動化です。 背景 提供機能の保証 Conformance E2Eテストの実行 カスタムE2Eテストの実行 クラスタ構築の不安を軽減する おわりに 背景 私が所属するチームではKubernetesを利用しアプリケーション実行基盤を開発しています。 エンドユーザへの安定したサービス提供はもちろんのことアプリケーション開発者が開発に集中するための様々な機能提供を行っています。 一例を紹介すると以下のような機能が提供されています。 アラート・メトリクスを可視化するGrafanaダッシュボードの自動構築 OPAを利用したmanifestがベストプラクティスに沿っているかどうかの検証 実行基盤への移行を容易にするテンプレートの開発 他にも多数の機能を提供していますがそれらをさらにシンプルに導入する取り組みとして、CRDとして定義された設定ファイルを書くだけでまとめて手に入るという仕組みを開発しています。 これが完成すればnamespaceの作成からデプロイ環境の構築、アラート・メトリクスなど多岐に渡る機能が統合的に導入できるようになります。 こちらについてはまた別の機会に紹介できればと思います。 チームでは「可観測性の向上」「アプリケーション移行支援」「コスト削減」といったテーマを決定し それぞれに求められる改善・機能開発を継続して提供することを目標としています。 こういった活動に対しスピード感を損なわず安定して価値を提供するための仕組みづくりが必要でした。 また、実行基盤(クラスタ)にはマルチテナンシーを採用しており多種多様なアプリケーションがデプロイされます。 多くの裁量を開発者へ移譲できるような思想で運用していますが、基盤自体を安定稼働させる責任としての調査・不具合等対応等が求められます。 テナントが増えることで観測範囲も増加し基盤への開発・運用はより複雑なものになっていく傾向がありました。 提供機能の保証 提供機能も増え、それを利用するアプリケーションも増え影響範囲も増加していきます。 さらにKubernetes本体や周辺エコシステムのアップデートはとても早く、さらなる価値提供のためにもいち早く適用していかなれければいけません。 そこで実行基盤開発の「守り」を強化することを目指しテストを実装しました。 Sonobuoyというツールを利用してクラスタのE2Eテストを実行しています。 github.com このテストによって機能が正しく動作することを保証し、 機能開発のデグレチェック・クラスタバージョンアップによる影響の確認が機械的に行えるようになります。 Conformance E2Eテストの実行 KubernetesにはCNCFが実施している認定プログラムがあり、 Certified Kubernetesとして認定されたアプリケーションはSonobuoyによる適合試験をクリアしていている必要があります。 ※認定済みのアプリケーションはこちらのリポジトリに登録されています。 github.com テスト実装についてはKubernetesリポジトリに格納されておりKubernetesのE2Eの実行方法や、ラベルの種類などはこちらから確認することができます。 github.com Sonobuoyはこれらのテストを便利に実行してくれるテストツールとして利用することが出来ます。 実行されるテストの一部を紹介すると以下のようにConformanceラベルがついたテストを実行していく様子が見られます。 Sonobuoy namespaceを始め独自のnamespaceが作成され実行ログやnodeの様子、テスト実行結果などはSonobuoyが提供するコマンドを通じて確認することが出来ます。 "[sig-network] DNS should provide DNS for pods for Subdomain [Conformance]" "[sig-api-machinery] AdmissionWebhook [Privileged:ClusterAdmin] listing mutating webhooks should work [Conformance]" "[sig-storage] Projected secret should be consumable from pods in volume with defaultMode set [LinuxOnly] [NodeConformance] [Conformance]" "[sig-storage] Projected downwardAPI should provide container's memory limit [NodeConformance] [Conformance]" "[sig-node] Downward API should provide pod UID as env vars [NodeConformance] [Conformance]" 認定済みのアプリケーションを利用しているわけですが組み合わせによる不具合やクラウド固有の設定による挙動変化などがあった場合にそれを検知したいという意図がありLIFULLでは構築後のクラスタでConformanceテストを実行するようにしています。 カスタムE2Eテストの実行 また、前述の通りLIFULLのアプリケーション実行基盤として多くの機能開発を行っています。それらが期待通りに動作するかについてConformanceテストとは別にE2Eテストを実装しています。 これらはKubernetes本家同様にテストフレームワークであるGinkgoとGomegaを使いSonobuoyのカスタムプラグインとして実行できるようにテストを実装しています。例として以下のようなテストを実装しています。 cluster-autoscalerを稼働させインスタンス増減が機能するかを確認する デプロイされたpodがすべてreadyとなっているかupstreamから検証する prometheusがscrapeするjobがすべて成功しているかどうか 実行基盤にデプロイされているアプリケーションにおいてSIGTERMの挙動が期待しているものとなっているかrolling restartさせてみる spinnakerのpipelineを設定したアプリケーションがすべてデプロイされているかを確認する fluentdによるログ収集が機能しているか カスタムプラグインについては公式のドキュメントが充実しています。作成手順は簡単です手順通りに実行すればすぐに導入可能と思います。 sonobuoy.io 前述した内容についてテストを実装してimageをbuildし、 Sonobuoy pluginのcommandが以下のスクリプトを参照するようにしてGinkgoを実行するようにしています。 #!/bin/bash set -x results_dir = " ${RESULTS_DIR :-/tmp/results } " mkdir -p $results_dir saveResults() { cd ${results_dir} tar czf results.tar.gz * printf ${results_dir} /results.tar.gz > ${results_dir} /done } trap saveResults EXIT ginkgo_args = () if [[ -n ${E2E_DRYRUN :- } ]] ; then ginkgo_args+ = ( " --dryRun=true " ) fi ginkgo_args+ = ( " -ginkgo.focus= ${E2E_FOCUS} " " -ginkgo.skip= ${E2E_SKIP} " " -ginkgo.noColor=true " " -ginkgo.v=false " " -ginkgo.reportFile= ${results_dir} /junit.xml " ) e2e_args = () e2e_args+ = ( " -kubeconfig= ${E2E_KUBECONFIG} " " -disable-log-dump=true " " -dump-logs-on-failure=false " ) extra_args = (${E2E_EXTRA_ARGS :- }) target = " ${E2E_TARGET :-apps } " cd /go/src/github.com/lifull/cluster/ test /e2e ginkgo $target -- " ${ginkgo_args[ @ ]} " " ${e2e_args[ @ ]} " " ${extra_args[ @ ]} " | ( tee ${results_dir} /e2e.log ) && ret = 0 || ret = $? saveResults exit ${ret} 実はこのタスクは私が今のチームにJOINした際のオンボーディングの一環として担当させてもらったタスクでした。 そういった経緯のためにクラスタ挙動の理解が浅く、運用開始当初は稼働中のクラスタでは動作するけど構築直後には動作しないといった不十分な実装になっていたりnodeの状態によって失敗するといった不安定さも多く残っていました。 例えばこのコードは安定したdeploymentにおいては稼働しますが、spotインスタンスに配置されたpodがspotのterminationによってEvictされたり、deschedulerによってPodが移動されている最中に実行されたりすると失敗してしまいます。 Context( "Deployment" , func () { var dList *appsv1.DeploymentList BeforeEach( func () { deployments, err := cs.AppsV1().Deployments( "" ).List(metav1.ListOptions{}) if err != nil { panic (err.Error()) } dList = deployments }) It( "should be fullfill specified number of replica" , func () { errList := make ([] error , 0 ) for _, d := range dList.Items { if deployment.IsFulfilledDesiredReplica(&d) != true { e := errors.New(fmt.Sprintf( "Failure deployment ns:%s name:%s check replicas (%d desired | %d updated | %d total | %d available | %d unavailable)" , d.GetNamespace(), d.GetName(), *(d.Spec.Replicas), d.Status.UpdatedReplicas, d.Status.Replicas, d.Status.AvailableReplicas, d.Status.UnavailableReplicas)) errList = append (errList, e) } } Expect(errList).To(BeEmpty()) }) }) そういったケースを考慮してpolling処理を行いながらdeploymentを満たすかどうかを判定するような処理に修正しています。 Kubernetesの挙動を知る意味でもテストを書くのは有益ですし、Kubernetes本体に実装されているテストを参考にしつつ挙動を理解していくのは学習方法としても良かったと感じています。 interval := 5 * time.Second duration := 3 * time.Minute err := wait.PollImmediate(interval, duration, func () ( bool , error ) { return deployment.IsFulfilledDesiredReplica(&d), nil }) if err == wait.ErrWaitTimeout { e := rrors.New(fmt.Sprintf( "Failure deployment ns:%s name:%s check replicas (%d desired | %d updated | %d total | %d available | %d unavailable)" , d.GetNamespace(), d.GetName(), *(d.Spec.Replicas), d.Status.UpdatedReplicas, d.Status.Replicas, d.Status.AvailableReplicas, d.Status.UnavailableReplicas)) errList = append (errList, e) } 実行したテスト結果はslackに通知し、失敗時のログが後から確認できるようにS3に保存するように設定してあります。 Sonobuoyで実行されたテストは実行前のnodeの状態や実行時のログを残すことが出来、どういう状態で失敗したかの詳細を確認することが出来ます。 こうしてテストコードで提供機能の正常稼働を保証しバージョンアップにおいてもそれらが正しく機能するかが判定できるテスト基盤が用意できました。 クラスタ構築の不安を軽減する LIFULLではいつ誰が実行しても期待するクラスタが手に入る状態を一つの目標としていました。 気軽に稼働中のクラスタのクローンが手に入り破壊的変更を試すことができるのは開発を支える視点でも優位なものとなります。 そのための材料として構築の自動化と構築後のクラスタにおいてE2EテストがGreenになることは重要でした。 現在、構築手順についてはすべてコードベースで定義されスクリプト実行に依存し手作業は一切排除されています。 さらにリソースを操作するための権限差異、OS依存の環境差異などにより構築が失敗する状態を避けるため AWS CloudFormationでAWS Systems Manager Automationを構築し固定されたマシンイメージ・権限に基づいてスクリプトが実行できる環境として整備してあります。 この構築環境を利用し「毎日、EC2インスタンスからクラスタ構築スクリプトと一緒にE2Eテストを実行する」ことにしています。 毎日構築を試すことにより構築スクリプトの健全性が定期的に保証される 構築されたクラスタはE2Eテストによって期待する動作を保証される この2つが担保されていることで構築スクリプトの風化やデグレの不安から開放されポジティブに開発に取り組むことが出来ます。 おわりに 以上、アプリケーション実行基盤開発を支える視点での取り組みについて紹介してきました。 目新しいものではありませんがこういった取り組みによりスピード感を損なわずチャレンジングな開発に取り組むことができます。 今後はテストの拡充を行うことでさらなる安心を得て、一切手作業が発生しないクラスタの完全自動切り替えなどにも挑戦して行きたいと思います。 E2Eテスト導入の参考になれば幸いです。 また、LIFULLではメンバーを募集しております! カジュアル面談もありますのでご興味ある方は是非ご参加ください! hrmos.co
どうも【 エンジニアの「市場価値」を向上する 】をキーワードに活動している @サム です。 今回はエンジニアの新しいスキル『 マーケティング × エンジニア 』について書いていきます。 昔と今のITエンジニア 一概にITエンジニアといっても、Webエンジニア、インフラ(サーバ)エンジニア、フロントエンドエンジニア等、様々です。 携わる環境や言語の違いから、必要なスキルも変わってくるため、より専門性の高さが求められていました。 しかし最近は専門性の高さよりも、汎用性の高い(メインスキル + サブスキルを持つ)エンジニアの需要が増えてきていると感じています。 例えば、ほんの数年前まではiDC(インターネットデータセンター)と契約したり自分たちで物理サーバを用意するのが当たり前でした。 用意したサーバにLAMP環境を構築したり、サーバやデータベースの保守運用も必要なので専用のエンジニアもいました。 けれども、AWSやGCPなどクラウド化が進み、インフラ面の構築がGUIベースで簡単に行えるだけでなく、保守面もCI/CDを活用する流れに変わりました。 そのため、 Webエンジニアがインフラ面も担当する 事が多くなったと思います。 そういった流れから、現状はITエンジニアは職種の掛け合わせ 「 ITエンジニア ✕ n 」が当たり前になってきています。 例えば... Webエンジニア ✕ インフラ iOS・Androidエンジニア ✕ バックエンド など... その流れはエンジニアスキルの掛け合わせだけでは収まりません。 プログラミング ✕ 数学などの統計学 = データサイエンティスト エンジニア ✕ 人事 = ジンジニア つまり、ITエンジニアは専門性を高めるだけでなく、オイラー図のように 様々な職種やスキルと掛け合わせる ことで、新しいサービスの開発や、既存サービスの成長に貢献できる人材が求められています。 サービスが使われる仕組みを作り出す「エンジニア」 サービスを世の中にリリースするにあたり重要なことな何でしょうか?それは「サービスが使われる」ことです。 どんなに良いサービスも使われなければ、それまでです。 そのため、サービスが使われる仕組みが必要になってきます。それをエンジニアスキルを使って実現するのが、今回のテーマである『 マーケティング × エンジニア 』になります。 なぜマーケティングなのか まず、マーケティングを4Pで表すと、各分野でエンジニアリングが関係する部分がありますが、LIFULL HOME'Sの事業でいうと最も大きいのはコミュニケーション(プロモーション)です。 コミュニケーションは新規客と既存客に分かれ、新規客はアドテク界隈の技術が代表的です。 そして、主に既存客へのコミュニケーションの自動化を行うもので、CRMの考え方を母体とするのが「 マーケティング・オートメーション・ツール (以下MAツール)」です。その名前のとおり、マーケティングを仕組み化するツールで、MAツールはGDPR等の第三者データの活用規制によってより一層注目度が高い分野と言えます。 MAツールを導入すればいいだけじゃないの? もちろん導入だけで見れは簡単です。しかし目的はMAツールの導入ではなく、使われるサービスの仕組み化なのです。MAツールはマーケティング全般をツールを使って実施していくため、ある程度のマーケティング知識が必要になってきます。そのため、 マーケティングの知識や経験が浅い場合は、MAツールを使いこなせないというリスク もあります。それは一般的なソフトウェアも同様ですね。 MAツールを使うのがエンジニアである必要があるの? もちろんツールを使うだけならエンジニアである必要はありません。 しかしオムニチャネル *1 を始め、ユーザーにアプローチする戦略のオートメーション化を考えると、MAツールとそれぞれのチャネル *2 との連携は欠かせません。 もちろんLINEやメールと連携できる機能を最初から提供しているMAツールも多く存在します。 しかし、既存のWebアプリケーションやすでに使われているサービスを全て1つにまとめるには、 必ずサービスとMAツールを繋げるアプリケーション開発が係わって きます。 こういった事から、マーケティングの知識を持ち、MAツールを使いこなし、サービスを横断して繋げるための開発ができるスキルを持ったエンジニアが必要になってくるのです。 マーケティング × エンジニアのスキルとは マーケティングとプログラミングの知識を持ったエンジニアのスキルはどのようなものでしょうか? そもそもマーケティングのスキル全般を収めてしまうと、それはマーケターの領域になります。 もちろんスキルはあればあるほど良いので、マーケター × エンジニアでも問題ありませんが、この場ではあくまでエンジニアとしてマーケティングに着目していきます。 上記でも述べましたが、マーケティングを一番有効・効率的に行えるのが「MAツール」です。基本的にはこのツールを使いこなすスキルは必須となり、MAツールと連携できるサービスの開発が主軸になると思います。 つまりスキルを分けると次のようになります。 マーケティングスキル ...MAツールの利用、連携(、MAツールを使うために必要なマーケティング知識) エンジニアスキル ...MAツールや既存サービスと連携させるためのAPI開発 もちろん、上記以外でもサービスを構築するためのインフラスキルや、各サービスが配信しているメールのHTMLコーディングやチャットボットなどのUI/UXなど、マイクロサービスを考慮すると必要なスキルは幅広くなってきます。 マーケティング × エンジニアの目指すべきところ マーケティング × エンジニアとは、サービスが使われる仕組みを作り出す「エンジニア」になります。 MAツールを中心として各サービスとの連携を開発し、エンドユーザに対して様々なチャネルを通じてサービスを配信していく機能を創り出すことです。 それはサービスにおけるLTV(LifeTime Value)やARPU( Average Revenue Per User)にも繋がる大切なものです。 今後のエンジニアは現状のテクニカルスキルの延長線ではなく、そのスキルで何を成し遂げたいかで学ぶスキルが変わってくる と思います。 その中でも、ビジネス寄りでサービスの成長を考えたマーケティングスキルを持ったエンジニアは、企業にとって無くてはならない存在になるはずです。 最後に これまで『 マーケティング × エンジニア 』について書きましたが、今後もこういったハイブリット型のエンジニアは増えてくると考えています。 フルスタックエンジニアがいるように、サービスを創るだけでなく、いずれはサービスそのものの成長にも新しい目線で貢献できるエンジニアになってほしいです。 告知 Ltech では、LIFULLエンジニアが中心となって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。 今後もLtechを積極的に開催していきますので、 ぜひ気になった方は、connpassでLIFULLのメンバー登録をよろしくお願いします! lifull.connpass.com *1 : オムニチャネルとは、店舗やアプリなどエンドユーザとあらゆる接点で最適な購入体験を提供すること *2 : チャネルとは、エンドユーザと接点を持つ店舗やアプリなどのサービスのこと
こんにちは、LIFULL HOME'Sの技術基盤部門に所属している戸野です。 LIFULL HOME'Sのエンジニア組織は大きく分けて2つに分かれています。 LIFULL HOME'Sに限らず、プロダクト・サービス全体の基盤システムを保守・改善する技術基盤部門と、ビジネスサイドと密接にコミュニケーションしながら、エンドユーザーが触れるプロダクトを日々開発する事業開発部門です。 下記のエントリでは、事業開発部門における技術的負債解消の取り組みが紹介されています。 www.lifull.blog 一方、技術基盤部門でも各PJでLIFULL HOME'Sの技術的負債解消に取り組んでいます。 そこで、今回は技術基盤部門での技術的負債解消の取り組みをご紹介したいと思います。大規模サービスになると、技術的負債との戦いは避けられないでしょう。私達の取り組みが少しでもお役に立てたら幸いです。 技術基盤部門の体制と取り組み 価値提供を加速させるために技術基盤部門では、技術的負債解消の文脈でバックエンド・フロントエンドともに既存アプリケーション改修を行っています フロントエンドの既存アプリケーション改修についてはこちらの記事で紹介されています。 www.lifull.blog 私がアサインされているPJでは、 バックエンドの既存アプリケーション改修 を、現在2名体制で取り組んでいます。 具体的にどのような技術的負債があったかと言いますと、 設計レベル 何重にもなっているクラスの継承関係 処理の流れがとても分かりづらい複雑な依存関係 実装レベル マジックメソッドがあらゆるところで使われているためデバッグしづらい 動的に呼ばれるクラス、メソッドが多くデバッグしづらい ビジネスロジックがテンプレートエンジンに記載されている などがあってそれぞれに対応していきました。 PJを進める上での制約 このような技術的負債に立ち向かっていくわけですが、技術基盤部門と事業開発部門が並行して開発を進めるため、当然制約がある中での開発でした。そして、具体的には次のような制約がありました。 制約💁‍♂️ 事業開発部門の人数の方が多く、並行開発による衝突のリスクが常にあるので、事業開発部門の変更をウォッチしコミュニケーションを適宜取り調整する必要があった。 事業開発部門の人数の方が多く、速度的に技術的負債の「増大スピード > 解消スピード」であるため、手当たり次第にリファクタリングを行うのではなく、効果の高い部分から対処する必要があった。 事業開発部門の開発を停止させることはできないため、バグが確実に出ないようにQCDのQ重視でテストを厚くし、後方互換性を維持したAPI設計の必要があった 技術的負債解消のために講じた具体的な取り組み これらの制約の中で私達は技術的負債の解消を進めていきました。そこで、設計実装レベル両方で技術的負債を解消するための取り組みを3つ紹介します。それぞれの取り組みの説明、メリットと大変だったことを具体的に説明しています。 全体を俯瞰して分析し本質的な問題点と解決策の洗い出し 技術基盤部門がLIFULL HOME'Sの技術的負債を解消することに取り組むメリットは、 事業開発部門が工数的にできないような、広い範囲での根本的なリファクタリングを行えることだと思います。 広い範囲での改修になるので、部分最適な設計実装にならないようにする必要があります。そこで、UMLを駆使してリバースエンジニアリングを行い、全体的にクラスの依存関係、継承関係、API呼び出しなどを調査し現状の本質的な問題と解決策を分析しました。 メリット🙆‍♂️ そもそもの設計レベルから見直すことができ、できるだけ理想に近い形の設計をすることができた 大変だったこと🤷‍♂️ 継承関係と依存関係が複雑すぎて現状のソースを理解、分析するのにかなり苦労した 古いAPIをやめて新しいAPIを呼び出すように改修 LIFULL HOME'Sでは複数のAPIが使われていて、中には古いAPIが使われている箇所があります。 古いAPIはアーキテクチャの技術的負債があったりして利用しづらいので、 できるだけ古いAPIの呼び出しをやめて、新しいAPIを呼び出す実装に修正していきました。 新しいAPIはテストコードが完備されているのとアーキテクチャの面で分かりやすいので、以前よりも保守性可読性が上がったと考えています。 メリット🙆‍♂️ (廃止予定の)古いAPIを廃止するのに1歩近づいた 大変だったこと🤷‍♂️ 古いAPIのアーキテクチャが複雑で、調査分析の工数がかなりかかった ビジネスロジックと表示ロジックの適切な分割 ビジネスロジックと表示ロジックがフロント側のシステムに混在していて、 フロント側のコードが肥大化し、かなりメンテナンスしづらい状況でした。 そこで、他PJが考えていたビジネスロジックと表示ロジックの切り分けのルールを参考にしながら、 ビジネスロジックをAPI側、表示ロジックをフロント側に実装するように切り分けていきました。 メリット🙆‍♂️ フロント側のコードのボリュームが小さくなり、以前よりも調査しやすくなった 各システムの責務が明確になり、以前よりも凝集度の高いメンテナンスしやすいコードになった 大変だったこと🤷‍♂️ 単位やprefixのような文字列をドメインとして扱うかどうかの判定で悩み、ビジネスロジックか表示ロジックかの切り分けが難しかった 最後に 技術基盤部門での技術的負債解消の取り組みを紹介させていただきました。技術的負債解消は、直接的にビジネスの価値提供をするわけではないので、どうしても優先順位を高くつけづらいところがあると思います。 しかし、技術的負債が積み重なるとビジネスの価値提供も鈍化するので、かなり重要なことだと考えています。 技術基盤部門という立場で、今後も技術的負債解消に立ち向かい、長期的に価値提供ができるシステムを構築していきたいです。
LIFULLのエンジニアの村田です。 私は2018年までLIFULL東京本社で勤務していましたが、現在は北海道の札幌拠点に勤務しています。 当時LIFULLには、全国に営業拠点はあったものの地方開発拠点はありませんでした。私が北海道に移住するタイミングで 札幌の営業拠点に開発拠点を整備することになり、LIFULLにとって初の地方開発拠点が誕生しました。 本エントリーでは、東京に長年勤務していたエンジニアが 地方開発拠点で働くようになって感じたメリット・デメリットおよび、 今後どのような働き方になっていくのか思うことをつらつらと書いていこうと思います。 内容が札幌に限定されている部分も多々ありますが コロナ禍でのリモートワークが普及する中、 地方に移住しようと考えているエンジニアの方に向けて参考になれば幸いです。 地方(札幌)拠点の良いところ 家賃が安い まず何と言ってもこれ。 都心に比べると、家賃が圧倒的に安いです。 同じ家賃で広い部屋に住める! 私の場合は、3人家族で2Kから3LDKに引っ越しましたが 東京にいた時よりもトータルで家賃が安くなったにも関わらず 広さは2倍近くになりました。 参考までにですが、私が住んでいる行政区の家賃相場と東京23区で 比較的家賃相場が低い足立区と比べてみても ▼ 札幌市豊平区の家賃相場 https://www.homes.co.jp/chintai/hokkaido/sapporo_toyohira-city/price/ ▼ 東京都足立区の家賃相場 https://www.homes.co.jp/chintai/tokyo/adachi-city/price/ およそ2倍の家賃の差があります。 リモートワークにおける仕事部屋の確保のしやすさという点では 非常に大きなメリットですね。 上記の例では札幌ですが、他の地方でも都心に比べれば 家賃が下がる可能性は高いはず。 通勤が楽になった 通勤のストレスがまったくないというわけではありませんが、 毎日満員電車に揺られていた頃に比べると、雲泥の差です。 札幌はコンパクトシティで、地下鉄の最寄駅から 中心地さっぽろ駅まで、通勤時間がだいたい10〜15分以内に収まります。 住む場所によっては、自転車で通勤することも十分可能です。 リモートワークであれば、そもそも通勤に関しては問題になりにくいかもしれませんが、 場合によっては出社する必要があるケースも出てくるので 通勤が快適であるに越したことはないですよね。 採用・勤務範囲が広がる 会社の勤務範囲が広がることは会社にとってもメリットになります。 今まではエンジニアの採用は東京勤務が必須であり、本社に通勤できる 範囲のエンジニアしか採用できませんでした。 札幌拠点ができたことで、札幌にいるエンジニアも採用の対象となり、 採用の幅が広がりました。また、北海道出身の社員もLIFULLにはたくさん働いていますので、 彼らが北海道に戻るようなケースがあった場合は 札幌拠点で働き続けるといった選択肢も用意できるようになりました。 その他メリット エンジニア視点ではありませんが、他にも ご飯が美味しい、子育てに優しい環境、夏それほど暑くない などなど、総じて言えることはQOLがかなり向上したと思います。 地方(札幌)拠点の気になるところ 勉強会の開催数が少ない。 東京にいた頃は、平日もぎっしり様々な種類の勉強会が行われていましたが 北海道の勉強会の開催数はかなり少ないです。 人口比率からして仕方ないことですが、エンジニアにとっては残念な点になるかと思います。 しかし、コロナ禍で勉強会がオンライン開催されることが多く 札幌にいながらでもこういった勉強会に参加できるようになってきたので この点のデメリットはなくなりつつあります。 情報システム部のサポートが手薄 情報システム部のメンバーが拠点に存在しない場合、 PCのキッティング等は本社の情報システム部門が行ないます。 万が一業務PCが故障した場合、本社から新しいPCが送られてくるまで 業務がまったくできない状態になってしまいます。 また、PCが不調の場合でも本社であれば、直接PCを持ち込むなどして情シスのサポートをすぐに受けられますが それが地方拠点だとできないため、このあたりのケースに備えて 予備のPCをあらかじめ用意しておく等、対策を考えておく必要があります。 冬が厳しい(北海道限定) 一年の半分は寒く、1月〜4月は雪が積もりっぱなしです。 北海道に来た年は、3-4回盛大に雪の上を滑りました。 エンジニアにとって、手は命なので雪で滑って骨折したなんてことにならないよう、 細心の注意を払う必要があります。 在宅勤務の場合は、吹雪にさらされる場面は少なくなるものの 自宅の暖房代がかさんでしまうのが辛いところです。 地方拠点で苦労したこと 私のミッションは、LIFULLの価値創造を加速させるようなエンジニア組織を 札幌拠点でも構築することでした。 本社にエンジニアが集中している中で、1人だけ物理的な場所が離れたオフィスにいる身としては 本社とどうやって連携を取っていけば良いか手探り状態でした。 その中でも特に困った事が、本社との会話におけるコミュニケーションです。 本社の会議に私だけリモートで参加するスタイルになるわけですが、 会議の音声がクリアに拾えるかどうかは会議室の設備に大きく依存します。 高価なマイク設備が設置された会議室であれば、ある程度広い範囲のメンバーの 声をクリアに聞き取れることができます。逆にマイク設備がなくメンバー一人のPCを 利用したミーティングでは、そうはいきません。 ミーティングを行う場所によっては、あらかじめ集音マイクを用意してもらうように 参加メンバーに依頼したりしていました。 設備を揃えたとしても、離れた位置にいるメンバー同士での会話はどうしても把握しづらいなど 体感値として、MTGの内容のうち6〜7割キャッチアップできれば上出来だったのではないでしょうか。 コミュニケーションに苦戦しつつも 私が強く意識していたことは 「この仕事を任せたいけど、メンバーが本社にいないなら無理かも」 といった、判断をされないように実績を積み上げていく事でした。 前例が無い状態で、成功事例を作ることは非常に重要です。 拠点のメンバーでも、本社のメンバーと問題なく連携して仕事を遂行できる ということを証明するため、基本はどのような仕事も引き受けるようにしました。 実績を積み上げることで、開発拠点の可能性を広げ 全国にどんどん開発拠点を展開していくような未来を描きたいと思っていたからです。 最終的には、全国にいるエンジニアが横断でチームを組んで PJを遂行するような働き方を実現したいと思っていました。 コロナになって変わったこと 開発拠点が設立されて1年が過ぎ、新しいメンバーが増え 実績を着実に積み上げている中、ある出来事で状況は一変しました。 そう、コロナです。 コロナによる緊急事態宣言下の中、 LIFULLでは比較的早くリモートワークが導入されました。 これがきっかけで、拠点と本社のコミュニケーションの質が劇的に改善されることになります。 札幌拠点の開発チームは2020年から、東京にいるチームと組んでPJを進めていたのですが コロナ禍以前では、彼らとのやりとりは基本はチャットベースが中心で 週1回の定例MTGで情報共有を行う程度でした。 MTGも回線や設備が悪い状態で音声が聞き取りにくいこともあり、非常にストレスでした。 現在は各メンバーがZoomで常時接続しながら仕事をしており、何かあればすぐにコミュニケーションをとれるようにしています。 画面共有によるペアプロや、オペレーションのダブルチェックといったことも苦労なくできるようになりました。 あれほど苦労していたMTGも、全員が同じ条件でWeb会議システムに参加する形式になったので 参加メンバーの声がききとりやすくなり、MTGの雰囲気も掴みやすくなりました。 拠点も本社もフラットに 今まではどんな工夫を施したとしても本社、拠点という区切りがありました。 物理的な距離が離れた拠点にいる、という事実は消すことができず 何かを判断するにもそこは意識せざるを得ません。 コロナになって、リモートワークが導入されたことで どこで働いているのか、ということはあまり問題ではなくなりました。 本社だからとか、拠点だからとか、地方だからとか、東京だからとか それらに差が生まれなくなり、働く場所における条件がフラットの状態になったのです。 拠点ならではの価値を出す事や、本社とうまく連携するためのノウハウを 溜め込んでいくといった必要性がもやは無くなりました。 こうなってくると、組織の形も変わってくるのではないでしょうか? 今までは同じ拠点の社員で組織を構成せざるを得なかったケースが多いようでしたが 拠点という概念を外して、組織を編成することが容易になりました。 少なくとも、エンジニアのグループをあえて拠点で区切る意味はもう無いように思えます。 日本全国に散らばった「働きたい場所で働くエンジニア」同士が チームを組んで、リモートでコミュニケーションをとりながら 仕事を進めていけるような、私が目指していた遠い未来にぐっと近づきました。 まとめ コロナによる新しい生活様式が確立され、リモートワークが広がりつつある今、 物理的な場所に縛られず働くことが可能になってきました。 地方拠点においても、リモートワーク浸透により 本社との連携が劇的に改善されるなど、今までのデメリットが改善され より生産性を上げて仕事ができるようになりました。 選択肢がぐっと広まったこの機会に、自身の働き方を見直してみても良いかもしれません。 何はともあれ、北海道はいいところです。