エンジニアの松尾です。LIFULL HOME'Sの売買領域を支えるエンジニアチームのマネジメントを担当しています。 弊社のサービスは、主にサービス企画、デザイナー、エンジニアの3職種により進められています。今回はより良いプロダクト開発のために3職種の連携を強める取り組みについて紹介します。 より良いプロダクトを開発するために 現在LIFULLでは組織が職能別に分かれており、各領域の専門性を高めるためにさまざまな取り組みが行われています。 私が所属するプロダクトエンジニアリング部でも、 勉強会の開催 、 独自のKPIの設定 、 技術的負債解消への取り組み などを進めてきました。 一方で職種間の連携にもまだまだ伸びしろはあります。そこで、現場におけるコミュニケーション上の課題と打ち手を考えてみます。 上手に期待感をすり合わせたい 書籍「 アジャイルサムライ 」では、チームメンバーどうしでお互いの期待感を伝え合うための「ドラッカー風エクササイズ」という手法が紹介されています。自身が思う強みや役割と他者からの期待のギャップを明らかにすることで、お互いの魅力を引き出します。 弊社でもプロジェクトごとにキックオフのタイミングで実施されていることが多く、チームビルディングの一つとして重宝されています。しかし、現在の組織は構成人数が多く、プロジェクトメンバーの変更が発生することもあり、個人間の期待をすり合わせ続けることはなかなかのコストです。 そんな悩みを抱えていたときに「 どういうデザイナーとだと仕事しやすいか 」という記事を拝見し、個人以前にほかの職種に対しての期待も少なくないことに気付きました。 そこで、コミュニケーションの土台として、サービス企画、デザイナー、エンジニアの3職種間での期待感をすり合わせるための取り組みに着手しました。 チームで取り組んだこと 今回の取り組みではLIFULL HOME'Sの売買領域でエンドユーザ向けの開発に関わるメンバーを対象にしました。各職種は下記のような内訳です。 サービス企画: 10名 デザイナー: 5名 エンジニア: 15名 事前課題 自分の職種について、「役割/強み」を記入する 他の職種に対して、「期待すること」を記入する 「期待すること」を見渡して、同意するものにリアクションをつける 気軽に回答できることを優先するため、記入する内容はドラッカー風エクササイズよりシンプルにしています。とはいえ大人数での意見をまとめる必要があるため、スペースや人数の制限が少ないホワイトボードとしてmiroを採用しました。 議論 記載された内容について、不明瞭な部分や背景を聞きたい部分を職種間で議論しながら深掘っていきます。すべて理解できたあとに、職種内で期待されていることに対しての振る舞いをふりかえり、教訓とアクションをまとめました。 職種ごとに用意したmiroのボード 私達が期待している/されていること 全体的に「協力は惜しまないので、妥協せずにやってほしい」という姿勢の意見が多く見られました。ある人にとっては「当然のことでは?」ということでも明示的に伝えることで、より互いの理解が深まりました。 実際に出てきた意見の一部を抜粋して紹介します。 サービス企画への期待 PJ全体の優先順位の相談〜判断 目的/意義/効果に納得できる施策を提案してほしい リリース後にも継続的にその機能を見直してくれるとうれしい デザイナーへの期待 すごいと思える/説得力のある/最良のデザイン サービス全体を俯瞰した情報・デザインの整合性 UIだけでなくUXも一緒に考えてほしい エンジニアへの期待 実装方法の工夫で仕様の可能性を広げること 他のサービスに横展開しやすいように実装してくれること 実装中にモヤモヤするところがあれば率直に伝えてほしい まとめ 自組織において職種間の期待を伝え合う方法を紹介しました。今回の結果はあくまでも弊社での一例ですので、プロダクトの特徴や組織のあり方に応じてきっと違う結果が出ます。 ちなみに後日メンバーから、「対個人じゃないので素直に書きやすかった」というコメントがありました。完成度の高いチームでは個人間で率直に伝え合えば済む話ですが、そこに至るまでの途中段階として今回のようなワークショップを挟むのも良い手段だと思います。 今後もより良いプロダクトを世に送り出していきます。ともに最高のチームを作っていく仲間を募集しておりますので、よろしければこちらのページもご覧ください。 hrmos.co hrmos.co
こんにちは!LIFULLのプロダクトエンジニアリング部の井上です。 エンジニアリングマネージャーをやっています。 今回は、私が管掌する組織で「大規模スクラム」という、スクラムを拡張して複数チームで運用する開発手法へチャレンジし、生産性向上を図った話をしようと思います。 結論 結論から伝えますと、組織を俯瞰して管理する立場からすると、一定レベル、メンバー主体で合理的に動ける仕組みをつくれた実感をもてました! その反面、経験値不足もありますが本質的な組織的なスクラム開発が実践できているか?と言うと、まだまだ改善をしていく必要があるとは感じています。 取組みのポイント スクラムの3本柱「透明性」「検査」「適応」に倣うならポイントはこのような感じです。 透明性 バックログは組織に1つだけ 誰でもいつでも全体像が見れる、判断できる状態をつくる(チームや誰かだけしか知りえない状態は禁止) ただし認知コスト削減の為にチーム単位でフィルタを作るのは問題なし 検査 意思統一できる場を用意 全体+各チームの状況を共有や相談できる場、共有や議論できる定例を用意 適応 優先度ルール 基本的には各チーム内施策に集中すればよい ただし、優先度が高い障害や、組織判断で優先度「高」の施策が現れたら、各チームの施策に専念する限りではないというルールを初期に徹底 まとめの図 前提(それまでの組織の構造) 最初に、私が管掌している組織の話からさせてください。 私が管掌する組織ではあるプロダクトに対して1つミッションを持っています。 今回の取り組み以前は、それらの達成のために4~6人程度の職種混合の小チームを4~5チーム程組成し、それぞれで施策表/課題表(バックログ)をつくり開発していました。 チームだけで考えれば関心ごとがチーム中で閉じている為、意思決定速度は担保されるのですが、チームでミッションを固定している故にチーム外への意識が弱くなったり、全体では優先度が高い施策や変化に対して、柔軟性が損なわれる課題がみえていました。 組織構造の図 私たちが目指したいこと 限られたリソースで、効率よく最大の効果を出すためには・・ =チームへミッションを固定させすぎず、全体視点で優先度が高い課題から対応できると良さそう 真の優先度が高い施策から実行したい これを実現するためには、ひとつのミッションを分解した課題群が組織で1つのバックログで管理され、各チームがバックログから自主自律的に、優先度が高い課題を選んで実行していくことが理想と考えました。 複数チームが1つのバックログからチケットを取得する図 柔軟な組織 また、期の途中であってもミッション実現のために当初計画していたタスクとは別に、重要な課題が発生するケースも考えられ、突発の事態に柔軟に対処できる仕組みである必要があります。 想定される、計画外案件: 障害対応 他部署からの依頼・相談 成果を出すために、戦術レベルでの優先度変更 など 効果的なチームの組成 効果的なチームである為には心理的安全性が重要であるという調査結果もでています(Googleが公開しているre:Workより)が、この観点でも配慮はいれたいと考えました。 その為にチームメンバーを固定することができれば、互いに信頼し合い働き方や考え方・期待値を一致させることがしやすく、仮に優先度にあわせてミッションやKPIが多少変化したとしても高いパフォーマンスで乗りきりやすいと考えました。 逆に、チームメンバーがコロコロ変化すれば信頼や考え方の一致が出来るように至るまで、パフォーマンス低下は免れないでしょう。 現実は複雑 新規開発などシンプルなKPIを追いかける構造のミッションや、スクラムに対して習熟度が高いメンバーが揃っていれば、上述した仕組みがワークする気がするのですが・・・ 施策優先度が単純に比較できない 数年間、運用を続けているプロダクトに対して適用させると、方向性がそこそこ違う複数の打ち手が並列で並んできます。 すると、チーム間で優先度の判断は非常に困難になってきます。 優先度が判断できない課題群(例) チーム 打ち手 課題 A UX追及 〇〇モーダルの挙動調整 B SEO対策 〇〇記事からのリンクの新規設置 C 新機能開発 〇〇機能の開発 全体で優先度を判断するためには、方向性の異なる打ち手を誰かが管理する必要があると思います。 その方法として以下のようなパターンが考えられます。 方法①:各チームのスクラムマスターが集まり、全体バックログリファインメントを実施し全体管理して各優先度を決定。 方法②: 全体をみている上長が、トップダウンで優先度を判断。 しかし、前者は認知負荷が大きかったり、後者も上長が都度意思決定するプロセスが増えてしまい、不要なコストがかかりすぎるように思えました。 前提となるスクラム / アジャイル開発に対して、理解や習熟度がバラバラ そもそもスクラムやアジャイル開発を知らない・経験がないというメンバーは、いないものの、習熟度も興味も人によって差が大きく、理想形から組織に落としていくには、導入コストもコミュニケーションコストも大きい割に十分なリターンが得られるか不透明で、困難を極める事が想定されました。 導入の為に、意識したこと 理想と現実のジレンマはあるのですが、最初からすべて完ぺきに実行するのではなく、次の3点をベースに 極力シンプルなルール を設ける事としました。 意思決定の速度を高める、不要なものを可能な限り排除 チームメンバー全員がチームの中と外の両軸について、常に関心を持ち続けることは認知コストが高く効率性を下げてしまいます。 よって、シンプルに原則チームに集中してよいルールとし、チーム内はもちろん組織全体で発生した優先度が高い課題をとるかはチームの自主・自律性に任せる体制としました。 合わせて上長が意思決定や承認に入るケースも最低限とすることで、より効果を高めることも図りました。 定期的に、全体の数字や課題を確認・議論できる場を用意 とはいえ、チームに関心を集中しすぎると、横断的な施策などに対して組織的な柔軟性は失われ、上長が指示をしたとしても自主性がないためストレスを抱えかねないと考えました。 これは心理学でいうザイオンス効果(単純接触効果)により、自身が一番よく触れる数字や課題、プロダクトに対して、興味をもってしまうので致し方がないことだと考えていますが、極端になりすぎないようにしなければいけません。 効率よく結果を出す為には、隣のチームと協力できる程度の情報共有はされているべきですし、上述していますが、当初計画していなかった戦術の変化や緊急対応はありえる事だから対処が当然必要です。 その為に、隔週でスクラムマスターを集めて組織全体の中でも特に課題となっている部分だけを議論する場を用意し、話し合いで合理的に処理するようにしました。 学習コストは最低限に ルールは、シンプルに 可視化により組織全員が共通認識をとれるようにする 為のルール(=小さな学習コスト)だけが必要とだけ伝えていました。 結論 冒頭にも記述していますが、3か月ほど運用した時点での感想としては、本当の意味で、組織の目指すKPIに対して優先度が高いものから動けているか?というと、まだまだ伸び代を感じていますが、最初の一歩としては、よい状態をつくれたと感じています。 導入のポイント 今回、アジャイルをスケーリングした開発手法を導入するにあたり、Scrum of ScrumやLeSS・SAFeといった様々なものを参考にさせてもらったのですが、フレームワークのカタチに拘らず、そもそも自組織の課題やありたい姿と照らし合わせてシンプルに小さく適用したのがよかった気がしています。 ここまで、この記事を読まれた方は、 アジャイルをスケーリングすることに興味がある方かと思いますが、何かの参考になれば幸いです。 最後に 今回とりあげた、組織で実行するスクラムは私自身も上手く行くか不安があったものの、 チャンレンジをさせてもらって一定の次に繋がるカタチにできたかなと思っています。 このように、LIFULLでは、さまざまな新しいチャレンジに取り組みやすい環境が整っています。 LIFULLでは一緒に働く仲間を募集しています。よろしければこちらも合わせてご覧ください。 hrmos.co hrmos.co
KEELチーム の相原です。 もう随分と前のことになるのですが、以前我々が管理するKubernetesクラスタであるKEELで起きた障害のふりかえりについて書きます。 今回起きた障害 PriorityClassとはなにか 経緯 何が起きたか なぜPodDisruptionBudgetは機能しなかったのか どうすればよかったか 最後に 今回起きた障害 既にサービスインしているKubernetesクラスタ に対して globalDefault: true なPriorityClassをデプロイした 影響で、まだPriorityClassが設定されていない priority: 0 なPodが一斉にPreemptされ一時的にサービスに障害が起きた。 PriorityClassとはなにか 詳しい説明は公式ドキュメントの Pod Priority and Preemption に譲りますが、初めにPriorityClassについて軽く説明しておきます。 kubernetes.io PriorityClassとは以下のように定義するKubernetes組み込みのリソースで、KubernetesがPodをスケジューリングする時の優先度を表します。 apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : high value : 1000 Pod側の priorityClassName で以下のように指定することで有効になり、このPodのスケジューリング時にNodeに十分なリソースがなければ priority の値が 1000 より小さいPodを対象のNodeから選択してPreemptするというものです。 apiVersion : v1 kind : Pod metadata : name : example spec : priorityClassName : high ... Preemptionとはkube-schedulerによって実行される単なるPodの終了のことで、通常のPodの終了と同じように preStop の実行 -> SIGTERMの送信 -> terminationGracePeriodSeconds の秒数経ってPodが終了しなければSIGKILLを送信する といったフローで実行されます。 PriorityClassに preemptionPolicy: Never と書けばPreemptionを無効にできますが、この場合リソースに空きが出た時に優先的にスケジューリングされるというだけなので当然待ち時間は長くなります。 globalDefault: true と書くことで priorityClassName を指定していないPodに自動的にPriorityClassを設定することも可能です。 デフォルトではPodの priority の値は0となるため、基準となる priority を globalDefault: true として作成しておくとよいでしょう。 priority はKubernetesのAdmission Controllerによって設定されるため、次回のPodデプロイ時から有効になります。 後述しますがこれが今回の障害の原因となりました。 ちなみに、このPriorityClassにはデフォルトで system-cluster-critical と system-node-critical の2つのPriorityClassが存在していて、これらはKubernetes 1.13で廃止された scheduler.alpha.kubernetes.io/critical-pod の代わりとして用意されるようになったものです。 絶対にPreemptされたくないクラスタの重要なコンポーネントであるDaemonSetに付与することが想定されていて、 kube-system 以外では利用することができせん。 経緯 我々が管理するKubernetesクラスタであるKEELではPodのほとんどをAWSのスポットインスタンス上で稼働させるべく、 スポットフリート の導入や、スポットインスタンス売り切れ時のフォールバック機能やスポットインスタンス上のPodの安全な終了処理の開発などを進めてきました。 フォールバック機能は開発したものの依然スケジューリング待ちは予想できたため、待ち時間をできるだけ短くするべくスポットインスタンス上のPodの中でもスケジューリングの優先度をつける必要が出てきました。 そう、PriorityClassです。 そこで我々は以下の3つのPriorityClassを用意して適用しました。 PreemptされてもよいPodに付与する value: 100 の low PriorityClass 標準的なPodに付与する globalDefault: true かつ value: 1000 の medium PriorityClass 優先度の高いPodに付与する value: 10000 の high PriorityClass 適用後、無事にlow PriorityClassを持ったPodのPreemptionを確認することができ、これで更に安定してスポットインスタンスを利用できるようになりました。 と、思ったのもつかの間、突如チームに対して大量のアラートが届きます。 アラートの発生元は外形監視で、どうもクラスタ外からのリクエストのエラーレートが急上昇していそうです。 調査をしてみると、クラスタ外からのリクエストを受け付けるリバースプロキシである istio-ingressgateway をはじめとして多くのPodに再起動した形跡が見られました。 クラスタ内のリクエストはKEELで利用しているService MeshであるIstioによってリトライされていたため大きな影響はありませんでしたが、クラスタ外からのリクエストを受け付けるリバースプロキシの台数が減ったことによって外からのエラーレートが急上昇していました。 何が起きたか この障害は globalDefault: true によって引き起こされました。 前述の通り、デフォルトのPodの priority の値は0です。 PriorityClassを導入する前にデプロイされたPodにはすべて priority: 0 が設定されています。 priority はAdmission Controllerによって設定されるため、PriorityClassを適用しても既存のPodは引き続き priority: 0 のままです。 そこに今回 value: 1000 なPriorityClassに globalDefault: true を設定した影響で、十分なリソースがないNodeに新たに priority: 1000 なPodがデプロイされ、PriorityClass導入以前のPodが一斉にPreemptされました。 なぜPodDisruptionBudgetは機能しなかったのか KubernetesにはEvictionというPreemptionに似た挙動が存在します。 Evictionは Node-pressureが起きた際 や Taintによって PodをNodeから退避させるものですが、PodDisruptionBudgetによって一度に退避させるPod数に制限をかけることができます。 KEEL上にデプロイされているPodにはほぼすべてPodDisruptionBudgetが設定されているため、こういった現象は防がれていたはずです。 しかし、Preemptionのドキュメントには以下のようにあります。 Kubernetes supports PDB when preempting Pods, but respecting PDB is best effort. The scheduler tries to find victims whose PDB are not violated by preemption, but if no such victims are found, preemption will still happen, and lower priority Pods will be removed despite their PDBs being violated. kubernetes.io なるべくPodDisruptionBudgetの通りにPreemptしようとするが、完全に保証されるわけではありません。 そのため、PodDisruptionBudgetを設定しているにも関わらず今回のような障害が起きてしまいました。 どうすればよかったか まず第一に、稼働しているクラスタに対してPriorityClassを設定することには慎重にならなければなりません。 全てのPodにはデフォルトで priority: 0 が設定されているため、PriorityClassの設定によって意図しないPreemptionが発生してしまう可能性があります。 globalDefault: true を設定するならなおさらで、以降デプロイされる全てのPodには priority が設定されるため、これが0を超えている場合PriorityClass導入以前の全てのPodがPreemptionの対象となってしまいます。 priority の取りうる数値は n < 2000000000 と広いため、つい幅を持ってPriorityClassを作りたくなってしまいますが、恐らくそれほど細かく priority を設定することは少ないため、KEELでは以下のようなPriorityClassの定義に落ち着きました。 apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : low value : -10 --- apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : low-nonpreempting value : -10 preemptionPolicy : Never --- apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : medium value : 0 globalDefault : true --- apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : medium-nonpreempting value : 0 preemptionPolicy : Never --- apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : high value : 10 --- apiVersion : scheduling.k8s.io/v1 kind : PriorityClass metadata : name : high-nonpreempting value : 10 preemptionPolicy : Never globalDefault: true なPriorityClassの value を0にしているため、万が一後からPriorityClassを設定することになっても既存のPodがPreemptされることはありません。 KEELはStatelessなKubernetesクラスタであるため、大きな変更を伴うバージョンアップの際にはクラスタの稼働系を2つ用意してCanary Deploymentをするので、念のため後からもPriorityClassを設定できるようにしました。 また、 kubernetes/autoscaler のcluster-autoscalerを利用している場合、 --expendable-pods-priority-cutoff を下回った priority は無視されるため デフォルト値の-10 を下限としています。 最後に 実は恐ろしいことに、この障害の2週間前に Grafana社での同様の障害のPostmortem をチーム内で共有したばかりでした。 grafana.com しかもこのPriorityClass導入の作業者である私がです。 Preemptionの挙動も頭に入っていたはずにも関わらずの大失態でしたが、Kubernetesの失敗談を集めた Kubernetes Failure Stories にもPriorityClassにまつわるエピソードは多いため、このエントリでの注意喚起をもって罪滅ぼしとさせてください。 k8s.af Multi TenancyなKubernetesクラスタでは利用者による意図しないPreemptionを防ぐため、勝手にPriorityClassをデプロイできないよう権限を絞るのはもちろんのこと、ResourceQuotaやOPA Gatekeeperで利用できるPriorityClassを細かくコントロールする必要があることにもご注意ください。
自己紹介 プロダクトエンジニアリングチームの石川です。 2020年新卒入社で2年目のエンジニアです。 今回の記事では、エンジニアだけで新機能開発・検証を行うPEChallengeについて紹介させていただきます。 ユーザーテストの具体的なやり方まで紹介させていただきますので、最後まで読んでいただければ幸いです! PEChallengeとは PEChallengeは「Product Engineer Challenge」の略で、エンジニアだけでHOME'Sの新機能のプロトタイプを作るプロジェクトです。 開発は クリエイターの日 という社内制度を活用して、現在は半年ごとに7営業日の活動期間を確保しています。 2020年7月に発足し、プロトタイプを二度作り、現在ユーザーテストを実施しています。 プロジェクトの内容は企業秘密になるため、具体的な内容を書くことはできないのですが、今回の記事ではエンジニアだけで、どのように新機能のプロトタイプを作り、何に悩んだのかを書かせていただきます。 メンバー構成 エンジニアマネージャー:1人 エンジニア:4人 ここに記載しているエンジニアは、普段HOME'Sの開発をしているエンジニアの中から有志で集まったメンバーで構成されています。 自分たちで企画を行い技術選定ができるので、そこに魅力を感じて集まったメンバーが多い印象です。 開発を行うのはエンジニアの4人で、エンジニアマネージャーは、MTGの進行を務めプロジェクトの方向性を決めたり、社内での承認対応をしています。 どのように進めているのか? PEChallengeでは技術的な面ではなく、ビジネス的な面でのHOME'Sの課題をエンジニアリングで解決する事を目的としています。 そのために週次で全員で1時間MTGを開催し、HOME'Sのサービスとしての課題を定義し、エンジニアリングでの解決策を考え、プロトタイプの技術選定を行います。「どんな技術で何を作るのか」が決まると実際に開発に入ります。 開発は半年に一回、7営業日の時間を利用して進めているので、ここで一気に設計からプロトタイプ作成まで行います。 その後ユーザーテストや振り返りを実施し、プロダクトを作り直すのか、拡張させるのかを決めます。 このサイクルが半年で回るように進行しています。 チームがエンジニアメンバーのみで構成されるため、サービスの課題設定からプロトタイプ作成・検証まで行うことができ、非常にやりがいのあるプロジェクトです! 何が大変なのか? 設計が定まっていないと、開発が滞る このチームメンバーで初めてプロトタイプを作る際に、画面設計、API設計、DB設計を役割分担して行いました。 画面設計(2人)、API設計、DB設計の役割を決めた後に、同時進行で設計を進めてしまいました。 僕はAPIの設計を担当だったので、DB設計ををざっくりと頭で想像しながら、設計を行っていました。 しかしその後にDBの構成に変更を加えることになり、途中まで作り上げていたAPIの設計も大幅な修正をすることになりました。 教訓としては画面設計(2人)、API設計、DB設計を同時並行で進行させずに、一つ一つの設計をメンバーで議論、吟味して着実に進めることが大切だと感じました。 何をMVPにする? よく新規事業をするときに「MVPを作れ」と言われる事が多いかと思います。 MVPとは「minimum viable product」の略で、「価値を提供できる最小限のプロダクト」という事です。 今回のプロジェクトでは何を「実用的な最低限機能」とするのかということに度々つまりました。 新しい商品を作ろうとすると、どうしても「あんな機能も欲しい」とたくさん機能を追加したいという気持ちになります。 プロダクトを作る上で多くの人がこの問題に悩むかと思うのですが、僕たちも同じ問題に悩まされました。 そこで僕たちは再度課題に戻るために、「誰の、どんな課題を解決するのか」という問題に対して、以下の手順でアイデアを精査しました。 そもそも最も大きな課題は何か? 今の方法でその課題解決できているか? その方法は抵抗感なく使用してもらえるのか? 結果として、最も大きな課題だけを解決するためのMVPを作成する事ができました。 しかしここで安心してはいけません。 なぜならば、MVPを作成した後のユーザーテストを行った時に、再度アイデアが発散するからです。 ユーザーテストをすると、テスターの方から「こんな機能があったら嬉しいなー」などと意見をいただく事が多々あります。 それは非常にありがたい事なのですが、その意見を全て反映させていると、結局また「誰の、どんな課題を解決するのか」という部分がうやむやになってしまいます。 ですので、ユーザーテストで今回開発した機能が課題解決に結びついているのかを最優先で確認し、 ユーザーテストの結果を踏まえて再度メンバーで上記3つの手順に戻ることが大切です。 全てのステークホルダーを重んじれているか? LIFULL HOME'Sでは新機能を作る際に ユーザー(HOME'Sを使って住み替えをする人)とクライアント(HOME'Sに物件を載せている不動産会社) のどちらに対してもメリットが出せているかを考える必要がありました。 両者にとってメリットがある状態にする事はかなり難しく、解決策の立案に苦労しました。どちらの立場から見ても良いプロダクトにするために、僕たちは同じプロトタイプのテストを、ユーザー側とクライアント側の両方で行いました。 プロトタイプに対する両者の意見を取り入れて、どうすれば両者を立てたプロダクトができるのかを模索しております。 両者によって良いプロダクトを考えると、またアイデアが発散して混沌とした状態になってしまうので、 ユーザーテスト完了後、再度「誰の、どんな課題を解決するのか」という問題に戻りたいと思っています。 ユーザーテスト PEChallengeのユーザーテストの手順・結果は下記のようになりました。 手順(PEChallengeのユーザーテスト) テスターは、今回の新機能で解決する課題を持っていそうかで選定 テスター1人に対して対面でユーザーテストを実施(約30分) 1人のユーザーテストにチームメンバーが全員参加し、司会・書記を分担して行う 司会(PEChallengeメンバーの一人)がプロトタイプを使用する手順を一つずつ説明して、手順が終わる毎に質問する 「OOというボタンを押してください」 「期待通りに動作しましたか?、どのような動きだと良いと感じますか?」 「この機能に5段階で点数をつけるなら何点ですか?」 結果(PEChallengeのユーザーテスト) 1時間かけて2人に対してヒアリング取得 使い方を丁寧に説明しながら質問を重ねたので、機能を理解してもらった上で回答してもらえました テスターの方からの質問に対して、僕たちが随時回答することで、「それだったこんなアイデアの方が良くないですか?」という提案を頂くことも多く、質の高いフィードバックを得ることができました テスターの方に手順を一つ一つ説明し、その後に実際のプロトタイプの操作を実施してもらい、最後に質問をしていたので テスターの方が機能をしっかり理解した状態でヒアリングをする事ができました。 また1人のテスターに対して十分な時間を確保し、双方向にコミュニケーションをとれたため、より深くまで意見を聞くことができました。 自作アプリケーションで行ったユーザーテストとの比較 個人的な話になりますが、僕もプライベートの時間で自作アプリケーションを作成して、友人にユーザーテストを行うことがありました。今回PEChallengeで行ったユーザーテストと自作アプリケーションのユーザーテストの違いを比べて、学べる部分があったので、ここで少し書かせていただきます。 手順(石川の自作アプリケーションで行ったユーザーテスト) LINEで複数の友人に、自作アプリケーションのURLとGoogle form(アンケート)のURLを共有して回答してもらう 友人の選定は協力してくれそうかで判断 Google formに自作アプリケーションに対するアンケートを明記 アンケートの冒頭で自作アプリケーションの特徴と使用手順をざっくり説明 質問内容は以下2つ 「このアプリを使うとOOという課題が解決された状態になりますか?」 「このアプリを空き時間で使用したいですか」 選択肢を5段階で用意してチェックして回答してもらう 結果(石川の自作アプリケーションで行ったユーザーテスト) 1時間LINEで複数の友人にテストの依頼を行い、13件の回答を取得 機能と使い方の説明がざっくりであったため、自作アプリケーションの使い方自体がわからないという声が殺到 自作アプリケーションで実施したテストでは手軽に多くの回答を得ようとするあまり、テスターの方が機能を理解しないままテストが終了してしまう事がありました。 設計思想や使用用途を激詰めするような電話もいただきました笑(良い友人なので大事にします)。このようにテスターの方が感じた疑問に対して、双方向でコミュニケーションが取れなかったため、より細かいフィードバックを得ることができませんでした。 またテスターの選定においても違いがありました。自作アプリケーションのテストでは無差別に行い、PEChallengeのテストでは、開発した機能を使用したいと想定される人を中心に選定しました。 そのため後者のユーザテストの方が、テスターの方が自分事として捉えてテストを受けてくださったので、より深いフィードバックを得る事ができました。 今回のPEChallengeのユーザテストは不特定多数の人から手軽に回答を得る事ではなく、新機能を使うと想定される人に深く質問する事を意識していました。 そのため事前に「どのようにすれば実際に使用しているように感じられるのか?」や「どういう手順ならば機能を理解してもらえるか?」などを考え、 インタビューの流れや質問内容を吟味し設計していました。このように目的に合わせてテスト設計を行う事が必要な回答を得るために重要なのだと感じました。 まとめ 約1年間このプロジェクトをやってみて、使ってもらえる新機能をつくる事がこんなにも大変なのかと感じました。 実装の前に設計を確定させる事、迷ったら常に課題に立ち戻る事、適切なユーザテストを実施する事を肝に銘じてこれからも開発したいと思います。 今後新規事業や新機能開発をされる方やそれらで困っている方々のご参考になれば幸いです。 またLIFULLでは、PEChallengeのように 「エンジニアとして経営をリードする」 を体現したい方を募集しております。ご興味のある方はこちらのページもご覧ください! hrmos.co hrmos.co
はじめまして、品質改善推進ユニットの根本です。 ユニットではプロダクトや業務プロセスの品質を継続的にモニタリングし、改善計画の作成を支援していくパートナーシッププログラムという取り組みが始動しました。 詳しくは下記の記事をご覧ください。 www.lifull.blog モニタリングのスコープにはセキュリティも含まれます。今回は、このセキュリティのモニタリングに、スレットモデリングを取り入れる試みについて、ご紹介したいと思います。 課題 モニタリングの方法としては、システムを直接診断するもの、セキュリティにかかわる業務プロセスを診断するものが考えられます。例えば、システムを診断するものとしては、Webアプリケーションやプラットフォームの脆弱性診断 などがあげられ、業務プロセスを診断するものとしては、脆弱性への対応業務プロセスを整備状況や運用状況の面から評価するものなどがあげられます。 これらは、第三者もしくはツールが診断を実施し開発・運用チーム側にレポートすることが一般的です。そのためレポートされる開発・運用チーム側は受け身の姿勢になりがち、という状況が発生します。 第三者による客観的な診断結果は必須なものですが、最もシステムについて詳しいのは開発・運用チームですから、もったいない状況ともいえます。開発・運用チームがもつシステムそして業務プロセスに関する情報が診断の精度を上げることは間違いありません。 この課題について、スレットモデリングが解決の一助になるかもしれません。プロダクト開発・運用のステークホルダーが参加し、自らセキュリティ面の脅威(スレット)を洗い出していくところに効果を期待できるからです。 スレットモデリング スレットモデリングは、システムの設計段階で用いられる脅威の洗い出し・分析・評価の手法ですが、すでに運用に入ったシステムについても実施する価値があるといえます。大きなシステムの場合、どこに対して優先的にセキュリティ対策を実施していくかなど、限られたリソースを振り分ける際の判断材料になるからです。 スレットモデリングについて詳しく知りたい方は下記をご覧ください。 owasp.org 今回の試みでは二つのアプローチをとりました。 STRIDEモデルの活用 公開されているスレットモデル情報の活用 1.STRIDEモデルの活用 まず、DFD(データフロー図)の作成を通して、重要なデータの流れについて参加者間で情報を共有します。つぎに、STRIDEモデルとよばれる脅威を洗い出すための観点を通してデータの流れを追い、思いつく懸念点を出し合っていきます。この洗い出し作業を脅威ブレストと呼んで、DFD上に付箋紙を張る方法で進めました。 Microsoft のSTRIDE定義 出典) https://docs.microsoft.com/ja-jp/azure/security/develop/threat-modeling-tool-threats このアプローチでは多くの懸念点を出し合うことができました。一方、実施上の課題も見えてきました。 当初は抽象度の高いDFDからはじめ、段階を踏んで具体性を高め、それに合わせて洗い出す脅威の具体性も高めていく予定でした。しかし、システムと常に向かい合う開発・運用チームはすでに具体的な懸念点を持っており、脅威ブレストよりも既知の懸念点を直接リスト化する方が効率的でした。 このように、すでに具体的な懸念点が認識されている場合、必然的にそちらにフォーカスすることになるためデメリットが生じました。新たな脅威を見つけ出すことが手薄になる点です。STRIDEで脅威を洗い出していくには、練度を上げることが必要と感じました。 また、脅威ブレストにしろ、既知の懸念点のリスト化にしろ、そこで出てきたものが本当に脅威であるかは、さらに踏み込んだ調査が必要となりました。短い開発サイクルで多くの機能を実装・改修する開発・運用チームにとっては、この活動のためのリソース確保が最大の課題といえます。 2.公開されているスレットモデル情報の活用 特定の技術については、すでにスレットモデルが検討され公開されているものがあります。今回の試みでは、OAuth2.0 に関する下記の文書を活用することができました。 datatracker.ietf.org 文書の扱いには作法があり、少し文書自体について説明をします。 この文書は、現在インターネットドラフトという状態で、まだ作業が進行中(work in progress)の文書です。2016年11月から作成され始め2021年4月にはドラフトの18版がでました。文書内に、この18版の有効期限は2021年10月と記されています。 また、BCP(Best Current Practice)という種類の文書に属し、OAuth2.0実装におけるセキュリティ面のベストプラクティスを検討している文書ということになります。 文書の第2章には実装時のセキュリティに関する推奨事項がまとめられています。内容理解にはOAuth2.0に関する前提知識が必要とされますが、OAuth2.0については書籍の出版もあり、インターネット上からも多くの情報を得ることができるので、それらを参照しながら理解を進めていくことができます。 第3章ではどのような攻撃者を想定する必要があるのか確認することができ、第4章では具体的な脅威および対策について知ることができます。 第2章の推奨事項や第4章の対策事項は「MUST(NOT)」や「SHOULD」などの形で表現され、対策の必要性について強弱が分かるようになっています。これらの表現が対策優先度の判断において拠りどころとなり、たいへん便利といえます。各表現の定義は、RFC2119、RFC8174で確認することができます。 出典) https://datatracker.ietf.org/doc/draft-ietf-oauth-security-topics/ datatracker.ietf.org datatracker.ietf.org 今回の試みでは、モニタリング対象のシステムに当てはまる脅威を文書から探し出し、先の「MUST(NOT)」や「SHOULD」を考慮しながら確認項目をリストアップすることができました。 このような文書を活用できるのは、脅威の考慮漏れを防ぐという面でも大変有効だと感じられます。また、具体的な対策まで知ることができるので脅威を洗い出した後の対策検討も楽になります。 一方、このアプローチにおいても課題がないわけではありません。先ほど「システムに当てはまる脅威」と書きましたが、OAuth2.0の実装の詳細を知るために、DFDよりも詳しいシーケンス図を必要としました。開発チームからは詳細な図を提供いただき確認項目のリストアップが可能になりました。 まとめ ブレストを通してざっくばらんに懸念事項を出していくアプローチ、特定の技術について公開された文書から核心部を確認していくアプローチ、両方にメリットがあることは確かだと感じました。 そして、スレットモデリングという手法にトライしながら、脅威があるかもしれない事項に気づいたとき、気づいた脅威に特化してその有無を検証する作業が必要になりそうだと感じました。 スレットモデリングの方法として、STRIDEとともに紹介されることのあるPASTAという方法が有効ではないかと考えています。 今回は、セキュリティのモニタリングにスレットモデリングを取り入れる試みについて、大まかに紹介させていただきました。 この試みをすすめるなかで、ご紹介できるような失敗談、成功事例などが出てくると思います。それらを、また別の機会にご紹介できればと思います。 LIFULLでは共に成長できるような仲間を募っています。 よろしければこちらのページもご覧ください。 hrmos.co hrmos.co
こんにちは。テクノロジー本部のyoshikawaです。好きなW3C Recommendation は RDF 1.1 Concepts and Abstract Syntax です。 会議やチャットでのやり取りの決定事項・議事録、アプリケーションや機能の設計書・仕様書、READMEなどなど... LIFULLの開発現場においては、ソースコード以外にもこのように様々な文書の管理・蓄積(=ドキュメンテーション)を実施しています。 多くの開発者・メンバーがドキュメンテーションの重要性やその恩恵は理解はしているものの、なかなかうまく情報の蓄積・管理ができない、 その結果、本質的ではない調査に時間を取られてしまいDeveloper Experienceが下落してしまう。 このような課題を抱えているプロジェクトやチームは世の開発現場において少なからず存在すると思います。 LIFULLの開発現場にもこの課題は当てはまります。 私が参加しているバックエンド刷新プロジェクトではドキュメンテーションにまつわる課題を解決すべく様々な取り組みを行ってきました。 この記事では私が参加しているバックエンド刷新プロジェクトを中心に実施している、継続的なドキュメンテーションを可能にする仕組みについて紹介します。 バックエンド刷新プロジェクトについてはこちらの記事をご覧ください。Clean Architectureを採用しバックエンドAPI開発を行っています。 www.lifull.blog 想定している対象読者 ドキュメンテーションをうまく機能させるための仕組みやヒントを知りたい人 社内WikiやREADME(Markdownファイル)でのドキュメントの作成と管理に限界を感じている人 GitHub Discussionsの活用事例を知りたい人 どうやってドキュメンテーションを実施しているのか LIFULLでは主に社内Wikiツールを利用してドキュメンテーションを実施しています。 メンバーがエンジニアのみで構成されているチームでは専用GitHub Repositoryを作成しMarkdownファイルをバージョン管理したり、 GitHub Wikiなどの機能を活用しているケースもあります。バックエンド刷新プロジェクトもそのケースの一つです。 現在は主に社内Wiki、ドキュメンテーション専用GitHub Repository、そしてGitHub Discussionsの3つをツールとして活用しドキュメンテーションを実施しています。 ドキュメントの性質とツールの使い分け ドキュメントの性質によって、バックエンド刷新プロジェクトでは以下のようにツールを使い分けています。 以下で挙げているツール以外にGitHub Wikiも利用していた時期もありました。記事の本題と逸れるため経緯は割愛しますがGitHub Repositoryへと移行しています。 社内Wiki: 技術要素が薄くエンジニア職以外が見ることを想定しているもの、便宜上社内Wiki内の機能を利用したいもの 例: プロジェクト憲章、Retrospective資料 GitHub Repository: 技術的な内容に関する規約、ルール、ベストプラクティスや学習資料など、「決まりきったもの」 例: コーディング規約、推奨実装パターン、Clean Architecture学習資料 GitHub Discussions: 技術的な内容に関するメモやログ、構想など、「とりあえず記録しておきたいもの」 例: アーキテクチャに関する規約やパターンの提案、決定事項のメモ(Architecture Decision Records) このように社内Wikiは必要性が生じた際に利用し、なるべくGitHub上に情報を蓄積させていく運用をしています。 当初は通常のソースコード管理と同様に、GitHub Repositoryで全てのドキュメントのバージョン管理を実施していましたが、これからお伝えするような「辛さ」が生じてしまったために、 「決まりきったもの」はRepository内に、「とりあえず記録したいもの」はArchitecture Decision Recordsの考えの下、GitHub Discussionsに蓄積する運用に変更しました。 GitHub Repositoryだけでドキュメントを管理してみた結果と課題 どうやって運用してきたのか 当初はGitHub Repositoryのみで技術的なドキュメントを管理していました。 個人ブログや各種ブログサービスの記事管理と同じように、通常のソースコードと同様にドキュメント(.mdファイル)を管理するというものです。 ドキュメンテーション専用Github Repository ドキュメントが作成・更新されるまで ドキュメントの作成や更新の際には、ドキュメントの体裁が崩れることや用語の表記揺れを防ぐためにtextlintというライブラリを利用してドキュメントのフォーマットを実施しています。 github.com 下記のように設定ファイルを作成し体裁や表記の揺らぎを防止しています。 version : 1 rules : - expected : Library patterns : - ライブラリ - expected : Application patterns : - アプリケーション - expected : CleanArchitecture patterns : - clean architecture - Clean architecture - Clean Architecture - クリーンアーキテクチャ - クリーンアーキテクチャー ローカルではnpm script, pushした後もGitHub Actionsでtextlintを実行&規約指摘するように設定し、 文章の体裁やフォーマットの揺らぎを防ぎつつ、ドキュメントの作成・更新を実施してきました。 ドキュメント中の文章の体裁やフォーマットだけでなく、ドキュメントのファイル名やドキュメントの階層構造の適切さもレビュー時にチェックするようレビュー体制の運用もしてきました。 この一連の厳格なドキュメンテーション更新フローによって読者に優しく読みやすいドキュメントを提供できます。 しかし、厳格なドキュメンテーションのフローを変更の多いプロジェクトにおいて適用することはドキュメント提供者への負荷となり得ます。 浮上した課題: 書くのが「辛い」 ドキュメンテーションに対して課題を持ちながらも、開発者は人間なので構造化され整ったドキュメントを書くことが辛いということもあります。 実際に運用しているとちょっとしたドキュメントの変更をする際にもtextlintからの厳格な指摘をpassする必要があり、「文章を書く辛さ」が目立つようになりました。 textlintの設定を緩和すれば多少の改善になりますが、ドキュメントの品質は維持したいため根本的な解決にはなりません。 文章を書く辛さ以外にも、「階層構造を維持する辛さ」もまた見逃すことはできませんでした。 意気揚々とブログを始めて最初は丁寧に記事の階層構造やカテゴリ管理をしていたがやがて面倒になった、そんな経験を持ったことがある方もいるかと思います。 ドキュメンテーション不全が招くディストピア ステークホルダーが多いため、仕様変更や実装規約、推奨実装パターンなどの変更をなるべく最新の状態に保つ必要があるという、バックエンド刷新プロジェクトの性質上、 変更の頻度の多さに乗じて膨れ上がるこの辛さは無視できるものではありません。 ドキュメントを書くことが辛くなると、ドキュメンテーション専用Repositoryを触る/見るのが辛くなります。 開発プロセスにおいて、往々にしてドキュメンテーションは優先度が低くなり、後回しにされがちです。 やがて優先度が低くて誰も更新したがらないドキュメンテーション専用Repositoryが出来上がります。 そして誰も更新しないのでRepository内のドキュメントは陳腐化し、ドキュメントにすべき知識は個人のナレッジとして埋没してナレッジの共有が機能不全に陥り、 挙句には調査工数として新規開発者にそのツケがのしかかることでしょう。 実際にはさほど深刻な状態にはなっていませんでしたが、「ちゃんとした文章を書くのが辛い」ことに起因してナレッジの共有が失敗することは無視できないリスクです。 解決策 開発者ガイドラインを敷くことで紳士協定的の名の下にドキュメンテーションを強制するのではなく、 そして、ドキュメントとして機能するような適度にまとまった文書を作成可能でありながら、ドキュメンテーションの辛さを解消できる別の仕組みを用意できないか? それこそが GitHub Discussions を利用した Architcture Decision Records(ADR) です。 docs.github.com GitHub DiscussionsでのADR ADRとは? 以下はThoughtworksのTechnology Radarからの引用です。 Much documentation can be replaced with highly readable code and tests. In a world of evolutionary architecture, however, it's important to record certain design decisions for the benefit of future team members as well as for external oversight. Lightweight Architecture Decision Records is a technique for capturing important architectural decisions along with their context and consequences. We recommend storing these details in source control, instead of a wiki or website, as then they can provide a record that remains in sync with the code itself. For most projects, we see no reason why you wouldn't want to use this technique. www.thoughtworks.com バックエンド刷新チームでは以下のことに着目してADRの考え方をドキュメンテーションに取り入れました。 決定事項の経緯や背景を第三者が閲覧可能 軽量なドキュメンテーション 第三者が簡単にコメント、編集可能 元の定義ではアーキテクチャに関する決定事項やその背景を記録することに焦点を当てていますが、バックエンド刷新チームでは実装に関する事柄も含めアーキテクチャ以外の事柄でも記録しています。 GitHub Discussionsを採用する プロジェクトメンバーも、ステークホルダーもエンジニアが中心であるため、GitHubが提供する仕組みを利用してADRを実現することは自然な流れでした。 そして、スレッド形式で簡単にドキュメントの作成、第三者の編集/コメントが可能であり、ドキュメントをカテゴライズ、タグ付け可能なGitHub Discussionsを採用しました。 以下はDDD(ドメイン駆動開発)におけるDomain Serviceを巡ってのADRの実例です。 ADRの実例. とりあえず残しておきたいことをメモしています なお採用当初、GitHub DiscussionsはBeta版でしたが2021年8月17日にBeta版から正式版になりました。 github.blog GitHub Discussions × ADRを実践してみた効果 意図していたドキュメンテーションの負荷削減に加え、コミュニケーションにおいて意図していなかった効果がありました。 とりあえず残しておきたいことのドキュメンテーションが楽になった 大事なことだけど、とりあえず書き殴りのメモで残しておきたい、埋もれがちなテキストチャット上でのやりとりを保存しておきたい、 といったことを気軽に残せるようになりました。 その結果、大事な情報が個人のナレッジとして埋没してしまう機会が減りました。 下記のように、様々な粒度・トピックの内容を気兼ねなく残せています。 GitHub Discussions上にあるスレッド一覧 よって、当初課題となっていた「文章を書く辛さ」はGitHub Discussions × ADRによって狙い通りに克服できました。 Repositoryにあるドキュメントの管理も楽になる ADRを取り入れていなかった以前、日数が経ってからドキュメンテーションをする場合は何を書くべきか思い出す/書くべきことを関係者にヒアリングすることが必要であり、 Repository上に残しておきたいような体裁の整ったドキュメントを作成するコストが高くなっていました。 ADRとして「とりあえず」残しておいた情報があることで、そのようなコストが発生することを予防できます。 なお、RepositoryはDiscussionsを採用した後も「決まりきったもの」を残す場として活用し続けています。 事例こそ多くありませんが、Discussionsで記載された「とりあえず残したいもの」を「決まりきったもの」としてRepositoryに残すという運用を実施しています。 スレッドを階層構造ではなくラベリングやタグ付けで管理できる ドキュメントを見つけやすくするためにもドキュメントに階層構造などのメタ情報を持たせることは重要です。 以前の運用ではドキュメントをディレクトリに格納し階層構造持たせていたため、やや管理コストがかかっていました。(ドキュメントの階層構造を変更するためにcommitする必要がある) GitHub Discussionsで管理した場合、カスタムのラベルやタグによって各スレッドを管理・検索できるため、ドキュメントのメタ情報の管理コストが低くなりました。 そのため、第二の辛さである「階層構造を維持する辛さ」も解決することができました。 予定外の効果: 部署間のコミュニケーションチャンネルが増えた 当初は意図していませんでしたが、GitHub Discussionsを採用したことによる恩恵もありました。 プロジェクト内でのADRとして利用してきましたが、プロジェクト外の方でも広く閲覧可能&コメント可能にしてあります。 そのため、プロジェクト外の方からのフィードバックをいただけるような機会が増え、ドキュメントの質を向上させることに繋がりました。 また、チャットツール(Slackなど)で発生した他部署からの質問対応のやりとりをGitHub Discussionに転載・蓄積・転用することでコミュニケーションコストの削減にも役立っています。 現在はバックエンド刷新チームがモデレーターとなり新バックエンド基盤(新BFF)の開発コミュニティを運営していますが、 今後は開発者が増え、社内開発者コミュニティとして醸成されゆくことを期待しています。 カテゴリ一覧. プロジェクト外の方も見やすいようにカテゴライズ おわりに 以上がバックエンド刷新チームで実施しているドキュメンテーションです。 先日Beta版から正式版となったばかりということもあり、GitHub Discussionsは社外/社内どちらからの視点でもその採用事例は多くはないです。 しかしその効果は確かなもので、本記事で紹介したドキュメンテーションとしての用途の他にも、著名なOSSコミュニティでもコミュニケーションフォーラムとして利用されています。 ドキュメンテーションで悩む方、あるいはGitHub Discussionsの利点がわからない、といった方に本記事が参考になれば幸いです。
こんにちは。LIFULL でネイティブアプリのスペシャリストをしている菊地です。 今回は LIFULL HOME'S アプリにおけるプッシュ通知の役割やアーキテクチャの変遷についてご紹介させていただきます。 一般的にスマートフォンアプリにとって プッシュ通知 というのはユーザーとのコミュニケーションのために重要な役割を持っています。 SNS などでコメントやメッセージが来た際にリアルタイムに気付くための通知 ゲームやマンガアプリなどで、時間によって回復するライフなどが回復したことを知らせる通知 サービス内における重要な情報に気付いてもらうための通知 EC やオークションアプリなどで気になる商品の値段が下がったり、高値がついた場合にお知らせする通知 など様々なシーン、目的で使われています。 LIFULL HOME'S アプリにおけるプッシュ通知とは LIFULL HOME'S アプリでは、どのようなシーン、目的で使っているかというと 住まい探しをしているが条件はほぼ決まっており物件が出てくるのを待っているユーザーに対して、最新の情報を提供する 気になっている物件について掲載が終了してしまって見れなくならないように期限をお知らせすることで見逃さないようにする サービスからユーザーに対して重要な内容を告知する ある行動をした際に次のステップにつなげてもらうための通知 一定期間アプリを利用していないユーザーに対して、アプリに戻ってきてもらうための通知 などがあります。 その中でも今回は 1 の新着物件通知 と 2 の掲載期限通知 と呼ばれる「ユーザーに対して有益な情報を提供」するための通知をご紹介します。 新着物件通知 目的 ユーザーが自分の探している条件で毎回アプリを立ち上げて探す手間を省く 探している条件で新しい物件が出てきたタイミングでユーザーのアプリの起動を促す Android アプリ 配信時間 :朝、昼、夜の3つの時間帯で指定可能 配信条件 :アプリ内で 保存した検索条件 がある場合はその中から新着物件を。保存した検索条件がなければ 前回検索条件 から新着物件を検索して通知する ※ Android では 保存した検索条件 もしくは 前回検索条件 のどちらか一つの条件で送る仕様 iOS アプリ 配信時間 :夜のみ 配信条件 : 保存した検索条件 で「通知を受け取る」にチェックを入れたものの新着物件を検索して通知する ※ iOS では複数の 保存した検索条件 をまとめて送る仕様 掲載期限通知 目的 ユーザーがお気に入りに登録している物件の掲載がいつの間にか切れてしまい問合せを失ってしまうという機会損失を減らす 問合せの機会損失を減らしつつ、ユーザーがアプリを起動するきっかけを作る 配信時間 :夕方 配信条件 :お気に入りに登録している物件の掲載期限を確認して、期限切れ数日前の物件があれば通知する ※ Android のみ アーキテクチャの変遷 初期 開発工数の関係で、プッシュ通知ではなくアプリ内で実装を行い、バックグラウンドで定期的に処理を走らせてローカル通知を行なっていました。 ただし、毎回バックグラウンドで処理をして API を呼び出して受け取った結果を通知するため、導入コストは低かった反面、改修する際のコストは高くなっていきました。 具体的には、A/B テストの実施のたびにリリースが必要となることや、通知を送るための条件や内容を変更するたびにリリースが必要となるといったことが挙げられます。 さらに、Android の場合は OS のアップデートにより、バックグラウンド処理に対する制限が厳しくなっていきました。何も対処をしないと バックグラウンドで API を呼び出している間にプロセスが終了してしまい通知が行われない 通知の対象とならなかったため通知されなかったのか?通知の対象となっていたが通知が行われなかったのか?の判別が困難 指定時刻に通知を行いたいのに、ユーザーがアプリを立ち上げた瞬間などに突然通知が行われる という問題が出てきました。 このままではユーザー体験としておかしくなるため、改修を重ねて行きましたが、継続的に改修をしようとすればするほどサーバーサイドでロジックを持ち自由に A/B テストができる環境を求める声がチーム内で強くなってきました。 そこでプッシュ通知に移行することを検討したのですが、要件として 新着物件通知 :ユーザー毎の検索条件に合わせた新着物件 掲載期限通知 :ユーザー毎のお気に入り物件の掲載期限 といったユーザーごとに違う情報を用いて通知を行う必要がありました。 最初に検討した Firebase ではユーザーセグメント単位での通知は簡単に利用することができますが、ユーザー毎に違うデータを元に通知を送るということが難しいため、サーバー側でサードパーティーのプッシュ通知を送る必要が出てきました。 移行期 ローカル通知における課題などを解決するにあたり、プッシュ通知として今後どういうことを実現するか?という要件定義から行って、新たに仕様を作ることになりました。 様々な要件を定義して施策を行ったのですが、わかりやすいものとしては「配信時間帯(朝・昼・夜)の中でもユーザー毎に開封してもらいやすいタイミングに合わせて配信する」というものがあります。 新着物件 及び 掲載期限通知 それぞれで朝・昼・夜(夕方)という配信時間帯の中でも「ユーザーのライフスタイルに合わせてスマートフォンをみる時間にはばらつきがあるため、朝・昼・夜(夕方)ごとに基準となる配信時間を設けて、そこからユーザー毎に時間をずらすことで開封率の向上を狙うということを行いました。 これを実現するためには 時間帯別の配信リストを作成する 配信時間帯毎に配信リストを処理する ユーザー毎に異なる条件を元に検索を行い、通知を送る という手順を踏む必要がありました。 この時に出来る限りサーバーレスで、かつ今後も継続的に改修がしやすい構成でと考え、Cloud Functions をベースとして Cloud PubSub と組み合わせた構成に移行しました。 アーキテクチャ 時間帯別の配信リストの作成 時間帯別の配信処理 メリット 処理毎に疎結合となっているため、テストや改修が非常にしやすい 今後の改修でアーキテクチャを移行することになっても一部のみ切り替えということが可能になるため、メンテナンス性が非常に高い サーバーレスのみで構成しているため、通知配信用のサーバーなどを用意する必要がなく運用の負担が低い デメリット 配信リストの作成、時間帯別の配信処理毎に Cloud Scheduler が存在してしまうため、管理が大変になる ユーザー数が増加した場合や処理が複雑になった場合に、Cloud Functions の実行時間の制限に引っかかる恐れがある Cloud Firestore の Read / Write の頻度が高く、単位時間あたりの制限に引っかかる恐れがある API server に対して、Cloud Functions からのリクエスト制限をかけるのが難しいため、大量のリクエストが同時に発生する恐れがある 現在 移行期のアーキテクチャでも運用はできていたのですが、プッシュ通知をより使いやすくと改修を繰り返していくうちに想定よりも早い段階で、移行期のアーキテクチャのデメリットとしてあげていた「ユーザー数が増加した場合や処理が複雑になった場合に、Cloud Functions の実行時間の制限に引っかかる恐れがある」という懸念が現実の問題となり始めていました。 元々、Cloud Functions の実行時間の制限を回避するために、Cloud Functions -> Cloud Pub/Sub で配信対象ユーザーの抽出を段階的に行なっていましたが、一度に処理できる量の問題や処理の回数が増えてきてしまい途中で失敗するといったことが懸念としてありました。 また、該当部分のロジックは特にスケールする必要もなく Cloud Functions でなくてもよいため、より実行時間の制限が長い Cloud Run での抽出に移行することになりました。 アーキテクチャ Cloud Run + Cloud Tasks + Cloud Functions 処理の流れとしては Cloud Scheduler-> Cloud Run で配信時間帯毎にユーザー抽出を行い、配信時間帯の中でさらにユーザーごとに時間を調整して Cloud Tasks にタスクを追加する Cloud Tasks では設定された時刻になるとタスクが実行され、Cloud Functionsを呼び出す Cloud Functions は Cloud Firestore にアクセスを行い、通知に必要となるデータの取得や加工を行い、FCM に通知を送る という流れになります。 メリット Cloud Functions から Cloud Run にしたことで、実行時間の制限が緩和された Cloud Scheduler から Cloud Tasks にしたことで、管理コストが減少 エラー発生時の再送処理などを全て Cloud Tasks に任せられるようになった API server へのアクセスのスロットリングを Cloud Tasks で簡単に調整できるようになった デメリット Cloud Functions は Typescript、Cloud Runは golangと別の言語で作ってしまったため、開発に学習が必要になった(チームのエンジニアに学習機会を提供するという目的もあったので負債ではない) 処理の流れも、構成も移行期のものよりもだいぶスッキリしたものとなりました。 さらに懸念されていた処理量の増加についても問題なく処理ができるパフォーマンスを出せているため、当分はこの構成でユーザー毎にパーソナライズされた通知を配信していくことになると思います。 最後に 今回は LIFULL HOME'S アプリを支えるプッシュ通知について、実際に行っているプッシュ通知の例とアーキテクチャの変遷をご紹介させていただきました。 ご紹介したものはローカル通知でも実現可能ではありますが、プッシュ通知にすることで、より良い体験を継続的に提供できるようにすることができました。LIFULL HOME'S アプリではサービスの成長に合わせて施策が実行できるようにするためにアーキテクチャの刷新を継続的に行っています。 また、紹介した通知以外にもアプリでは様々な通知を行なっており、Firebase を用いたユーザーセグメントに対する通知や、ユーザーの行動をトリガーとしたリアルタイムな通知なども行なっております。 プッシュ通知は便利な反面、送り過ぎてしまうとユーザーにとって有益なものでなくなってしまう場合もあるため、今後もカスタマイズを続けていきユーザーにとって最適なタイミングで最良の情報を提供できるようにしていきたいと思います。 LIFULLではメンバーを募集しております! カジュアル面談もありますのでご興味ある方は是非ご参加ください! hrmos.co
こんにちは。プロダクトエンジニアリング部の加藤です。 皆さん、リモートでのチームビルディングはどのように行っていますか? 弊社では本格的にリモートワークを導入し一年が経過したところとなりますが、リモート環境下でのコミュニケーションや組織形成の課題に対しさまざまな解決策を模索し取り組んできています。 そのような中、今回は競技プログラミングを用いたチームビルディングを行ったので紹介したいと思います。 どのように行ったか 今回の主な目的はチームの結束力の強化です。 部署のメンバーを複数のチームに分け、一つの問題をチームメンバーで協力して解答し勝敗を競うチーム対抗戦の方式にて実施しました。 題材として「AtCoder」の過去問を、コミュニケーションツールとして「Zoom」を利用しました。 atcoder.jp 基本ルール 3人1組のチーム対抗戦 40分の間に獲得した得点により勝敗を決定 得点は問題の難易度により設定(事前に運営が問題を複数ピックアップ) 問題に正解することで設定された得点を獲得 言語の選択は自由 チームの中で実際にコードを書くのは一人だけ(モブプロ方式) コードを書く人が画面共有を行う 途中で役割の変更はOK やってみてどうだったか やってみて良かった点、イマイチだった点・改善点は以下の通りです。 良かった点 業務で接する機会が少ないメンバーともコミュニケーションが取りやすかった 複数人で協力してコーディングする機会を強制的に設けられたことでモブプロへのハードルが下がったように感じられた 業務でもモブプロ・ペアプロを積極的に導入することで知識共有の効率化が図れそう 単純に楽しかった! 業務とは違った頭の使い方ができて刺激的だった イマイチだった点・改善点 40分では時間が短かった チーム内に一人実力者がいると力が偏ってしまい協力が難しい 標準入力の取得方法などAtCoder独自の利用方法の把握に手こずった 改善して再トライ! 実施後のアンケート結果から、チーム内にて経験値や知識量に差があると協力体制を築くことが難しいと分かりました。 そこで、チーム内での知識の偏りを減らし、なるべく各メンバーが活躍できる機会を設けるために新たに以下のルールを追加し再トライしました。 各チーム3言語以上利用すること 各チームランダムに縛りを適用(ワンライナーにて解答、if・for禁止など) これにより会話が増えて距離が縮まったという意見もあり、よりチームビルディングとしての効果が高まったように思います。 まとめ 今回はチームの結束力を強めるため実施したチームビルディングについて紹介をさせていただきました。 リモートワークの普及により業務効率化などのメリットが生まれる一方で、いまだコミュニケーションや組織形成の課題を抱える組織も多くあるかと思います。 今回紹介した取り組みが課題解決の一つの手段として参考になれば幸いです。
こんにちは。QAグループ所属のQAエンジニア松谷(まつや)です。 LIFULLでは新卒エンジニアに27日間の研修を行なっています。 その研修の中で、 丸一日を使ったテストワークショップ も行われています。 今回はそのテストワークショップについてご紹介します。 キーワードは「テストを考えられる」 です。 LIFULLの開発体制とQAグループについて まずは認識を合わせるためにLIFULLの開発体制とQAグループの業務について説明します。 LIFULLでは月に200件ほどの施策がリリースされています。 それら施策は、主に企画者、開発者、デザイナーの三職種のメンバーで構成されています。 ここでお伝えしたいことは、 テスト専門のメンバーは基本的にはいない ということです。 リリースする施策については、 施策のメンバーが責任を持ってテスト計画〜実行までを行っています。 数年前は第三者検証が主流だったため珍しい形でしたが、昨今のスクラムの形ではよくある形かと考えます。 ここでテスト=QAと思われている方は、QAグループが何を行なっているか疑問に思われるかもしれません。 QAグループは社内横断組織であり、各所の品質保証活動のサポートを行なっています。 例えば、施策のテスト計画の手伝い、品質保証についての相談などです。 以下の QMファンネルというモデルの「QAコーチ」「QAコンサルタント」 にあたります。 (テスト=QAの認識の方は、このモデルの「フェーズゲートQA」部分のみにフォーカスしていそうです) (出典 : 品質を加速させるために、テスターを増やす前から考えるべきQMファンネルの話(3D版) Yasuharu Nishi) テストワークショップについて テストの考え方を伝えている エンジニア志望の方々は、学校やプライベートで開発については深く学んできています。 ですが、テストについて体系立てて学んできた方は多くないのが現状です。 結果、 実装したものが実装した通り動くかチェックすることのみがテストの全てであるという認識の方もいます。 Unit Testの責任範囲ではそのように言えるかもしれませんが、企業が提供するシステム全体に対するテストとしてはそれでは不十分です。 テストワークショップでは 全体を通してのテストをどのように考えていけばよいかという「考え方」を中心に説明 しています。 教える内容はJSTQBに(基本的には)準拠 教える内容は基本的には JSTQB (国際的なテスト技術者認定資格ISTQBの日本版)に準拠しています。 わかりやすくするためにそのままの定義を伝えるのではなく、例などを用いてわかりやすい言葉に噛み砕いて説明を行います。 またJSTQBの全項目を教えているわけでもありません。大事なところをピックアップして伝えています。 (参考: JSTQB Foundation Level version2018V3.1.J03 ) JSTQBに沿ってお伝えしている理由は以下です。 正しいテストの知識 世界中のどこでも通用するテストの考え方 これらを身につけてから業務に入っていただきたいと考えています。 それにより「JSTQBではこのように言われていることが、LIFULLではこう実践されているのか」とわかりやすくなるためです。 テストプロセスを伝えている テストをあまり知らない方の場合、テスト実行することだけがテストだと思っていることもあります。 また新卒研修の場合、最初にテスト実行をやってもらうのだから実行工程のやり方を細かく教えよう、という会社もあります。 LIFULLのエンジニアとしては、与えられたことを与えられた通りやれるだけではなく、テストを考えられるエンジニアになって欲しい のです。 よってテスト実行のやり方だけではなく、「何をどうテストするのかを考える」ということを伝えるため、テスト分析からテスト実装の流れ、つまりテストプロセスを使ってお伝えしています。 テストプロセスを知ることで、テストについて何をどう考えていけばよいかの道筋がわかる ためです。 (テストプロセスについては JSTQB Foundation Level version2018V3.1.J03 P19〜参照) 各項目ごとに(ほぼ)ワークがある 教えている項目は多岐に渡りますが、 それぞれの項目でワークがあります。 そこで実際に考えてみて手を動かしてもらいます。 個人ワークを行ってもらった後に、少人数グループでのディスカッションを行ってもらいます。 これは、 個人でしっかりと考えた後に周りのメンバーと話し合うことで、他者の意見から新しい気づきを得たり理解を深めやすくなるから です。 ワークの一例を記載します。 以下は「マイヤーズの三角形」と呼ばれる問題です。 (出典:ソフトウェア・テストの技法第2版 Glenford J. Myers) テストワークショップで、テストの考え方を伝える前に行っているワークです。 このワークは一見すると簡単そうです。 ですが 「テストは仕様通り動くことを確認すればOK」と考える方がひっかかる問題 です。 またグループディスカッションでは、入力値以外にも動作環境の観点も挙がりました。 こういった話も踏まえ、 テストで考えるべきことは意外と多いことをお伝えしています。 最終ワーク テストワークショップの最後には おおよそ3時間ほどの本格的なテストの実習 があります。 QAグループが作ったテスト用プロダクトに対して、少人数のグループで実際に以下のことを行なってもらいます。 仕様把握、テスト分析 テスト設計 テスト実装 テスト実行 / 不具合起票 グループ発表 これらは学んだことを総動員しなければいけません。 とはいえ、ただ「やってください」といっても皆さん不慣れですので動けません。 そこで各プロセスをどう考えていけばよいかのヒントは出しています。 ただ大まかなヒントなので、 グループ内で考え、話し合い、協力しながらでなければ決められた時間での進行は難しい ようになっています。 グループ発表では以下の内容で発表してもらっています。 何を重要と考えたか なぜ重要と考えたか どうテストをしたのか 発見したバグ 良かった点 悪かった点 最後に、最終ワークの私の所感を記載して終わります。 3時間という限られた時間でしたが、作成されたテストケースでは重要なポイントの確認は押さえられており、仕様をなぞったテストだけでは見つけられない問題も見つけられるものとなっていました。 また「◯◯を確認したいから、このように確認する」といったテストの意図が第三者にも伝わるテストケースです。 そういったテストケースを書けていますので、発表でも「こういった理由でここが重要なので、このようにテストを考えていった」と自分たちの考えと実施したテストについて説明ができていました。 もちろん全体的には荒削りなところも多いですが、最初の「実装したものが実装した通り動けばいいのではないか」の状態から、テストを考えられるようになっていることを感じ取ることができました。 まとめ 何をテストすればよいのか、それらをどのようにテストをするのか。 これらが考えられなければ、思考を放棄し仕様をなぞるだけのテスト実施になり、抜け漏れが多かったり非効率なテストになってしまうことでしょう。 それにより企業として信頼を失ってしまうような大問題を発生させてしまうかもしれません。 「テストは仕様通り動くかだけを確認すればいい」という考えから、何をどうテストしていけばよいか考えられるようになるためのテストワークショップの話でした。 LIFULLでは、何をどうすればよいか自ら考えられるエンジニアを育成していきたいのです。 このブログの話はLIFULL主催のLtech#19でもお話しさせていただきました。 ご興味がある方はスライドをご覧ください。 LIFULLでは新卒エンジニアに 丸一日のテスト研修を行なっている from LIFULL Co., Ltd. www.slideshare.net 最後に教えている項目を列挙します。ご参考になりましたら幸いです。 なぜテストをするのか マイヤーズの三角形問題 テストプロセス テストレベル / テストタイプ レビュー コードレビュー テスト技法 ホワイトボックステスト C0カバレッジ C1カバレッジ ブラックボックステスト 同値分割 境界値分析 デシジョンテーブル オールペア リスク バグ管理 テストケースの書き方 テスト実習
こんにちは!Ltech運営チームの引持です。今回は、2021年8月19日(木)に開催した「QA Talk Night~LIFULL HOME'Sを支える品質保証の取り組み~」についてレポートします。 lifull.connpass.com Ltechとは Ltech(エルテック)とは、LIFULLがお送りする、技術欲をFULLにするイベントです。特定の技術に偏らず、様々な技術の話を展開していく予定です。 品質保証の取り組み Ltech#19のテーマは、LIFULLでの品質保証の取り組みについてです。LIFULL内で品質保証を担当するエンジニアに、SaPIDの導入についてや新卒エンジニアのテスト研修についてを語っていただきました! SaPID を導入するまでとそれから 最初の発表はソフトウェアプロセス改善手法「SaPID」の導入までの遍歴と導入してからの工夫についてのお話です。 SaPID を導入するまでとそれから from LIFULL Co., Ltd. www.slideshare.net 自チームへSaPIDを導入するにあたっての背景、課題の洗い出しから実際の導入、導入した結果、そしてさらなる課題まで時系列に沿って話して頂きました。 導入したメリットとして、問題分析の癖がつくことやチームの課題に対する認識共有がしやすくなった等が挙げられており、個人だけではなくチームとしても成長できる良い手法だと感じました。 発表を聞いて私自身もSaPIDにとても興味が出てきたので、本を購入して自チームへ普及してみようかと思っています。 LIFULLでは新卒エンジニアに丸一日のテスト研修を行なっている 続いての発表はLIFULLでは新卒エンジニアにテストの基礎となる考え方をJSTQBというテスト技術者の試験に沿った内容で座学、およびQAグループが開発したシステムを用いての実習による研修を行なっており、その研修についてのお話です。 LIFULLでは新卒エンジニアに 丸一日のテスト研修を行なっている from LIFULL Co., Ltd. www.slideshare.net 弊社ではテストの基礎を理解してもらうために、新卒エンジニア向けの研修としてテストワークショップを丸一日使って行っています。 内容としてはJSTQB(国際的なテスト技術者の認定資格ISTQBの日本版)に準拠した座学、座学で得た知識をもとにワークをいくつか行います。 最終ワークとしては実際のテスト用のプロダクトに対してテスト分析、テスト設計、テスト実装、テスト実施までを行います。 「テストを実行すること」だけがテストではなく、「何をどうテストするのか」まで考えられるようになることを目指しているとのことです。 研修後のアンケートでもその部分がきちんと伝わった感想を得られており、業務でも得られたテスト技術を存分に活かして頂きたいと感じました。 私も新卒の時に受けたかったなと思いました。 まとめ 今回はLIFULLの品質保証の取り組みについて、QAチームのお二人に話して頂きました。 発表した内容以外にもQAチームはLIFULL全体の品質向上のための取り組みを日々行っており、全社的に品質の考え方を根付かせ、LIFULLというブランドで品質が保証されていると世間に認知されることを目指して日々業務にあたっています。 最後に Ltechでは、LIFULLエンジニアが中心となって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。今後も Ltech を積極的に開催していきますので、ぜひ気になった方は、connpass で LIFULL のメンバー登録をよろしくお願いします! lifull.connpass.com
こんにちは。プロダクトエンジニアリング部でエンジニアリングマネージャーをやっている野澤です。現在LIFULLのプロダクトエンジニアリング部では個人のスキルを高めることを目標の一つとして取り組んでいます。 この記事を読んでいる皆さんもご承知のとおり日々技術は進歩しており、追いついていくのも大変です。当たり前のことかもしれませんが、個人のキャリアのためにも、企業間の激しい競争に負けないためにも、また企業の理念を実現するためにもエンジニアには高い技術力が要求されます。 もちろん自分で勉強して、新しい仕事にも挑戦して、勝手に成長していくエンジニアもいますが、全員が全員そういうわけではないと思います。 前職でも、なかなかスキルアップできないメンバーをどうやって成長させるか私自身思い悩んだ経験があります。例えば、スキルアップ目標を掲げても行動しない、忙しくて時間が取れない、気が向かない、何が嬉しいのか分からない、かつては自己研鑽していたがやらなくなってしまった、など。 こういったことは皆さんの周りでもありえることではないでしょうか。 私が所属するプロダクトエンジニアリング部5ユニットでも、自己研鑽についていろいろ取り組んでいます。多少うまくいったところもあるため、少しご紹介できればと思います。 やったことと結果のサマリー まず、どんなことをやったのかとその結果どうなったのかを簡単にご紹介します。 やったこと なんで自己研鑽が大事なのかディスカッション 自分が行ったInput/Outputの簡単なログを作る slackで書籍や勉強会の情報共有チャンネルを作る 発表機会(LT)を増やす ※後ほど詳しく説明します 結果 4月から3ヶ月間、上記の取り組みをしてみての感想をアンケート形式でメンバーに聞いてみました。 Input Inputの量が増えた(100%) 以前よりも書籍を読むようになった(75%) Inputに対してのアンテナの感度が高くなった(62%) 以前よりも外部の勉強会やセミナーに参加するようになった(50%) Inputが増えて楽しいと感じるようになった(87.5%) アンケート結果: インプットについて Output Outputの量が増えた(25%) 以前よりもブログや勉強会、LTでの発表内容が良くなった(50%) 以前よりも仕事における工夫の幅が広がった(38%) アンケート結果: アウトプットについて Outputには課題はあるものの、Inputにははっきりとした改善の兆候が見られます。では取り組んだことをご紹介できればと思います。 やったこと 1. なんで自己研鑽が大事なのかディスカッション まず「そもそもなんで自己研鑽するんだっけ?」というテーマでディスカッションしてもらいました。 チームの中には「今まであまり考えたことがなかった」という人もいれば、「改めて考えるとなんでだっけ」という人もいました。上から「スキルアップしてください」というのは簡単ですが、まずは自分の頭で「なんでスキルアップしなきゃいけないのか」を考えてもらう必要があります。またチームで話し合うことでフラットに他人の意見を聞くことができるので、「そういう考え方もあるのね」と思考の幅を広げることができます。 例えば技術力が向上すると給料があがる、仕事が選べる、転職のチャンスが広がるといった個人のキャリアに関することもあれば、価値提供のスピードを上げられる、理念の実現に貢献できるといった会社目線での意見もありました。また率直に「技術力が上がるといろんなことができるようになって単純に楽しい」といった意見もありました。 ディスカッションの様子 そのあと、自己研鑽ができている理想の状態についても考えてもらいました。理想の状態とは、しっかり自己研鑽ができている人はどういう行動をしているのか、結果としてその人はどういう状態になっているのかについてです。 これもチームのメンバーと話し合うことで、いろんなあり方・やり方に気づくことができます。「理想の」というところもポイントです。理想的な状況を想像できるようになると、なれるかもしれない自分の可能性に気づくことができます。例えばOSSのコミッターになっているとか、大きなイベントで登壇している、社外からも信頼されていて相談されるなどです。 理想の状態 その後、理想に対する自分たちの現状についても議論もしてもらいました。現実はなかなか理想通りにはいきません。仕事でスキルアップするのが一番効果的ですが、毎回スキルアップにつながる仕事があるとは限らないよね、といった声もありました。 ここで理想と現実のギャップを認識してもらいます。そのことによって、じゃあどんなことができるのか?どうやって変えていくのか?ということをチームが自然に考え始めます。 その上でユニットとして次のようなことを取り組むことにしました。 2. 自分が行ったInput/Outputの簡単なログを作る 自分がどんな本を読んでどんなことを感じたり何を学んだかというのは、サマリーやブックレビューを書かない限り忘れてしまうことが多いのではないでしょうか。参加したセミナーの感想なども同様です。そこで、簡単な表形式でインプットしたことをログとして残すような取り組みをしてみました。 社内ブログで公開している私自身のInput/Outputのログ ログにインプットしたことが蓄積されていくと自身の成長も感じるし、達成感もあって楽しくなってくるようです。アンケートでもそういった回答をした方が多かったです。楽しくなると継続のハードルが少し下がり、自己学習が習慣化されていきます。 また、時々このログを振り返ってみると、どんなことを知りたくてどんなジャンルの本を読み続けていたのか、この時期は何に関心があって、どんなセミナーに参加していたのかを思い出すことができます。その上で自分が何をどこまで理解することができて、何に関心があるのか、あるいは何についてはたいして興味を持てなかったのかが分かるようになります。つまり自分の好みや強みの傾向を分析できるようになります。そのことによって、今後の成長の方向性を考えたりすることができるようにもなります。 また、1on1のときなどに一緒にこのログを見ることで、「この本読んだんだね。どうだった?」みたいな会話が生まれたり、「このセミナー参加してたんだね。私は○○についての話が面白いと思ったけど、どう思った?」みたいな会話が生まれ、理解が広がっていきます。お互いおすすめの本を紹介しあったりすることもあります。 またアウトプットしたことも同様にログをつけてもらうようにしました。この取り組みを始めたのが4月ですので、まだそんなにアウトプットが書けていない人もいます。インプットはできてもアウトプットをするまでの余裕が無いとか、どんなふうにアウトプットしたらよいか分からないと考えるメンバーが多いようです。このとおりアウトプットにはまだ少し課題が残ります。 ただ私自身は普段の業務でもインプットした知識が以外にも活用できていることに気づいたり、せっかくなので業務でアウトプットする機会を作ろうとしていることにも気づきました。アウトプットすることによって、周りからFBをもらって更に理解が深まるという体験もしています。 またアウトプットの蓄積がされてくると、インプットとアウトプットの関係が見えてきたり(5月に読んだ本の知識が6月の業務で役になっているなど)、インプットとアウトプットが循環して、より学びが深くなるといったことが起こります。こうなってくると、自己研鑽がより楽しくなるのではと思います。 3. slackで書籍や勉強会の情報共有チャンネルを作る 私の部署ではslackを使っているのですが、とあるメンバーがおすすめの書籍や勉強会の情報を共有するチャンネルを作ってくれました。それによって、面白そうな新刊の情報や、イベントやセミナーの情報が活発に交換されるようになりました。一緒に同じイベントに参加して感想を話し合ったりというようなことも起こっています。AmazonのKindle本セールなど、お得な情報も共有されて役に立ちます。 一人だとなかなか自己研鑽するのが難しい人でも、他の人と得た知識を共有しあったり、コミュニケーションが生まれると楽しさを感じることができて持続的にインプットすることができるかもしれません。 4. 発表機会(LT)を増やす また月に1回、インプットしたものをアウトプットする機会としてLTの時間を作ってみました。 発表時間は10分と短く、そこまで資料の完成度や準備の時間も求めないことにして、リラックスして発表できることを目指しています。実際にフィードバックをもらえることもモチベーションになったり、LTで話す内容を意識しながらインプットする方もいるようです。 その他の取り組み 以前から行っていた取り組みですが、社内勉強会をメンバーたちが自主的に開催しています。気になる本の輪読会やとある技術についてのハンズオンのような勉強会を、興味のある人同士で隔週くらいで活動しているようです。 また業績評価にはしないものの、アウトプットの目標、例えばQiitaや会社の公式技術ブログ(今ご覧になっているブログです)への投稿数や社内でのLT・発表の回数を設定して取り組んだりもしています。 今後の展望と課題 アンケートや普段のメンバーの動きを見ている限り、このような取り組みを行ったことでメンバーのInput/Outputに対する意識はかなり変わったように思います。私としては以下の2つの理由があったと思っています。 自己研鑽を見える化することで、自分がどれだけ頑張ったか分かるようになり達成感を得られるようになったこと 自己研鑽をその人だけの孤独な取り組みにせず、みんなで取り組めるようにしたこと ご参考になれば幸いです。 今後はInput/Outputのログを全社公開し、お互いにどんなことを勉強しているのかを知れるようにすることで、おすすめの本やセミナー、資格などの情報交換を活発にしたり、理解を深め合うような状況を促進していきたいと考えています。 LIFULLでは共に成長できるような仲間を募っています。 よろしければこちらのページもご覧ください。 hrmos.co hrmos.co
こんにちは、データプラットフォームグループの樋口です。エンジニアとしてデータ基盤の構築・運用を約4年ほど担当しています。 今回は私達が「データの民主化」を目指してこれまでに取り組んできた事を振り返りながらご紹介したいと思います。 はじまり(2017年10月〜) 当時社内では以下のようなキーワードがトレンドでした。 データドリブン経営 データの民主化 データウェアハウス しかしデータが十分に活用されているのは一部の部署や施策に限られており、「データの民主化」と呼ぶには程遠い状態でした。 データのサイロ化 データはLIFULL HOME'Sなどのサービスのために最適化されており、セキュリティやシステム保護の観点からデータにアクセスできる人は必要最小限に抑えられています。 また複数のデータベースやクラウドサービスに散在していて、いわゆる「データがサイロ化している」状態でした。 このような中でデータを活用しようと思うと、まずはデータの抽出をエンジニアに依頼する必要があります。しかしデータが容易に見られる環境ではないので、データ抽出の適切な要件を考える事がそもそも難しいのです。依頼を受けたエンジニアとしても特に面白くない作業に時間が取られる事になり、しかもデータを出してみたら「なんか違った・・」「もう一度データ抽出お願いしますー」なんて事がよくありました。 どう考えても効率が悪いです。こんな状態ではデータ活用は進みません。 データドリブンを推進する部署の発足 そんな状況を変えるためにデータドリブングループという部署が新設されました。グループのミッションは「社内のデータ活用を推進する事によって、各種業務の効率化を図り、経営を後押しする」です。メンバーは企画/マーケター×2名、エンジニア×1名(私)の3名体制でした。 ゼロからの手探りの状態でしたが、3人で下記のような事に取り組んでいきました。 社内のデータの調査 社内にある分析に使えそうなデータをリストアップし、データがどこにあるのか?どのような連携が可能か?を調査していきました。LIFULL HOME'Sなどのサービスのデータはもちろん、営業関連のデータや会計システム、既存のBIのツールの中身などを調査していきます。特にバックオフィス系では様々なSaaSや外注しているシステムが存在していて「データのエクスポートには追加の費用が必要かも?」という物もあったりしました。 データ分析のトライアル 営業部門と一緒にデータ分析による営業戦略の立案に取り組んでみました。 仮説を立てる → 関連データを集めてきて仮説を検証 → 筋がよさそうなら営業戦略に落とし込んで実行 → 結果を検証 というサイクルを回していきます。 具体的に作業を進めてみると「キーとなる情報がなくてデータが結合できない」「そもそもデータが無い」などの問題が浮き彫りになってくるので、今後のDWHやデータマート作成時に考慮すべきポイントが見えてきました。 DWHの構築 サイロ化しているデータを一箇所に集めて分析者が利用しやすい環境を作るために、データウェアハウス(DWH)を構築します。DWHにはGCPのBigQueryを採用しました。LIFULLではGoogle Workspaceを導入しており、社員全員がGoogleアカウントを持っているのでBigQueryへの権限付与も非常に手軽に実現できました。 BigQuery自体にも積極的に機能追加・改善が行われており安心感がありますね。個人的には殆ど非の打ち所のないサービスだと思ってます。 2期目(2018年10月〜) 非エンジニア向けの勉強会を実施 データ活用を進めるにはデータを扱える人も増やしていく必要があります。エンジニアへ依頼する事なく誰でもデータを取り扱える状態を目指しているので、非エンジニアの人を対象にSQLの勉強会を行いました。クエリの向き先は分析用のBigQueryなので、SQLに不慣れな人が多少無茶なクエリを実行しても大きな問題にはなりません。実際に実行しながら試せる環境があるのはとてもいいと思います。ただしクエリのコストの面では不安が残るので「ユーザー一人あたりのクエリ上限(Query usage per day per user)」などのキャップを設定しています。 Tableau BIツールとしてはTableauを導入しています。こちらも利用者を増やすための勉強会を実施したり、各部署で追っている指標をTableauで可視化するサポートを行いました。 当初はTableau Desktop × Tableau Onlineの組み合わせで使っていましたが、利用アカウントの増加に伴いこの時期にTableau Serverへの切り替えを行っています。 Tableauは直感的なマウスの操作で綺麗なデータビジュアライゼーションができるのが売りですが、サッとデータを見たい時のビューワーとしても重宝しています。 3期目(2019年10月〜) これまでは非エンジニア部門をメインのターゲットに置いてDWHを中心としたシステムを構築していましたが、エンジニア部門からもDWHのデータを使いたいという声が聞こえてくるようになりました。また各部署ごとにデータの準備にコストが割かれているという問題も表面化してきました。そこでデータの集積はデータ基盤に統合していく方針とし、データプラットフォームグループというエンジニアリング組織で管理していく体制になりました。 データレイクを備えたデータ基盤の構築 LIFULLではAWS上で稼働しているサービスが多いため、これらデータソースの一番近くに位置するデータレイクにはAWSのS3を採用することにしました。これまでもBigQueryの前段にあったCloud Storageが同等の役割を果たしていたのですが、これからは明示的にデータレイクを構築していきます。 同時にETLの実行環境もAWSのECSやStep Functionsを利用した構成にリプレイスしていきました。 これまでの構成 DWHを中心にGCPで構成 現在の構成 データレイクにS3を採用しAWS側にリプレイス 現在(2020年10月〜) 現在、データ基盤では約2,000のエンティティ、約4,000億レコードを管理しています。取り扱うデータ量や種類の増加に伴って運用コストも増加傾向なので、より効率化を図りながら規模を拡大していくことが目下の課題です。 まとめ 今回は「データの民主化」に向けて取り組んできたこれまでの流れを大まかに紹介させていただきました。システムの詳細や運用の仕組み、Tableau Server、失敗談など、個別の具体的な内容についてはまた別の記事でご紹介できればと思います。 最後にLIFULLでは一緒に働く仲間を募集しています。(※データ基盤開発のポジションもあります!) カジュアル面談も行っていますので興味のある方はぜひご応募ください! hrmos.co hrmos.co
こんにちは、LIFULLのエンジニアマネージャーをやっております。河津です。 私は、2015年の6月〜2018年の6月までの丸3年間をLIFULLグループの会社であるTrovitに常駐しスペインで過ごしました。 帰国してすぐに、スペインでのエンジニアの働き方を書いてみようかとも思っていたのですが書けずに2年が経ってしまいました。 ですが、2年ほど日本での働き方も再度経験したことで、改めて当時の経験で今役に立っているなと感じる部分があったので、筆(キーボード)を取りました。 また、スペインに出向の経緯やスペイン常駐時の苦労話などはいつか紹介できたらと思います。 ※Trovitは企業統合により現在は LIFULL CONNECT となっています。 ※ 世界最大規模の不動産・車・仕事のアグリゲーションサービス を提供するスペインの会社です。 組織と働き方 チームの役割が明確! 私が所属していたころのチームはエンジニアだけでなく多職種で一つチームを編成しており、担当分野が、アプリケーション、検索エンジン、インフラ、パーサ、SEO、有料集客にチームが分かれていました。 それぞれのチームでのミッションが明確になっており、会社の戦略に明確に紐付いていました。 例えば、検索エンジンとしてSolrを利用しているのですが、クエリ構築を容易にするプラグインを実装することで検索エンジンを使う全てのアプリケーションの開発効率を改善させ、バグの発生率を下げていました。インフラチームでは、Kubernetesを利用目的とした基盤の移行(AWSからGCPへ)を3ヶ月程度で完遂させ可用性を高いものにしていました。 ※例はほんの一部です 学び チームにまで落とし込まれたミッションが明確であることが組織全体の生産性向上に繋がり会社の成長につながる。 日本での取り組み 戦略に則したチーム編成とそのチーム毎にメインミッションを明確に決め、やることへのフォーカスができるようにしました。うまく回っていると実感できるシーンもあれば、フォーカスすべき内容と業務の幅との調整など改善の余地はまだあると感じています。 全社で閲覧するデータの統一と可視化が徹底的! ミッションが明確でも、状況を正確にモニタリングしたり、施策に対する結果を定量的に見ないと成否の判定が正しくできないという考えから、データの可視化を徹底的に行っていました。 例えば、SEOチームでは日々のセッション数とキーワード数との相関だったり、パーサチームはポータルサイトからパースしたデータの数と品質を可視化して、社内の誰でも見れる状態にしていました。 この社内の誰もが統一されたデータを見るということがとても重要で、統一されたデータを見ることで状況を共通して認識することができ、そこからの質疑応答が社内コミュニケーションを活発にしていました。 ある時、CEOが「個人分析の資料で語るな、分析資料は共通してみることができるものに統一すること」と言っていたのはこのためだったんだなと、改めて思いました。 どのデータを正とするのかといった、無駄な時間と労力も生まれなかったと思います。 学び 全社で統一した指標を見ること、それが全社に公開されていることが無駄な時間を発生させず、意識統一にもつながる。 日本での取り組み すでにLIFULLでも、会社全体で見る数値を統一させる動きを取っていました。 今まで、定期的に参照するKPIのデータ形式やドキュメントがバラバラだったものが一定統一され見やすくなっています。 また、エンジニアチームでは 技術負債の解消を目的としたCodeclimateを利用したコード品質の可視化 を進めていっており、 リファクタリングへの意識 が高まっています。 こちらは、エンジニア全体での動きがすでに取られており、私の思惑にも繋がりました。 www.lifull.blog www.lifull.blog 常にデプロイされる環境! テストまで完了したプロダクトは随時デプロイされる仕組みになっていました。 プロダクション前の環境では常に品質を担保するテストケースが走り続けていて、リリース可能な状態になったものは逐次デプロイされます。デプロイ後にバグが発生したら、一つ前のタグに戻すだけでロールバックができる仕組みとなっており、エンジニアは常に開発する事に集中できる仕組みが用意されていました。当時の私にはQAが活躍していたのは斬新でした。 学び 出荷可能な状態のプロダクトをすぐに世に出せる仕組みになっている事が、リリース日までのほんの数日ではあるが出荷を待機させるという事との小さな差を生み、その積み重ねが1年を通すと大きな差になる。 日本での取り組み 赴任する前は週に2回程度のリリース日が用意されていたのですが、今では毎日リリースできる仕組みがすでに構築されています。こちらも、赴任している間に仕組み化されていたので、LIFULLでもリリース頻度を課題と捉え着実に改善が進んでいると実感しています。 採用と人事 学んで来たことと仕事のつながりを重視する! エンジニアの中にも様々な職種があると思いますが、職種と大学での専攻が紐付いている人ばかりでした。中には、必要となるスキルを大学や専門学校で改めて学び直す人や、専門性をより高めていった結果、働きながら大学で講師をしている人もいました。 採用の面でも、大学での専攻や業務での実績が無い人が採用されることはほぼありません。 一般的に日本企業では大学での専攻と関係なくポテンシャル採用を行っていますが、ポテンシャル採用という言葉自体がありませんでした。 技術マネージャーが「特定の理工系大学の新卒を取ることが非常に重要で、卒業したての人材こそ即戦力として期待ができる!」と力強く言っていたのを覚えています。 またよくある話ですが、知識があり素晴らしい結果も出しているのに謙遜するということもありませんでした。あるのは謙遜ではなく、仕事の結果の分析と共有といった一つコミュニケーションのステップが省略されているイメージを受けました。これはエンジニアに限った話ではなく文化的なものかもしれません。 学び 同士として働いてもらうエンジニアを選考する採用に妥協は許されない。 Betterではなく、Bestを採用することが大事である。 日本での取り組み LIFULLのビジョンに共感していただける方を採用することは最重要ですが、社内での活躍が期待できるか、一方社内でも活躍の場をしっかりと提供できるかを一つ一つ丁寧に確かめながら採用活動を進めさせていただいております。 hrmos.co 雇用形態が異なる! スペインでは雇用契約上、解雇は普通に行われTrovitでも努力しているしていない如何に関わらず、結果が出ていなければ解雇されます。うちの会社にはフィットしなかったので、もっと活躍できるところへ送り出してあげる。それが会社にも当人にも幸せな結果をもたらす、という考えのもと解雇を選択します。 ある日、昼食から帰ってくると、とあるデスクの荷物がまるっとなくなっていることがありました。週末飲みに行く約束をしていたので、余計にびっくりしたのは覚えています。 赴任当初は日本の感覚が強く、解雇や退職と社員が辞めてしまう事にかなり敏感になっていたのですが、徐々にヨーロッパのエンジニア市場だったり転職事情を知り、過度にネガティブに捉えず次のステージを応援するマインドになりました。今でもその感覚は持っています。 学び 市場のニーズを捉え、スキルを磨いていくことが自分の市場価値も上げていくこととなる。 日本での取り組み 今期からエンジニアは職能別の組織となり「強い個人、最高のチームとなることで、価値創造を加速させ続ける」というビジョンを掲げ、 以前よりも勉強会やナレッジ共有会の開催頻度を上げたり 、個人でのスキルアップの発表の場を設けたりと、より高度に求められる市場ニーズに応えられるエンジニアの育成に取り組んでいます。 www.lifull.blog 人生で大事なものはお金よりも時間!時間を大事にする文化 オンとオフの切り替えが上手い! オンとオフの切り替えを当たり前のようにしていて、すごく上手いなと感じました。 勤務終了後は近くのバーへ行くのが恒例でしたが、仕事の不平不満を話すのではなく、次にチャレンジしてみたい技術だったり、今プライベートで気になって触っている技術について熱く語る人ばかりでした。 Kubernetesがいかにイケているのかをブルーチーズを片手に赤ワインを飲みながら語っていたインフラエンジニアを今でも忘れられません。社内のメンバーだけでなく、エンジニアの友人を呼んでディスカッションが始まることもありました。 仕事の話から一旦離れるが技術の話は楽しくてついやってしまうという、根っからのエンジニアが多かったように思います。 また、サッカーの話になると地元のチームの話や日本から移籍してきた選手の話で盛り上がったりと、仕事を忘れて時事ネタで盛り上がることも多々ありました。 現地の会社対抗のリーガ(フットサルの大会のようなもの)が一定期間で開催されるのですが、仕事の後のちょっとした運動ってレベルではなく毎回みんな本気なので、参加しては毎回死ぬんじゃないかと思っていました。 学び 仕事とプライベートの切り替えや時間の使い方の上手さがストレス解消に繋がり、翌日の業務へのモチベーションを保つ秘訣。 日本での取り組み 直近のコロナ禍ではコミュニケーションのとり方が大きく変わりました。特にオンラインでのコミュニケーションは業務の内容のみになってしまいがちです。そこで特定の時間は気軽に話せる部屋を開放してみたり、あえて雑談しかしない時間を取るなど、切り替えの時間を取るようにしました。これが意外とストレス解消につながったり、メリハリをつける事につながったりと良い影響を及ぼしたと実感しています。これらは、メンバーが自ら実践してくれました。 ミーティングのセッティングも命がけ! 人の時間を無駄に搾取してはならないという文化がありました。 なにか提案をするとき、特に今あるものを否定するには否定するに至る事実(データ)がなければ、ただの個人の意見であるという考えがありました。 ある日、「このMTGは本当に無駄な時間をすごした!」と激怒され部屋から出ていかれたこともあります。 今は反省をするとともに、ミーティングの本当のあり方を学んだように思えます。自分が人の時間を搾取するということを真剣に考えるきっかけにもなりました。 今思えば、ミーティングではみんな「I think」ではなく、「It says」と言っていたのを思い出します。 学び ミーティングの要不要は必ず検討し、行う場合でも必要最小限で行う。 必ず客観的に判断できる事実やデータを用いて語り、無駄に時間を浪費させない。 日本での取り組み 効果的なミーティングを実践するために色々検討し実行しました。 ミーティングは極力削る 1時間ではなく30分でできるものは30分で終わらせる 早く終われば、終わり次第解散する チャットに書けば終わることは書いて終わらせる 書く方が時間がかかるなら、さくっと5分程度の会話する 必ず一つの指標をみんなで見て協議する などです。 オンラインでのコミュニケーションが必須となったなか、ミーティングが必要な場面は増え、なかなか難しいところはありましたが、今後も継続して改善していきたいと思います。 金曜の夕方をみんなで楽しむ! 金曜の夕方は「All Hands」という、各グループが自分たちの取り組みを共有する会が開催されていました。 ただの共有会が開催されるのではなく、会場ではビールとおつまみが用意されており、みんなフロアで足を伸ばして座りながらリラックスして聞いていました。そんなフランクな会なので、質問もどんどん飛び交い、聞く方も為になるし、プレゼンする側もテンションが上がるといった楽しい会だったのを覚えています。 また時には、聞いているメンバーがフォローに入ったりして、全社での一体感もすごく醸成できていたと思います。 私も一度、LIFULLでの取り組みである「 クリエイターの日 」を共有しましたが、多くの質問をもらえたり、うちでもやってみようかなと言ってもらえ、大きな達成感を得られたのを覚えています。 ただ、この「All Hands」への準備は運営チームとかなり綿密にやりました。一見フランクに適当に集まって午後の一時を楽しく過ごそうよ!って感じなんですが、全員で集まる意味をしっかり捉え、参加者にとって意義のある時間にすることへのこだわりはかなり強烈でした。 学び みんなで同じ時間を過ごすことも大事、その時間を有効活用することが、より洗練された組織づくりにもつながる。 日本での取り組み LIFULLでは以前から、チームビルディングの一貫で一つの事にみんなで取り組むという仕組みはありました。その多くは物理的に人と人が接し合うことで実現していたのですが、今回オンラインで実現させることが必要となってきました。 そこで今回、 エンジニアのユニット総会を特定のトーク内容について会話をする会にしてみる といった新しい試みを行いました。異なるグループのメンバー達が、同じ時間を過ごしながら意見を交わすことで、より相互理解と繋がりを強くすることができたと思います。 www.lifull.blog まとめ 帰任して2年経ち、スペインでの経験と学びからエンジニアマネージャーとして何を考えどう動いたのかを書き綴ってみました。 私の場合は海外の会社に転職したようなものだったので、言葉の違いに始まり、文化のギャップやマインドの違いで苦労はしました。しかし、それを乗り越えることで新しい学びを得られ、日本での取り組みに繋がったと感じています。 LIFULLのエンジニアには海外での経験も積んでみてほしいと思います。今の状況下、現地に行くことは難しくなっている一方、オンラインでのコミュニケーションは格段に取りやすくなっています。海外のカンファレンスなどオンラインで開催されているものは多数あるので、アンテナを広げて様々な価値観や取り組みを学び、日々の仕事に活かしてもらえたらと思います。 最後に 学びからの取り組みを共有させていただきましたが、実際に「取り組み」をしてくれたのは、他でもないエンジニアのみんなです。大きな変化への適応や、大きな事を一人で成し遂げるのは至難の技です。メンバーひとりひとりの協力なくしては成し得ません。 これからも、エンジニアがOne Teamとして活躍できる場を創り、共に切磋琢磨して成長していける組織を創って行きたいと思います。
こんにちは!エンジニアの美馬です!Vite 使ってみました! はじめに やったこと やっていないこと 開発の課題 周辺環境の課題 レガシー JS そのものの課題 ESModules がなく JS の依存が JS 内で完結しない 見慣れないプロトタイプチェーン Road to ESNext 導入したツール Vite JSDoc ESLint Prettier TestCafe Vite で嬉しかったこと 爆速ビルド 簡素な Config レガシーブラウザ対応 書き換えで苦労した点 Vite Backend Integration module/nomodule による問題 jQuery 成果 おわりに PR はじめに 新規 PJ では迷わずモダンな環境を選択します。しかし現実には既存のコードを流用・修正していかなくてはならないこともあると思います。 標準に追従しモダンな周辺ツールの恩恵を受けられるようにし、スムーズに開発を継続させるべく、フロントエンドの改善施策を行いました。 やったこと ES5→ESNext の書き換えを行った Vite の Backend Integration を使用した 周辺ツールを整えた Formatter - Prettier Linter - ESLint E2E Test - TestCafe Type Annotation - JSDoc やっていないこと TypeScript の導入 宣言的 UI の導入 デザインの刷新 開発の課題 対象のサービスは、マイクロサービスとしてメインのモノリスから切り出され、8 人のチームで開発していました。切り出したは良いものの、新規コンテンツページの作成等もりもりとサービスの開発は進むのに対し、開発環境のメンテナンスは特にされていない状況でした。 周辺環境の課題 開発ツールがそろっておらず、 効率の良い開発が行えるとは言いがたい状況でした。 ビルドツールがない トランスパイラはなく、生の ES5 が書かれていました。 バンドルツールは YUI Compressor が使用されており、bundle, minify はされていました。 JS の依存は HTML テンプレートにて管理されておりわかりにくい状態で、 ライブラリは npm で管理されておらず生ファイルが存在する状態。ライブラリのアップデートも難しい状態でした。 自動テストが十分でない 主要な機能を確認する E2E テストはあったのですが、JS エラーを網羅できるようなテストはなく、 ほかの部分ではほぼ手動でテストが行われていました。 不十分な静的解析 一応 Linter は JSLint が導入されていましたが、十分な静的解析は行えていない状況でした。(後述) ESModule での記述も静的に解析したかったこともあり、ESLint に乗り換える必要がありました。 (JSLint もこの施策中に大きめアップデートが来ていました。ESLint に乗り換えましたが。) レガシー JS そのものの課題 古くなった JS を書き続けるということは、JS の進化の恩恵を放棄し続けるということです。 ES2015 以前の JS では ↓ のような問題を抱えていました。 ESModules がなく JS の依存が JS 内で完結しない < script src = "jquery.js" ></ script > < script src = "common.js" ></ script > < script src = "app.js" ></ script > 依存は HTML テンプレートに直接書いて管理されます。 import, export の構文は使えず、どんどんグローバルは汚染されていき、 読み込み順序、読み忘れにより度々エラーが起き、JS を書いた後 HTML を開きエラーを確認する必要があります。 見慣れないプロトタイプチェーン someClass.prototype.say = function () { console.log( "hello" ); } ; 本サービスではこれを避けようとして独自のファクトリ関数のようなものによって擬似 Class が実装されていました。その結果、十分な静的解析ができない状態になっていました。 これらの影響により、ちょっと jQuery を推奨バージョンまでアップデートしようにも影響範囲は分かりづらく、独自に実装された内容が現在では不要であるはずの学習コストを生んでいることなど良い環境とは言えない状況でした。 Road to ESNext 効率の良い開発が行えていないと判断され、JS 改善 PJ が立ち上がり、ESNext への書き換えが始まりました。これは急に取り組み始められたものではありませんでした。 ES5 でそのまま運用されている背景からも分かるように、 これまでは事業としての開発に振り切られていた状態でした。 しかし昨年ごろから徐々に開発環境改善の動きがあり、改善の意識が高めてきた先の本施策でした。 次のような段階を踏んだ上で書き換えに至りました。 フロントエンドテスト環境改善の動きが出始める まずはテスト不足からアプローチされました。TestCafe での E2E テストが整えられ、主要な機能をテストできるようになりました。 TestCafe が CI で動き始める 毎朝とデプロイ時に E2E が動くようになりました。CodeBuild で動いています。 E2Eテストをクラウド移行したお話 - LIFULL Creators Blog TestCafe で全ページの JS Error を拾うようになる 全ページで初回ロード時の JS エラーを拾うようにしました。 リポジトリ内の使用されていないコードをひたすら grep して削除 ESNext 化する前に不要なコードは削除しておきました。 幸いリポジトリに配置されていた jQuery プラグインや自作ライブラリの多くは使われていないもしくは限定的な使われ方をしていたのでたくさん削除できました。 ビルドツール導入が検討される トランスパイラのみ導入すること、新環境を作成すること、等を検討する中で ノーバンドルツールである Snowpack, Vite のうち Internet Explorer 対応が容易かつ勢いが感じられた Vite に注目、採用することを決めました。 ESLint, Prettier を設定 既存の JS の ESNext 化の際、ツールで一括置換しようにもユニットテストはないので手動確認が必要になってしまいます。 また、Vite を採用するにあたって ESModules に書き換える必要があります。 全部書き換えることに決めたので、最大限にツールを活かして書き換えを行うべく周辺ツールを整えました。 ESNext 化 書き換え対象は 3 万行ほどありましたが、盤石な体制を整えて レビュー 1 人書き換え 2 人の計 3 人での手作業で JS を書き換えつつテストを作成するパワープレーを実行しました。 導入したツール Vite https://ja.vitejs.dev Rails や Laravel とも組み合わせることができます。 バックエンドとの統合 | Vite JSDoc もともと JSDoc を書く文化はあったのでそのまま採用しました。今回 TypeScript は導入していませんが型をざっくり守っています。tsc の checkJs によって型チェックを行うこともできます。 ESLint eslint-plugin-jsdoc JSDoc で不正な記述があった場合に検挙します。 eslint-plugin-import 存在しないパスやモジュールを指定した時に注意してくれたりします。 eslint-import-resolver-alias import エイリアスを設定しているので対応します。 eslint-plugin-prettier Prettier のエラーを ESLint のエラーとして表示します。 Prettier Why Prettier? · Prettier TestCafe E2E テストを行います。クロスブラウザに強く、セットアップが容易です。 Cross-Browser End-to-End Testing Framework | TestСafe Vite で嬉しかったこと 爆速ビルド 従来のビルドツールを導入すると分単位で待ち時間が生じてしまいます。 しかし esbuild のような高速ビルドツールやこの Vite などのノーバンドルツールによりその待ち時間は大幅に短縮可能になりました。 Vite では開発環境向けには Native ESM を活かし JS をビルドするので待ち時間がほぼありません。 3 秒で開発開始可能です。 簡素な Config postCSS, esbuild, Rollup と内包しているので Vite さえ面倒をみていればビルド環境が整えられます。 設定ファイルが簡素で、package.json もシンプルであることも良いところではないかと思います。 vite.config.js import legacy from "@vitejs/plugin-legacy" ; import glob from "glob" ; export default defineConfig( { plugins: [ legacyPlugin( { targets: [ "ie >= 11" ] , } ), ] , resolve: { alias: { pc: "/assets/js/pc" , sp: "/assets/js/sp" , common: "/assets/js/common" , } , } , build: { manifest: true , rollupOptions: { input: glob.sync( "**/js/**/entry.js" ), } , outDir: "out" , assetsDir: "js" , } , server: { port: 3000, hmr: { protocol: "ws" , host: "localhost" , } , } , } ); package.json " dependencies ": { " @vitejs/plugin-legacy ": " ^1.5.0 ", " vite ": " ^2.4.4 " } レガシーブラウザ対応 SPA ではなく MPA でしたが容易に導入することができ、 レガシーブラウザ対応もプラグインを設定して簡単に行えました。 github.com ライブリロードがあることも格段に開発体験を向上させてくれます。 (HMR まであるが JQuery を使用しているので今は活かされていない) 書き換えで苦労した点 Vite Backend Integration ガイド にあるように簡単にエントリーポイントのみ指定することで動作しますが、Native ESM による読み込みが行われるため RTT が生じます。回避するには、Vite から出力された manifest.json から依存ファイルを辿り、preload directives やタグを SSR しておく必要があります。 manifest.json { " assets/main.js ": { " file ": " main.5a48225c.js ", " src ": " assets/main.js ", " isEntry ": true , " imports ": [ " _moduleA.9fb6069d.js " ] } , " _moduleA.9fb6069d.js ": { " file ": " assets/moduleA.9fb6069d.js ", " imports ": [ " _moduleB.ead1d8b3.js " ] } , " _moduleB.ead1d8b3.js ": { " file ": " assets/moduleB.ead1d8b3.js " } } HTML(SSR) < script type = "module" src = "assets/moduleB.ead1d8b3.js" ></ script > < script type = "module" src = "assets/moduleA.9fb6069d.js" ></ script > < script type = "module" src = "assets/main.js" ></ script > module/nomodule による問題 type=module では常に use strict モードとなるので注意が必要です。 また、トップレベルの this は global ではなく undefined を返すようになります。 ECMAScript® 2022 Language Specification 既存のライブラリで最上位にて this を参照していたものを window に変える必要がありました。 jQuery 全書き換えのついでに 1 系から 3 系へのアップデートを行いました。 VSCode で型を参照しつつ非推奨の構文を取り除くことができ便利でした。 VSCode にて unbind が非推奨であると指摘されている 成果 7.1 万行あったJSから不要なJSを削除して 2.9 万行、ESNextに書き換えて最終的には 1.2 万行にまで減りました。 静的解析が強力になったのでレビューコストが削減されました。 パッケージ管理ができるようになったので外部ライブラリを導入しやすく、メンテナンス可能になりました。 おわりに 捨てるでも新しい何かをつくるでもなく、標準に寄せ、負債を縮小するという選択をとりました。 進化し続ける技術に追従しつつ、ユーザーにもエンジニアにもうれしい開発をしていけたらなと思います。 PR マンションを売る時も LIFULL HOME'S へ! lifullhomes-satei.jp
みなさんこんにちは、SET(Software Engineer in Test)の Ruey です。 弊SETチームの活動として、自動テストの実施依頼を受けています。 最近は大規模な範囲にページ内の特定な要素を追加する施策の自動テストを対応しました。 テスト内容はURLへアクセスして特定のタグがあるかを確認することなので、データ駆動型テストで対応しました。 開発チームの実装後、こちらからデータ駆動型テストを実施し、結果を報告する形になります。 テスト結果報告後に開発チームはバグ修正を行い、すべてのテストケースがPassするまで「再テスト➡︎再修正」の繰り返しを行いました。 すべてのテストを実行すると実行時間がかかりフィードバックが遅れるため、前回失敗したテストケースのみを再実行したいです。 なので、そのような仕組みがあった方が対応しやすいと考えました。 今回の記事では、データ駆動型テストにおいて失敗したテストケースのみを再実行できる仕組みを紹介したいと思います。 目次 目次 データ駆動型テスト(Data-driven testing)とは? データ駆動型テストの例 テストデータ sample-data.json サンプルコード data-driven.js どのような再実行の仕組みが必要か? 失敗したテストケースのみを再実行できる仕組み 不連続のテスト再実行を実現する仕組みの例 テストデータ sample-data.json サンプルコード data-driven.js 最後に データ駆動型テスト(Data-driven testing)とは? 仕組みを説明する前に、まずはデータ駆動型テストについて少し紹介します。 ISTQBの用語集の説明 では スクリプト記述技法のひとつ。テストスクリプトの実行に必要なテストデータおよび期待結果を含んだデータファイルを使う。 と定義しています。 今回の施策におけるテストでは、2000個程度のURLへアクセスして各ページ内に同じような検証を行います。 なので、テスト実行スクリプトを一つ用意して、後は大量のテストデータに記載しているURLと期待値を利用し、「URLへ遷移➡︎期待値検証」のループで対応します。まさしくデータ駆動型テストになっています。 データ駆動型テストのポイントとして、検証の部分を共通化することが大事です。テストケース数は大量になるので、全て同じ検証関数が使うことができれば実装が楽になります。 データ駆動型テストの例 ここはURLごとにページHTMLのtitleタグの内容を確認する例を紹介します。 テストデータ JSON式でURLとtitleタグの期待値が入っています。 sample-data.json [ { " url ": " https://devexpress.github.io/testcafe/example ", " expectedTitle ": " TestCafe Example Page " } , { " url ": " https://testcafe.io ", " expectedTitle ": " Cross-Browser End-to-End Testing Framework | TestСafe " } , { " url ": " https://testcafe.io/documentation/402632/reference ", " expectedTitle ": " Reference | Docs " } ] サンプルコード TestCafe というテストフレームワークで書いています。データ駆動型に対応していますので、簡単に実装ができます。 data-driven.js import { Selector } from 'testcafe' ; const dataSet = require( './sample-data.json' ); fixture `Data-Driven Tests` dataSet.forEach(data => { test(`Testing for '${data.url}' `, async t => { await t .navigateTo(data.url) .expect(Selector( 'title' ).textContent).eql(data.expectedTitle); } ); } ); シンプルなコードでsample-data.jsonにある3つのデータをループして確認することができます。 TestCafe公式サイトの各URLへアクセスし、ページタイトルにあるテキストとJSONデータにある期待値が一致しているかを検証します。 どのような再実行の仕組みが必要か? 上記の例では3ケースしかないですが、今回の施策で実施したテストは2000ケースほどありました。 そして、一回目のテストでは200ケースほど失敗しました。 この結果を開発チームに報告し、開発チームが再修正を行った後、前回失敗した200ケースのみを再実行することになりました。 TestCafeだと、テストケース名を指定して実行する機能がありますが、200ケースを直接指定しないといけないのでかなり大変な作業になります。 このような場合に「 失敗したテストケースのみを再実行できる仕組み 」が必要です。 ※ 本記事では失敗したテストケースのみの再実行の説明なので特に書いていませんが、バグ修正後には全てのテストケースが通るかを確認すべきです。 失敗したテストケースのみを再実行できる仕組み テストフレームワークによっては、失敗したテストケースをあらかじめ設定した条件に沿ってその場で再実行する機能があります。 (Testcafeだと Quarantine mode ) ただし、今回の施策のように「開発チームが修正➡︎再テスト」を繰り返すようなパターンでは、この機能はそぐわないです。 このようなパターンのことを、ここでは 不連続のテスト再実行 と呼ぶことにします。 不連続のテスト再実行を実現するためには、前回の実行結果の記録が必要です。 再実行の際に記録を確認することで、前回失敗したケースのみ実行することが出来ます。 不連続のテスト再実行を実現する仕組みの例 今回はJSONのデータに前回のテスト結果を記録する部分を加えて、不連続のテスト再実行を実現する例を紹介します。 テストデータ JSONデータは状態記録用の「passed」を追加します。初期値はfalseを設定します。 sample-data.json [ { " url ": " https://devexpress.github.io/testcafe/example ", " expectedTitle ": " TestCafe Example Page ", " passed ": false } , { " url ": " https://testcafe.io ", " expectedTitle ": " Cross-Browser End-to-End Testing Framework | TestСafe ", " passed ": false } , { " url ": " https://testcafe.io/documentation/402632/reference ", " expectedTitle ": " Reference | Docs ", " passed ": false } ] サンプルコード サンプルコードは実行の前にテストケースの実行状態を確認して、if文で実行もしくは実行しないを判断します。 また最後は実行成功時に状態をJSONファイルに状態を更新します。 data-driven.js import { Selector } from 'testcafe' ; const dataSet = require( './sample-data.json' ); const fs = require( 'fs' ); fixture `Data-Driven Tests` .after( async t => { fs.writeFileSync( './sample-data.json' , JSON.stringify(dataSet, null , 2)); } ); dataSet.forEach(data => { if (!data.passed) { test(`Testing for '${data.url}' `, async t => { await t .navigateTo(data.url) .expect(Selector( 'title' ).textContent).eql(data.expectedTitle); data.passed= true ; } ); } これでテストフレームワークに不連続のテスト再実行の機能がなくでも、 テストデータに前回の実行結果を追加することにより、失敗したケースだけを再実行できる仕組みを簡単に実現できます。 最後に この再実行できる仕組みを利用することで、修正後のデータ駆動型テストを簡単に行うことができました。 再実行したいテストケースの直接指定の大量な作業から解放できました。 ケース数が非常に多いデータ駆動型テストでの不連続のテスト再実行が必要な時に、この仕組みはとても役に立ちます。 もしみなさんも同じようなデータ駆動型テストを実施する機会があれば、この仕組みが参考になれば幸いです。 今回のサンプルで紹介したTestCafeには不連続のテスト再実行の仕組みがないですが、他のテストフレームワークにはあるかもしれません。 そのテストフレームワークを直接利用してもいいと思います。 最後は宣伝ですが、弊社製の Buckyにも不連続のテスト再実行 の機能がありますので、ぜひご検討ください! 以上、ありがとうございました!
導入 こんにちは、QAエンジニアの星野です。 突然ですが、改善活動はお好きでしょうか。 自分の所属するQAグループ内でSaPIDという改善手法の実施を行いました。 ここでは、SaPIDの紹介と導入〜初回の壁、失敗と工夫についてをお伝えいたします。 SaPIDとは SaPIDという名前は、 S ystems a nalysis / S ystems a pproach based P rocess I mprovement metho D から命名されています。 公式な説明を以下に引用します。 SaPIDは、当事者自らが システム思考 を活用して対象のメカニズムをシステムとして構造的に捉え、最も効果的で現実的な箇所、あるいは新しい価値創出に有効な施策・対策をうち、成果をあげていくための手法です。 特定の個人が実践することも可能ですが、チームや関係者、組織のメンバーが参画し、 デザイン思考 を併用して一緒に成長する、そして新しい価値を共創する方法を併せ持つのがSaPIDの特徴です。 引用 : https://www.softwarequasol.com/sapid/ 基本的には公式の提示している説明をお読みいただけば、どんなコンセプトでどんな特徴があるのか把握できるかと思います。 とはいえ参照する方が全員ではないと思いますので、 私の思うSaPID がどういうものかを箇条書きにします。 SaPIDとは、 当事者自らが主体的となり、 各々の感じている課題や懸念、不安や不満を挙げながら、 それらの背景や真の課題を明らかにして、 課題と課題の因果関係(原因と結果)を可視化し、 改善したい課題と、改善するための活動の検討、改善できているかの評価方法を、 納得感をもって検討・決定することができる手法 であるというのが私の理解です。 後述しますが、改善にあたって問題解決を急ぎすぎて何を解決すべきか吟味せずに対策を考えてしまうことも多いと思います。 SaPIDは合理的かつ改善に取り組むチーム全員が納得感をもって進められるようになっており、そこが魅力だと思っています。 コンセプトは上記の通りです。 具体的な中身としては、各々が挙げた課題や事実の関係性をこちらの 図 のように明らかにしてきます。 課題や事実の関係性が可視化できたら、具体的な改善のターゲットを特定し関係性をたどって根本から問題を解決していく手法です。 導入の壁と乗り越え方 SaPID経験者がいない 名前こそ知っているものの、チーム内にSaPIDの経験者はおらず具体的に何をするのかもわかっていない状況でした。 そこでとりあえず雰囲気だけでも体験しようと思い、 SaPIDの勉強会 を探して参加してきました。 (connpassで検索すると最近でもSaPIDに関する勉強会は開催されています。) ちょうど勉強会の中身がゆるく軽量化されたSaPIDのワークだったため、 チーム内で定期開催されている勉強会で体験してきたワークをさらに軽量化し、短時間でSaPIDの雰囲気と自分が魅力を感じた要素に絞ってチームに広めました。 学習コスト どんな手法にも言えますが、SaPIDを知るために学習コストがかかります。 SaPIDを学ぶためにはまずは書籍で全体像の把握をおすすめします。 細かな内容や実践しないとわからないようなTipsも多いため、あまり木を見ずに森を見るように読み進めることを推奨します。 さらにSaPIDを実際に体験をするために、勉強会を探すか年1回程度開催されている公式のSaPID Bootcampへの参加するとなおよいでしょう(参加者は書籍を割引で購入できます)。 参考 : SaPID Bootcamp SaPIDは今もアップデートされているため書籍の情報はSaPID Bootcampや勉強会の内容よりも少し古くなっていますが、考え方やコンセプトは変わりません。 基本的には書籍を読んで全体像を理解し、SaPIDを実践するときは書籍を開きながら細かい進め方やTipsを参照すると良いと思います。 後々必要になったら参照しようと付箋を貼りながら読み進めたところ、このような状態になりました。 こう見ると、さほど多くないと思います。 書籍自体も難解な箇所はないため、サクッと読み進められるはずです。 また、疑問点や感じた細かいことはtwitterでつぶやけば有識者や公式から助言をもらえることも多いです。 失敗と工夫 時間がかかってしまう チームの学習 SaPIDの導入にあたりファシリテートを務める人が書籍や勉強会で学習コストを払っているかと思います。 しかし、チームで行う場合、全員がSaPIDのことをある程度知らなければなりません。 全員に書籍を読んでもらい勉強会やSaPID Bootcampに申し込んでもらうわけにもいきません。 ファシリテートを務める人がキックオフを行ったり、各STEPのはじめに説明を行うなど手厚くサポートをしたほうが良いでしょう。 SaPIDでは参加者のことを尊重することが大事であると 明言 されています。 仮にやり方に誤りがあっても大きな問題ではありませんので、正しさよりも参加者の改善へのやる気や積極性を損なわないように進めてください。 SaPIDは一度で終わりではありませんので、困ったことがあればその次の実施時に改善するだけのことです。 実施の長期間化 どんなことにも言えますが、初めての実施には時間がかかります。 ひとつずつ手順を確認したり、課題や意見を挙げるにも「何を考えるか」を考える時間がか かって しまうでしょう。 他にもSaPIDの STEP2にあたる情報の精査や、STEP3の構造化 を行う際の合意形成や構造図の整理など、コツを掴めば早くなるのですが要領を得るまではどうしても時間がかかります。 書籍の中で挙げる課題の数の目安について経験上20個程度と言及されているのですが、いざ実施すると本当にそのくらいの数がちょうどよいです。 はじめのSTEPで課題が多く上がると後のSTEPすべてに影響が出てくるため、優先順位づけをして挙げる数を絞ってもらうなどの工夫をすると良いでしょう。 書籍の中にはこういったTipsが随所に書かれているため、もし特定のSTEPで困った場合は改めてその章を読み直してみるとヒントが得られるかもしれません。 参考:挙げた課題が多くなりすぎて複雑化してしまった問題構造図 ファシリテーター兼当事者 自分を含め、導入を推奨する立場の人は、ファシリテーター兼当事者になってしまう問題があります。 進行上は大きな問題ではなく、むしろ他の参加者は見様見真似で進められるためスムーズになるのですが、 ファシリテーターがファシリテートではなく、SaPID全体の流れをファシリテーターの考える方向に誘導してしまいがちになります。 初回であればSaPIDに慣れるためにそのような進め方でも悪くはないかと思いますが、 慣れてきたらあくまで参加者の意見を引き出したり、課題の深堀りや隠れた別の課題を洗い出すことに専念するよう意識する必要があります。 私自身、これがうまく出来ている自信はないですが、参加者を巻き込んだ一人舞台にならないように常に意識しています。 問題解決慣れ エンジニアであるがゆえの問題として、普段から問題解決に慣れていることが挙げられます。 日々、様々な問題を解決しているからこそ、課題を挙げるSTEPでも解決策を考えてしまいがちです。 問題を洗い出すフェーズではあくまで問題を洗い出すにとどめ、問題を精査する際も深堀りは行いますが解決策まで考えてしまわないように留意しなければなりません。 我々はつい「こうすればよいのではないか」「こんな手法がある」「〇〇があれば解決する」と考えてしまいがちです。 ファシリテートを行う人が意識するのはもちろん、参加者にも都度伝えておいたほうがよいです。 おわりに 今回はSaPIDについてご紹介しました。 日々の業務に課題や不満、不安を感じることがあれば、SaPIDの導入を考えてみてはいかがでしょうか。 チーム全員で大々的に始めることが難しければ、賛同してくれる人だけで小さく回して少しずつ周囲を巻き込んでいくとよいでしょう。
こんにちは。Ltech運営チームの河西です。今回は、2021年7月13日(火)に開催した「Ltech#18 AIで住まい探しをスムーズに!【おとり物件予測&3D間取り】」についてレポートします。 lifull.connpass.com Ltechとは Ltech(エルテック)とは、LIFULLがお送りする、技術欲をFULLにするイベントです。特定の技術に偏らず、様々な技術の話を展開していく予定です。 AIで住まい探しをスムーズに Ltech#18のテーマは、住まい探しをより便利にするためのAIを使った取り組みです。LIFULLでは2018年よりAI戦略室を立ち上げ、「創造と革進で喜びを届ける」をビジョンに掲げ、様々な取り組みを行ってきました。今回はその中でも 物件間取り図の3D化 おとり広告予測モデルの開発 といった内容の取り組みを語ってもらいました! それではさっそく発表レポートに行きたいと思います。 3D間取りを支える技術 最初は3D間取りを支える技術の発表です。 3D間取りを支える技術 from LIFULL Co., Ltd. www.slideshare.net 3D間取り図とは、LIFULL HOME'Sにおける2次元の間取り図をディープラーニング技術の活用により、画像認識・ポリゴン化して3Dモデルとして可視化し、より実際の物件に近い形で見ることができるサービスです。 これにより、従来1件あたり数万円の作成コストがかかっていた3Dモデルを安価・大量に生成ができるようになるようになりました。 ※3D間取りはこちらから実際に体験できます! https://www.homes.co.jp/3dmadori 次にそんな3D間取り図サービスを支えている技術を見ていきます。 3D間取りを支える技術は非常に広範囲に渡っています。特に、LIFULLでの全社アプリケーション実行基盤である「KEEL」を活用することにより、AIに特化したエンジニアでもシステム構築の負荷が軽減され、サービスの早期リリースが実現できたとのことです! ※KEELは過去CreatorsBlogでも紹介しています。 www.lifull.blog 次に間取り図画像の認識や、工夫しているポイントについてです。 間取り画像の認識については、3つの層に分け出力を行い、3Dモデル化しているそうです。3Dモデルとして可視化する際にも工夫している点として、 3Dモデル内の移動を簡単にするために、ポリゴン化したデータに移動点を作成して、移動データを付与 2次元間取り図内に浴室やトイレといったアイコンがない場合でも、独自のルールで設置し、可視化 などといった点についても話してもらいました。 最後に今後の展望については360度カメラを使ったフォトグラメトリの活用・家具配置シュミレートなども実現していきたいと語ってもらいました。 3D間取り図の開発には2~3年を要し、データの収集に苦労したり、機械学習モデルを何度も変更したりと、このような素晴らしいサービス誕生の裏には絶え間ない努力があるのだと感じました! LIFULL HOME'Sのおとり広告予測モデルの開発 続いておとり広告予測モデルの開発の発表です。 LIFULL HOME'Sのおとり広告予測モデルの開発 from LIFULL Co., Ltd. www.slideshare.net おとり広告とは、LIFULL HOME'S上で「成約済み物件の広告の消し忘れ」や「呼び込みのための架空物件の広告」など実際には契約ができない物件広告が存在している状態です。おとり広告があることにより、ユーザーは安心して住まい探しができないといった問題があります。LIFULL HOME'Sでは、 専属の情報審査チームによる能動調査 不動産管理会社とデータ連携 掲載110番 といった形でおとり広告をなくす取り組みを行っていますが、今回は「専属の情報審査チームによる能動調査」にAIを取り込み、募集終了物件の特徴を学習させて、募集終了確率を予測するAIを開発しました。 次に実際の能動調査の流れやAI学習から調査対象予測までの流れを見ていきます。 従来の専属の情報審査チームによる能動調査では審査チームが一定のルールに基づいて、調査対象物件リストを調査しています。そのため ルールでは選定できない物件がある ルールの複雑化への対応が難解 などの問題がありました。 AIを用いた機械学習フローの導入では、一定ルールに基づいた物件リストデータを用いますが、今度はAI学習用データに偏りが生じ、結果的に募集終了確率の精度が悪化してしまう問題が発生しました。そこで、精度を向上させるために、一定ルールではなく、無作為にデータを抽出することで、偏りをなくし、学習モデルの精度を向上させる取り組みを行ったそうです。 また、このようなモデル開発を効率的に行うための工夫として、BigQueryを用いたデータ加工、AutoML Tablesでの学習自動化、一連の流れをAirflowでスケジューリングし、機械学習フローを全自動化する効率化も合わせて行ったとのことでした! 最後に、おとり物件をゼロにすることが最終的な目標と語ってもらい、ユーザーがより安心して住まい探しができる未来の実現に向けて、素晴らしい取り組みだと感じました! まとめ 今回はAIを用いて住まい探しをよりスムーズにするための取り組みをお二方に発表してもらいました。今回発表されたもの以外にもAI戦略室では様々な施策を計画中とのことで、今後どのようなサービスが出てくるのか非常に楽しみです! 最後に Ltechでは、LIFULLエンジニアが中心となって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。今後も Ltech を積極的に開催していきますので、ぜひ気になった方は、connpass で LIFULL のメンバー登録をよろしくお願いします! lifull.connpass.com
こんにちは! KEEL チームの花塚です。 最近一番驚いたことは、OPA Gatekeeperの「OPA」を「オーパ」と発音するらしいということです。 さて今回は、OPA GatekeeperやConftestなどを用いてKubernetesのセキュリティ面を強化した話です。 以前からチームメンバー全員がセキュリティに気を配っているものの、今まで対策していることが妥当なのか、考慮漏れはないだろうかということを定期的に確認する機会がありませんでした。 闇雲に対策せず一度自分たちの対策を見直し、継続的にセキュリティを向上していける仕組み作りの過程をお伝えできればと思います。 目次 目次 解決したかった課題 OPA Gatekeeperとは Pod Security Policyの廃止 Kubernetesへの脅威 本番環境に導入するまで GatekeeperとConftestで使用するRegoを同期させる ConstraintとConstraintTemplateをクラスタへ適用する GatekeeperとConftestのテスト CIの形骸化を防ぐ おわりに 解決したかった課題 改めてセキュリティ対策を進める上で解決したい課題がありました。 それは「マニフェストの監査が自動化できていない」ことです。 KEELはマルチテナント構成をとっており、各サービスのマニフェストを一つのクラスタにデプロイします。 人力で各サービスのマニフェストのチェックすることは、不適切な設定・悪意のある設定の見落としなどが発生する可能性がありましたし、そのようなマニフェストをデプロイできない仕組みが必要でした。 結論としてOPA GatekeeperとConftestを採用しており、この後に詳しく紹介します。 OPA Gatekeeperとは 解決したい課題でも触れたように、結論としてはOPA Gatekeeperを採用しました。ここでは簡単にOPA Gatekeeperについて紹介します。 OPA Gatekeeper(以降、Gatekeeper)は、KubernetesのAdmission Controllerとして動作し、アンチパターンなマニフェストのデプロイの禁止などを可能にするカスタムコントローラーです。 github.com 以下の例では、 Constraint と ConstraintTemplate のCustom Resourceをデプロイすることで hostPID: true であるPodのデプロイを禁止することができます。 package deny_host_pid violation[msg] { input.review.object.spec.hostPID msg := sprintf( " Sharing the host pid is not allowed: %v " , [input.review.object.metadata.name]) } 上記の例でも分かる通り、Gatekeeperは、内部でポリシーエンジンである Open Policy Agent を使用しているためポリシーの記述にRegoを使用します。 強い権限を用いているマニフェストのデプロイを禁止するなど、セキュリティ面でも活用できますが、Istioの VirtualService や Gateway の衝突を防ぐなど、さまざまなユースケースを実現することができます。 余談ですが、Regoを使うことで汎用的にポリシーを記述することができる一方、「学習コストが高そう」 、「少し苦手」という方がいるかもしれません。 最近ではRegoの学習への課題を解決するために、ポリシーをyamlで記述できるKubernetes NativeなKyvernoが開発されています。 github.com Pod Security Policyの廃止 Kubernetesクラスタのセキュリティ面を強化していく意思決定をした際、まず最初に解決策として候補に上がったのが Pod Security Policy です。 PodSecurityPolicy を使うことで、Privileged containerのデプロイなど、セキュリティ的に好ましくない行動を制限することができます。 しかし PodSecurityPolicy は、Kubernetes v1.21から非推奨となり、v1.25からは廃止となることが発表されました。 github.com 先ほど紹介したようにGatekeeperは、さまざまなポリシーを記述することができます。 PodSecurityPolicy でできることは、多くのことがGatekeeperでも実現可能です。 実際にGatekeeperのlibraryでは、 PodSecurityPolicy をRegoで記述した サンプルコード が置かれています。 KEELでは、以前からGatekeeperを使っていることや廃止されることを考慮して、 PodSecurityPolicy の代わりとなるものをRegoで記述する意思決定を行いました。 また、Gatekeeperと似たような用途として使える Conftest というツールがあります。 Gatekeeperは実際にクラスタ内でリソースが違反していないかを動的にチェックしますが、一方Conftestは、Kubernetesのマニフェスト(マニフェスト以外にも対応しています)が違反していないかを静的にチェックします。 ConftestをCIに組み込むことで、デプロイ前にマニフェストがポリシーに違反してないかを確かめることが可能です。 ConftestもGatekeeperと同様にポリシーをRegoで記述するため、Gatekeeperとセットで採用しています。 ちなみに PodSecurityPolicy は廃止されるようですが、今後は PodSecurity admission が PodSecurityPolicy の代替となるようです。 Kubernetesへの脅威 Kubernetesに限らずセキュリティ対策を行う場合は、まずは「脅威を知る」ということが重要になります。 最初はKubernetesのセキュリティの全体感を、以下のような記事を読んで把握することをおすすめします。 クラウドネイティブセキュリティの概要 | Kubernetes Matrix - Enterprise | MITRE ATT&CK® Threat matrix for Kubernetes NIST SP 800-190 今回Kubernetesのセキュリティ対策を考える上で参考にしたのが、Kubernetesを対象とした以下の脅威モデリングのレポートです。 github.com このレポートは2020年1月に作成されているので少しだけ古いですが、一般的なKuberentesクラスタを対象とした主なAttack Vectorを把握することが可能です。 またAttack Treeもレポートに含まれており、ある攻撃を達成するための大まかな道筋を把握することもできます。 例えば以下の「Malicious Codeの実行」に関するAttack Treeでは、Privileged containerを利用したステップなどが必要であるということが分かります。 引用: https://github.com/cncf/financial-user-group/blob/master/projects/k8s-threat-model/AttackTrees/MaliciousCodeExecution.md このように攻撃の目的を達成する道筋を把握することで、「Privileged containerのデプロイを禁止する」など具体的な対策を考案することができます。 AWSやGCPなどのクラウド上でKubernetesを運用している場合は、「使用している権限(IAM Userなど)でどこまで悪用できるのか」を考慮するなど、自分たちの環境と照らし合わせて対策を考えることが大切です。 このように簡単に脅威を洗い出すだけでも、対策への妥当性を説明できることやコストに見合った対策を優先して取り組めると思います。 本番環境に導入するまで さて、ここからはセキュリティ対策を本番環境へ導入するまでの過程について書いていきたいと思います。 GatekeeperとConftestで使用するRegoを同期させる ConftestとGatekeeperで同じ内容のポリシーを記述する場合でも、以下の理由からRegoを併用することができません。 少しだけ文法に差異がある Gatekeeperでは ConstraintTemplate に直接Regoが埋め込まれる GatekeeperとConftestのRegoが別々で管理されるということは、どちらか一方を変更した場合、もう一方のRegoも変更しなければなりません。それは不便ですよね。 そこでKEELチームでは、GatekeeperとConftestのRegoを併用するためにkonstraintを導入しました。 github.com ここでは詳しく説明しませんが、konstraintの library を使用することで、GatekeeperとConftestのRegoの差異を吸収してくれます。 以下がkonstraint用に書き換えたポリシーです。 core や pod ライブラリをimportしています。 package deny_host_pid import data.lib.core import data.lib.pods policyID := " P1000 " violation[msg] { pod_has_hostpid msg := core.format_with_id(sprintf( " %s/%s: Sharing the host pid is not allowed " , [core.kind, core.name]), policyID) } pod_has_hostpid { pods.pod.spec.hostPID } ポリシーを記述した後に、以下のコマンドを実行すれば Constraint と ConstraintTemplate が生成されます。 $ konstraint create <policy_dir>. 現在はkonstraintとGithub Actionsを併用することでRegoのファイルを更新しただけで、自動で Constraint , ConstraintTemplate のファイルを生成・更新するようにしています。 ConstraintとConstraintTemplateをクラスタへ適用する Constraint と ConstraintTemplate を何も考えずにクラスタに適用してしまうと、意図していないリソースまでも影響を受ける可能性があります。 enforcementAction: dryrun を使用し、一定期間様子を見ながら適用することをおすすめします。 また、Gatekeeperではデフォルトでメトリクスを公開しているため、違反している Constraint 数も知ることが可能です。どの Constraint が違反しているかは、今のところメトリクスからは判別できないようです。 github.com Gatekeeper v3.4.0からは、 enforcementAction に warn が追加されたそうなので、本番環境での Constraint の使い分けがいろいろとできそうです。 GatekeeperとConftestのテスト 本番に適用することを考えると、記述したRegoのテストについても考慮しなければなりません。 セキュリティに関する機能のテストはとても重要です。いつの間にか攻撃し放題になっていたら嫌ですよね。 まずは記述したRegoのテストについてですが、先ほど説明したようにkonstraintを使用することで、RegoをConftestとGatekeeperで同期させています。 そのため片方のRegoが正しく動くということを証明できれば、もう一方のRegoも同様に正しく動くということが言えそうです。 Conftestの場合、cliで verify コマンドを使用すると、xxx_test.regoというファイルのテストケースを実行してくれます。 $ cat policy/privileged-container/src_test.rego package privileged_container test_privileged_true { input := { "securityContext" : { "privileged" : true }} container_is_privileged(input) } test_privileged_false { input := { "securityContext" : { "privileged" : false }} not container_is_privileged(input) } $ conftest verify 2 tests, 2 passed, 0 warnings, 0 failures またKEELでは、e2eテストを定期的に実施しています。 www.lifull.blog 以下のようにGatekeeperのテストケースを書いておけば、意図しないデプロイが防がれているかを定期的に確認することができます。 Describe( "Gatekeeper" , func () { Context( "when try to deploy deployments" , func () { f := framework.NewFramework(basename, framework.Options{ClientQPS: - 1 }, nil ) f.SkipNamespaceCreation = false BeforeEach( func () { gatekeeperTester.cs = f.ClientSet gatekeeperTester.namespace = f.Namespace.Name }) It( "should be successful to deploy a normal deployment" , func () { gatekeeperTester.createNormalDeployment() }) It( "should be failed to deploy a violated deployment" , func () { gatekeeperTester.createViolatedDeployment() }) }) }) CIの形骸化を防ぐ CIにおけるセキュリティ等のベストプラクティス(今回だとConftestのポリシー)を提供する場合に考慮すべきことは、「CIの形骸化」です。 Linterなどを導入してみたはいいが、結局無視している状態になることは少なくないと思います。 KEELではCIを形骸化させないために、CIのテストに失敗したら 必ず 対応する方針にしています。 これは言い方を変えると、「必ず対応すべきポリシーやテスト のみ を提供する」ということになります。 「できれば対策をしたほうがいい」ようなものは提供せず、あくまでガードレールのような開発する上で必ず対策しておきたいものを提供しています。 また、各種Linterの出力をrunbookに変換できる runbook-translator というソフトウェアも開発しています。 各Linterの出力を、reviewdogの errorformat を用いてParseして変換することにより、開発者に何をしてほしいのかを具体的に指示します。 github actions comment errrorformatを使うことで、Linterの特定のエラーコードは無視するなども可能です。 おわりに いかがでしたでしょうか。Kubernetesにおけるセキュリティ対策を、考案から本番環境に導入するまでの流れを紹介しました。 今回の取り組みは、脅威を洗い出して対策を考案したこともあり、間違いなくクラスタのセキュリティを向上させたと思います。 また対策に必要な工程の一部を自動化させたことで、今後も継続してセキュリティ対策に取り組めると思います。 まだまだセキュリティ関連でもやることがありますので、これからも取り組みを発信していきます。 それではまた次回のブログで!
こんにちは。テクノロジー本部の稲垣です。 LIFULLでは、提供するサービスによって、様々なDBが稼働しています。 異なるDBエンジン間でのデータ移行が必要となるプロジェクトが立ち上がることとなり、AWSが提供しているAWS Database Migration Service(AWS DMS)による検証を行う機会がありました。 www.lifull.blog AWS Database Migration Service(AWS DMS)がリリースされて間もないころに、一度検証目的で使ったことがありましたが、今回使ってみて、色々と分かったことがあったので、紹介します。 AWS Database Migration Service(AWS DMS)とは エンドポイント レプリケーションインスタンス(Replication Instance) データベース移行タスク(Replication task) DMSを使用した2つのデータ移行パターン 移行用の環境を別途作り、動作確認した上で移行 サービス運用しながらデータ移行 継続的なレプリケーション(CDC)を使用する際の注意点 ソースDB側の更新量に合わせた、レプリケーションインスタンスのサイジング データベース移行タスクの設定について テーブル作成モードと再開・再起動 CDCのTransactional Apply ModeとBatch Apply Mode DMSの検証 DMSのログ 実際に使用する前に確認しておくこと おわりに AWS Database Migration Service(AWS DMS)とは docs.aws.amazon.com AWS Database Migration Service (AWS DMS)は、リレーショナル データベース、データ ウェアハウス、 NoSQL データベース、その他の種類のデータストアなど、さまざまなデータベースを格納できます。AWS DMS を使用して、オンプレミスのインスタンス間 (AWS クラウドセットアップを使用)、またはクラウドセットアップとオンプレミスセットアップの組み合わせの間で、AWS クラウドにデータを移行できます。 https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/Welcome.html より一部抜粋 Oracle,MySQL,PostgreSQL,MariaDB,Microsoft SQL Server,Db2,Amazon DynamoDB,Amazon S3など、様々なデータベースに対応しています。 また、RDS-RDS間でも利用することができます。 AWS Database Migration Service(以下 DMS)は、「レプリケーションインスタンス」を作成して、ソースおよびターゲットの「エンドポイント」を指定します。 そして、「データベース移行タスク」を作成して、移行処理を実行させるといった流れです。 AWS DMSレプリケーションプロセス https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_GettingStarted.html より抜粋 上記の説明で出てきた、以下の3つについて説明します。 エンドポイント データベース移行タスク レプリケーションインスタンス エンドポイント データベースの接続情報の定義 ソースDB(Source Database)とターゲットDB(Target Database)それぞれに存在する レプリケーションインスタンス(Replication Instance) ソースDB、ターゲットDBとの接続を確立し、ソースDBで発生した変更内容をキャッシュする データベース移行タスクが実行されるインスタンス データベース移行タスク(Replication task) ソースDBとターゲットDBの間でデータ移行を実際に行う場所 移行タスクのタイプが「フルロードのみ」、「フルロード+継続的なレプリケーション(CDC)」、「継続的なレプリケーション(CDC)のみ」によって、タスクの動作が異なります。 フルロードのみ:ソースDBから既存のデータをフルロードし、レプリケーションインスタンスにキャッシュし、ターゲットDBに適用 フルロード+継続的なレプリケーション(CDC):フルロードが終わった後に、ソースDBで変更があった内容を定期的に読み込み、レプリケーションインスタンスにキャッシュし、変更データをターゲットDBに反映させる 継続的なレプリケーション(CDC)のみ:フルロードは行わずに、ソースDBで変更があった内容を定期的に読み込み、レプリケーションインスタンスにキャッシュし、変更データをターゲットDBに反映させる 今回は、 フルロードのみ および 、フルロード+継続的なレプリケーション(CDC) での検証を行いました。 DMSを使用した2つのデータ移行パターン 実際にDMSを使用して、データ移行を行う場合、以下の2つのデータ移行パターンを想定しました。 移行用の環境を別途作り、動作確認した上で移行 サービス運用しながらデータ移行 移行用の環境を別途作り、動作確認した上で移行 【データ移行の流れ】 既存の本番環境と並行して、新しいDBに読み書きするアプリケーションを開発 データ移行用のターゲットDBを作成 データ移行タスクを設定 データ移行タスクをフルロード実行(新しいDBにソースDBのデータが反映される) 新しいDBを参照して、動作確認 アプリケーションを本番環境にリリースする際は、一時的にサービスを止める データ移行タスクを停止し、フルロード実行 新しいアプリケーションをリリース(以降は新しいDBに対して読み書き) 【メリット】 事前に動作確認を行っているため、本番環境での不具合を事前に発見できる テストをして問題があった場合も、環境を再構築すれば切り戻しできる 【デメリット】 環境構築に時間がかかる 同じ機能のソースプログラムを複数管理しなければならない サービス運用しながらデータ移行 【データ移行の流れ】 データ移行用のターゲットDBを作成 データ移行タスクを設定 ソースDBの変更内容をターゲットDBへ定期的に反映 アプリケーションのDB参照先を段階的にソースDBからターゲットDBに変更 移行テーブル対象が増える際は、データ移行タスクを一時的に止めて、テーブルマッピングに追加→データ移行タスクを再開 【メリット】 リリースを止めずにデータ移行ができる 最小限の構成でデータ移行ができる 【デメリット】 データ移行後に問題が発生した場合の切り戻しが困難 本番環境に影響が出てしまった場合、事業へのマイナスインパクトがある 安全性を重視するのであれば「移行用の環境を別途作り、動作確認した上で移行」、多少安全性を犠牲にしても、工数を優先するのであれば「サービス運用しながらデータ移行」といった選択になります。 今回は、移行ケースとして、「サービス運用しながらデータ移行」を想定し、Data Migration Serviceの設定を行いました。 DMSの設定については、web上で紹介しているページがありますが、実際にやってみると、分かりにくい箇所がいくつかあったため、紹介します。 継続的なレプリケーション(CDC)を使用する際の注意点 ソースDB側の更新量に合わせた、レプリケーションインスタンスのサイジング 今回の移行ケースでは、ソースDBに更新が発生する状態で、ターゲットDBにデータ移行を行います。 よって、フルロード+継続的なレプリケーション(CDC)を採用するため、以下の流れでデータを反映していきます。 ソースDBで変更が発生 ↓ レプリケーションインスタンスで変更内容をキャッシュ ↓ ターゲットDBに反映するためのSQLを生成 ↓ ターゲットDBに対して生成したSQLを実行し、変更を反映 ソースDBでのトランザクション処理順に、ターゲットDBに反映するための内容をレプリケーションインスタンス内でまとめて、ターゲットDBへ反映する処理を繰り返しています。 つまり、ソースDB側の更新量が多くなると、その分レプリケーションインスタンス内での処理にかかる負荷が増えていき、レプリケーション遅延を引き起こしやすくなります。 データベース移行タスクの設定について データベース移行タスクについて、少し前で触れました。 データベース移行タスクを設定する際は、主に以下の2つです。 タスク設定 テーブルマッピング タスク設定、テーブルマッピングともに、AWSコンソール上で直接設定する方法と、json形式で設定する方法があります。 テーブルマッピングについては、テーブル数が多いケースでは、json形式で設定したほうが楽です。 タスク設定については、検証時に設定した内容について触れます。 テーブル作成モードと再開・再起動 タスクを設定して、テーブルマッピングで設定したテーブルに対して、どういったモードで再開するかを設定できます。 テーブルマッピングの変更などで、定期的にタスクを停止および再開する際に使用します。 テーブル作成モードには、以下の3つがあります。 何もしない:タスクを停止したときの状態のまま ターゲット上のテーブルを削除:ターゲットDBのテーブル自体を削除 TRUNCATE:ターゲットDBのテーブルは残したままで、テーブルのデータのみ削除 そして、タスクを再開すると、新規にテーブルマッピングが追加されたテーブルについて、 テーブル作成モードが適用されます。 一時的にテーブルマッピングから外したテーブルを、再度追加した際に、テーブル作成モードを「何もしない」以外にしてしまうと、ターゲットDB側の該当テーブルのデータが消えてしまうので、注意が必要です。 CDCのTransactional Apply ModeとBatch Apply Mode DMSタスクはデフォルトでは、 Transactional Apply Mode です。 ソースDBでトランザクションがコミットされた順にターゲットDBへ適用されます。 一方で、ターゲットDBへの書き込み量を減らしたり、まとめて書くことで効率的に動作させることで、高パフォーマンスが期待できる Batch Apply Mode が存在します。 タスク設定のBatchApplyEnabledをTrueに設定することで、有効化できます。 Batch Apply Modeの場合、以下のようにまとめて変更を行うため、ソースDBでトランザクションがコミットされた順で、必ずしも反映されない可能性があります。 一定期間にソースDBに行われた変更をレプリケーションインスタンス上にキャッシュ ↓ 同一テーブルに対する複数のクエリはDMS側でまとめられる ↓ 最終的な変更をまとめてターゲットへ書き込む 今回の要件では、「サービス運用しながらデータ移行」することが前提であり、ソースDB内のテーブル間で依存関係があるテーブルが複数存在していたため、Batch Apply Modeの適用は見送りました。 DMSの検証 タスク設定に「検証の有効化」というチェックボックスがあります。 「検証の有効化」チェックボックス チェックボックスの下の説明には、以下のように書かれています。 全データのロードを実行した後すぐにAWS DMSでソースとターゲットのデータを比較する場合は、この設定を選択します。 検証することで、データが正確に移行されたことを確認できますが、完了するまでに通常より時間がかかります。 ソースDBとターゲットDBで、同じDBエンジンでデータベースの文字コードが異なる場合、DBエンジンが異なる場合など、ソースDB側に特殊文字などが入っていることが原因で、ターゲットDBに移行できないデータが存在するケースがあります。 その場合、ソースDBとターゲットDBで差分が生じてしまうのですが、DMSの検証を有効化することで、AWSコンソール上で差分が発生しているテーブルと原因となっているデータなどを検出してくれます。 データ移行で漏れが発生してしまうと、大きな問題になる可能性もあるので、データを確実に移行したいケースでは有効化するのがオススメです。 テーブルマッピングに設定したテーブル全てが、DMSの検証対象です。 しかし、以下の点に該当する場合は、有効な検証結果が得られない、大幅なレプリケーション遅延が発生するなど、サービスに影響が出てしまう可能性があります。 ソースDB側で大量の更新が定期的に発生するテーブルが存在する ソースDB側に膨大なレコード数、およびカラム長が長いなど、データ量が多いテーブルが存在する DMSの検証処理自体は、レプリケーションインスタンスで行われますが、ソースDBの変更をターゲットDBに反映するレプリケーション処理も、同じくレプリケーションインスタンスで行われています。 よって、DMSの検証処理、レプリケーション処理どちらかの負荷が大きくなると、もう片方の処理にも影響を与えてしまう可能性があります。 例えば、「サービス運用しながらデータ移行」するケースで、ターゲットDB側も既にアプリケーションで利用されている場合は、DMSの検証を有効化することで、レプリケーション処理自体が遅延してしまうというリスクを抱えてしまうことになるので、設定にあたっては検討が必要です。 DMSのログ DMSのログとしては、以下があります。 DMSタスクログ ClouwdWatch Logsに出力される DMSタスク例外情報 ターゲットDB内にテーブルawsdms_apply_exceptionsが作成され、エラーが発生したテーブルやエラー情報が格納される DMSの検証情報に関するログ ターゲットDB内にテーブルawsdms_validation_failures_v1が作成され、エラーが発生したテーブルやエラー情報が格納される awsdms_apply_exceptionsについては、カラムSTATEMENTに、ターゲット側でエラーが発生したときに実行されたステートメントが記録されます。 awsdms_validation_failures_v1については、カラムDETAILSに、DMS検証時に指定されたキーと一致しないすべてのソース/ターゲット列値のJSON形式の文字列(エラーとなったデータ)が記録されます。 実際に使用する前に確認しておくこと 色々と説明しましたが、DMSを本番稼働しているサービスに使用する場合、以下の点について、確認しておいたほうがよさそうです。 データ移行パターン(サービス運用しながら・移行用の環境を別途作る・開発を一定期間止める) サービス運用しながらデータ移行する場合は、データ移行するソースDBで更新頻度が高いものがないか 移行するテーブル間で依存関係があるものがあるか(依存関係がない場合は、Batch Apply Modeモードの適用も検討) DMSタスクの数(複数稼働させる場合は、対応するレプリケーションインスタンスも用意するか) DMSの検証有効化有無(DMSの検証を無効化する場合は、ソースDBとターゲットDBの差分チェック方法の検討) おわりに 実際にData Migration Service(DMS)を使ってみて、分かりにくかった点について紹介しました。 オンプレミスで動いているDBをAWSへの移行を検討している、もしくはAWS内で別のDBエンジンへの移行などで、Data Migration Service(DMS)の利用を検討している方にとって、少しでもこの記事がお役に立てたら幸いです。
こんにちは。Ltech運営チームの井坪です。 今回は、2021年6月8日(火)に開催した『Ltech#17 実録!LIFULLアジャイル導入までの挫折と取り組み』についてレポートします。 lifull.connpass.com Ltechとは Ltech(エルテック)とは、LIFULLがお送りする、技術欲をFULLにするイベントです。特定の技術に偏らず、様々な技術の話を展開していく予定です。 LIFULLアジャイル導入までの挫折と取り組み Ltech#17のテーマは『アジャイル』です。日本でも多くの企業でアジャイル開発が導入されてきていますが、導入したけどうまく使われていないといったことも耳にされることが多いかと思います。特に大企業では既存の業務の進め方が存在し、アジャイルな開発がやりにくい場合も多いようです。LIFULLでの導入事例を踏まえて、導入時の課題や推進していく条件、体制作り・運営の苦労や工夫について語っていただきました。 大企業でアジャイル開発を推進できる条件とその心構え 大企業でアジャイル開発を推進できる条件とその心構え from LIFULL Co., Ltd. www.slideshare.net 最初の発表は『LIFULLで経験したアジャイル開発の導入における課題』とその経験から学んだ『アジャイル推進していくための条件』について発表していただきました。 LIFULLでは2013年頃、開発スピード向上のためにスクラムが導入されるようになりましたが、開発体制や当時のリリースフローの影響もあり運営が難しく下火になっていました。 その後、2018年頃から中途入社メンバー中心に各部署や各プロジェクトでスクラムが採用されるようになり普及し始め、今ではアジャイル勉強会の開催やスクラムサークルの活動が行われるようになりました。 アジャイル導入・運営から学んだ「推進してくための条件」は以下のようです。 ※発表者個人の見解になります。 * 型に囚われない * 考えるきっかけを作る * 土壌を作る 開発チームにはスクラムの経験者と未経験者がいる場合もあり、最初から完全なスクラムの型を目指す必要があるのか。 最初から完全な型通りに進めようとすると難しく上手くいかないこともあったりします。 どこに課題があるか気付いてもらうところから始め、チーム内で解決策を話し合い考えてもらい、世の中で起きている変化や課題に対してどう対応していくのかを話し合うことでチーム全員が納得して進められるようになっていきます。 スクラムを利用したアジャイルオフショア開発のとりくみ スクラムを利用したアジャイルオフショア開発のとりくみ from LIFULL Co., Ltd. www.slideshare.net 次は、LIFULLにはベトナムのホーチミンに開発子会社である『LIFULL Tech Vietnam(LFTV)』があり、LFTVとの開発においてスクラムを利用したオフショア開発のために取り組みについて発表していただきました。 リモートワーク全体の問題としてチーム間のコミュニケーションが不足するうえ、開発チームは日本とベトナムに分かれているので、デイリースクラムで雑談する機会を設けてコミュニケーションを図ったり、 ベトナムチーム側の問題を検知しづらいため雑談を兼ねた定期的な相談できる場を設けているそうです。 最後に 今回はLIFULLでアジャイル開発を導入・推進されている お2人に発表していただきました。LIFULLの事例や個人の意見ではありますが、今後アジャイル開発を導入しようとしている方々やアジャイル開発で困っている方々のご参考になれば幸いです。 Ltechでは、LIFULLエンジニアが中心となって皆様の技術欲を満たすよう実例を交えた勉強会を開催しています。 今後もLtechを積極的に開催していきますので、 ぜひ気になった方は、connpassでLIFULLのメンバー登録をよろしくお願いします! lifull.connpass.com