Medley Developer Blog

株式会社メドレーのエンジニア・デザイナーによるブログです

技術を使うための技術も大切というお話

初めまして。CLINICS の開発を担当しているエンジニアの平山です。 (同姓ですが CTO ではございません)

CLINICS の開発は「スモールチーム制」をとっておりまして、現在そのうちの1つをチームリードしています。

前職は長らく SIer に勤めていました。去年の12月にメドレーに JOIN して、間も無く1年経とうとしている。。と思うと、あっという間だったなぁという印象です。

さて、本日はメドレーで隔週開催している社内勉強会(TechLunch)において発表した内容についてご紹介させて頂ければと思います。

はじめに

「技術を使うための技術」というテーマとなりますが、プロダクト開発をしていく上では欠かせない素養と考えています。メドレーに所属しているエンジニアの1人として、どのように日々課題と向き合っているのか。当テーマを通してお伝えできればと思います。

また、この考え方自体は「医療というテーマ」や「事業の背景(ベンチャーSIer)」を問わず必要とされる場面があるかもしれません。(自身も前職では様々な場面でお世話になりました...)

即効性のあるものではありませんが、じわじわ効いてくる内容ではないかと思います。よろしければお付き合いください。

本題

「技術を使うための技術」

みなさんはこの言葉から、何を思い浮かべるでしょうか。筆者が試しに Google で検索した際上位にヒットしたのは

AIエンジニア
IoT

といった結果でした。なるほど。少し雑に解釈すると「技術(アルゴリズム等)を使うための技術(機械学習、家電等)」といった感じなのでしょうか。(この結果を拾ってきたというのも、いい意味で Google すごいなって感じました)

筆者が今回のテーマとして指しているのは、下記となります。

ロジカルシンキング
推論

これらの 思考を整理する「手段」 とエンジニアの武器である 技術という「手段」 をかけ合わせることで、大きなテーマである「医療」に向き合っています。

手段を目的にしてはならない

先に挙げたとおり「思考の整理」も「技術」も 「手段」 に過ぎません。これらを用いて、適切な一手を指していく為には「目的」に対する解像度を高く描く必要があります。

筆者の発表から抜粋した「技術を使うための技術」の要素をイメージした図

f:id:medley_inc:20201023135338p:plain

整理力

目的を達成する為に必要な「情報」を取捨選択するための要素。

SaaS ✖️ toB の世界においては「プロダクトが解決すべき課題か否かを業務の本質を踏まえて取捨選択する」と言い換えられるかもしれません。

業務知識

目的の「解像度」を高めるための要素。

CLINICS においては、医療情報を扱う上での規制(3省2ガイドライン)や、医療機関(医師・医事・診療科の特性)の業務、診療報酬についての知識、法改正、レセコン(ORCA)... と様々あります。

技術知識

目的を達成する為に必要な「指し手」を選択するための要素。

(エンジニアにとっては説明するまでもない内容であると思いますが) ここが欠けてしまうと絵に描いた餅で終わってしまいます。メドレーのエンジニアにおいても日々研鑽し、プロダクトに対してコミットを続けています。

行動力

目的を達成するための「推進力」を高めるための要素。

各種知識と整理した情報を推進力に変えていく為には、その時の状況に応じた動きをする必要があります。ステークホルダーとの調整は当然ですが、組織内連携といった「横の動き」も必要です。

想像力

これまで挙げたそれぞれの手段を適切に利用していくための要素としての土台が「想像力」であると考えています。

課題(Issue)への取り組み例

f:id:medley_inc:20201023135418p:plain

番号 概要
Issue に取り組む際に「本当に解決すべきこと」についての想像を働かせます。Issue に記載されていることが 本当にプロダクトとして解決すべきことなのか を含めて考えます。これまでの運用が必ずしも正しいわけではない。という点がポイントです。
① について「想像のまま」で終わらせてはいけないので、業務知識と照らし合わせて確度を高めていきます。常勤医師やカスタマーサポートにヒアリングしながら、医療業務としてのあるべき形の解像度を上げていく プロセスです。
① 及び ② で高めた解像度は言葉の延長線上なので、関係者間の認識のギャップが発生しやすいです。プロトタイプを作成して、視覚・触感レベルでギャップを埋めていくことで、あるべき形に向けて洗練させていきます。
① 〜 ③ のタイミングを問わず、必要に応じて関係者と相談しながら進めていきます。エンジニアが立てた仮説をデザイナーの目線で評価・UI/UX 最適化をして頂いたり、大きめの機能については、医療機関パイロット運用のご協力を仰いだりすることもあります。

① 及び ② の項に作業のウェイトが偏っているように見えるかと思います。実際、課題を解決する為の半分以上をここに割いています。

理由は「1度作って公開した機能」は、その後1人歩きをして作成者の意図しない方向で利用をされることがあるからです。

そして、利用者がその運用を定着させてしまうと 誤った機能においても「削ぎ落とすことが困難」 です。これは「使われていない機能」よりも直接的な負債といった形でボディブローのように効いてきます。

  • 「どのような使われ方をするか」について想像すること
  • その使われ方が、プロダクトの目指す世界と合っていること

エンジニアは技術を形にする上で、常に想像力を働かせて取り組む必要がある。 というのが筆者の持論です。

さいごに

執筆の締めにあたって CTO ブログを見返してみると、大事なことはここに詰まっていました。筆者は前職の SIer 時代に読んだのですが、この記事にすごく共感したのを覚えています。

toppa.medley.jp

メドレーでは 医療ヘルスケアの未来を作る という大きな目標、そしてその未来を作る為に解決すべき課題に向かって、今回ご紹介したプロセスや考え方も含め試行錯誤しながら、事業部一丸でプロダクト開発を推進しています。

エンジニアの総合力を発揮して医療ヘルスケアの未来を一緒に作り上げていきたい!という方にお会い出来ることを楽しみにしております。

www.medley.jp

フロントエンド開発環境の継続的なリファクタリング

こんにちは、第二開発グループエンジニアの西村です。主にCLINICSの開発を担当しています。

はじめに

CLINICSは電子カルテ、オンライン診療、予約システム、患者アプリなどを含む統合アプリです。CLINICSがローンチしてから現在に至るまで常に新機能開発と定常改善が行われており、開発環境のメンテナンスは後手になりがちでした。今回はそういった状況を改善すべく、開発環境のメンテナンス、リファクタリングを行った過程から得られたプラクティスについて紹介していこうと思います。

モチベーション

プロダクトの新規開発時に行われる技術選定は非常に難しく、業務要件やチーム状況など総合的に考慮してその時点でのベストな選択をする必要があります。

しかし、選択した技術で長期運用をしていくうちに、メンテナンスが行き届かなくなったコードやライブラリが出てしまいます。

CLINICSローンチ当初はオンライン診療のみを提供していました。SPAで構成されていましたが、1つのpackage.jsonで効率的に開発できていました。他に、現在ほどTypeScriptが主流ではなかったのでJavaScriptのコードがメインで実装されてました。

新たなアプリケーション(電子カルテや予約システムなど)を導入するタイミング、すなわちプロダクトが小規模から中規模に変遷するタイミングや、フロントエンドの時流によって、開発環境を改善できた部分もありますが、しきれていない部分も出てきました。

その改善しきれていない部分を残す状態が続くとDeveloper Experience(DX)の低下に繋がってしまいます。ですので、私たちは改善しきれていない部分を取り除いていき、よりモダンとされる開発環境へリファクタリングをしていこうと考えました。

DXを向上していくことで技術的なノイズに時間を取られないようになります。そして提供する機能そのものについて考える時間が増え、結果的にCLINICSをより良いプロダクトへ進化させていくのが当リファクタリングの目的です。

課題整理

改善していくためには、現状整理、課題整理を行わないことには何も始まりません。フロントエンド開発環境をメンテナンスするタスクは、プロダクトの機能(ユーザに提供される機能)に直接プラスの影響があるわけではありません。自ずと通常の機能開発や定常改善に比べ優先度は落ちるため、スキマ時間で改善をしていくことになります。こうしたスキマ時間を有効活用するためには、タスクの難易度の理解、タスクを適当に分割、フェージングの計画を行うことが極めて大事です。

そのように考慮した課題の中で、本記事で記載するのは以下の2つです。

  1. ライブラリを定期的にアップデートする運用が固まってない
    • 運用方式が固まっていないことで、放置されてしまいがちです。率先してアップデートするメンバーがいたとしても、属人化の課題が残ってしまいます
    • 放置されてしまったことにより、最新版との差分が大きくなりアップデートするコストも大きくなってしまいます
    • 結果的に、ライブラリのセキュリティフィックス対応や新しく提供された機能をすぐに適応できない環境になってしまいます
  2. 複数のSPAの依存を1つのpackage.jsonで管理している
    • 電子カルテ・オンライン診療、社内管理Webアプリ、患者Webアプリはそれぞれ別のSPAとして作られています
    • それらを1つのpackage.jsonで管理しているためそれぞれのSPAが同じ依存パッケージを使わなくてはなりません。小規模のときはこのような構成で十分でしたが、規模が大きくなるにつれて柔軟性が失われると共に、ライブラリのアップデートがもたらす影響範囲が広がってしまうため、容易にアップデートできなくなってしまいます

本記事では記載しませんが「Reduxの書き方が混在している」「フロントエンドのテストが少ない」「網羅的にTypeScript化できていなくJavaScriptがまだ残っている」などの課題も挙げられました。

こういう課題は、どのプロダクトにも存在すると思います。それはローンチ当時の技術流行であったり、プロダクトの期待規模、少数メンバに適した設計など要因は様々あり、プログラムのリファクタリングと同様にプロダクトの成長に伴ってリファクタリングしていくことが正だと信じています。

モチベーションにて記載した通り、これら複数の課題は開発環境のノイズであり、除去することによって、より良いDXが得られると考えています。他にこのようなリファクタリングを行うことによって、プロダクトをより堅牢にできるという側面もあります。

上記の2つの課題に対してそれぞれ「ライブラリを定期的にアップデートする運用手段を設けた」「package.jsonをSPA単位に分割した」話をこれからしていきます。

フロントエンド開発環境のリファクタリング

ライブラリの定期的なアップデートをする運用手順を設けた

手動アップデート

ライブラリをアップデートするにはコマンドを叩くだけだと考えていましたが、依存している別のライブラリに影響が本当にないかなど調査する必要があると知り、ライブラリのアップデート方法を模索するところから開始しました。

ライブラリではないですが、Node.jsのアップデートをしようとすると、node-sassやFirebaseが影響していたりして、芋づる式で根っこにあるライブラリのアップデートをする必要が出てきたりするので、一つ一つ問題がないか調査するのが大変でした。

何より、アップデート対象ライブラリのリリースノートにBreaking Changesが書かれていなかったり、semverが守られているかわからなかったりと、プロダクトに影響がないか調べる必要があり、問題の切り分け方が難しかったのです。

ここで得られたライブラリアップデートの安全性担保のプラクティスとしてwebpackによるビルド結果が変わらないケースと、QAテストによって担保するケースがあることがわかりました。前者はwebpackによる成果物が変わらないのであれば今回のアップデートが安全であるといえ、後者はエンジニアとQAエンジニアによってライブラリの影響範囲にハレーションがないことを確かめて安全であるといえるというものです。

renovateの運用開始

数カ月間は上記のようにライブラリのアップデートを手動で行っていましたが、確認工数が増えてしまい、他のタスクの時間を圧迫してしまうほどでした。

そこで、アップデートを自動化する renovate dependabot を視野に入れました。renovateは、dependabotに比べて高機能でかつ、無料であるという理由で選定しました。

運用当初、renovateがPull Requestを作成してくれたり、diffによりライブラリの変更点が見やすかったりと、恩恵を感じていました。しかし、徐々に「アップデート対象が多く、それぞれがどういうライブラリで、影響範囲がどこなのか」ということの調査に時間が取られるようになってしまいました。

ここで得られた調査時間を短縮するプラクティスとして「本番影響のあるもの」「開発向け」「ビルド周り」とrenovateから来るPull Requestを整理することです。このような整理を行うことで、本番影響のあるものに注力してレビューできるようになり、苦にならずにアップデートをできるようになりました。

結果

ライブラリアップデートの運用手順を設けることによって、今まで以上に堅牢な環境になりました。それから、renovateによって自動的に重要な(本番影響のある)ライブラリのみに集中してレビューを行うことによって、少ない工数でアップデートしていけるようになりました。

package.jsonをSPA単位に分割

課題整理で記載した通り、電子カルテ・オンライン診療、社内管理Webアプリ、患者Webアプリはそれぞれ別のSPAとして作られていますが、1つのpackage.jsonで管理しています。ですのでそれぞれのSPAが同じ依存パッケージを使わなければなりません。

弊害としてpackage.jsonに対して1つの変更があったときにすべてのSPAに影響が出てしまいます。ですので、この肥大化したpackage.jsonをそれぞれのSPAに分割しようとしました。

package.jsonをSPA単位に分割することは責務分離という側面もあり、ライブラリだけでなく、共通していた定数、ロジック、コンポーネント、webpack.config.js、babel.config.jsとtsconfig.jsonなどすべてをそれぞれのSPAに依存のない形に閉じるようにしました。これらの分割する作業は非常に泥臭いもので、本記事に記載するほどのものではありませんが、得られた結果について記載していこうと思います。

結果

まず、責務分離ができたので、1つのSPAに対する変更があったときに、他の全てのSPAに対する影響が出なくなりました。よって、1つのSPAに対して新たなWebフレームワークやライブラリを試すことが容易になりました。他にも、1つのwebpackですべてのSPAをシーケンシャルにビルドしていたのに対して、現在はパラレルでビルドできるようになりビルド時間が短縮されたため、今まで以上にコミットからデプロイまでのイテレーションが小さくなりました。

これらの結果からフロント開発環境の改善およびDX向上が果されました。

今後の課題

持続的なリファクタリングをする仕組み作り

「ライブラリの定期的なアップデートをする運用手順を設けた」はまさに持続的にライブラリをアップデートするための手段です。「package.jsonをSPA単位に分割する」もそれぞれのSPAをメンテナンスしやすい環境作りとしては欠かせない作業でした。

しかし、このままリファクタリングを中断すれば、プロダクトの規模が大きくなるときやフロントエンドの時流によって再びメンテナンスしづらい環境になってしまいます。

なので、持続的なリファクタリングをするためには仕組み作りが欠かせないと考えています。そのためには、属人化によらない仕組みづくり、メンテナンスしやすい環境改善、エンジニアそれぞれのフロントエンド開発環境に対するリテラシを高める取り組みを行っていく必要があります。そのため、現在横軸勉強会などでCLINICSフロントエンドの実装背景や、リファクタリングしやすい書き方などのナレッジを共有しています。

まとめ

フロントエンド開発環境のメンテナンス・リファクタリング自体はあくまでもユーザに新しい機能を提供しているわけではなく、粛々と行っていくものです。しかし、課題を洗い出し、向き合って、解決していったことによって得られたプラクティスは多くあり、フロントエンドのエコシステムに対する理解も多く得られました。

これらのリファクタリングを行うことによってDXが向上していき、技術的なノイズに悩む時間が減り、エンジニアはよりプロダクトの機能開発に専念できるようになっていると信じています。

今回私たちが課題を解決したことによって、持続的にリファクタリングをしやすい土台作りをしたという側面もあると思います。今後の課題として、この土台を基にそれぞれのエンジニアが意識を持ってメンテナンスできるような仕組みづくりも行っていきたいと思います。

 

最後まで読んでいただきありがとうございました。

 

www.medley.jp

iOSDC Japan 2020にメドレーが協賛しました

皆様こんにちは。インキュベーション本部エンジニアの濱中です。
9/19〜21にiOSDC Japan 2020(以下iOSDC)が開催されました。先日の記事の通り、メドレーは2017年よりiOSDCに協賛しております。
メドレーでは、Swiftを利用してオンライン診療/服薬指導アプリ「CLINICS」iOS版の開発をしています。

 

CLINICS (クリニクス)

CLINICS (クリニクス)

  • Medley, Inc.
  • メディカル
  • 無料

apps.apple.com


5回目となる今回は、初のオンライン開催となり、主にニコニコ生放送、Discord上で発表・コミュニケーションが行われました。私がiOS版CLINICSの開発に携わっている縁で、今回スポンサー枠としてiOSDCに参加させていただきましたので紹介させていただきます。

 

イベント全体について

オンライン開催となったため、会場の様子や企業ブースなど、雰囲気の伝わる写真をお届けできないのが残念ですが、発表の主会場となったニコニコ生放送では、終始穏やかな雰囲気でありつつも活発にコメントがなされ、大いに盛り上がっていました。

前回同様、初日はday 0として夕方から、2日目以降は朝〜夕方まで、最大5つのチャンネルで並行して発表が行われました。セッションについては事前に録画したものを放送し、LTのみリモートにてリアルタイム発表という形式となっていました。

質疑応答については、各発表の終了直後にDiscordチャンネルに発表者が待機して対応していました。初のオンライン開催ということで、イントロダクション動画をはじめとし、各所で積極的なフィードバック・コミュニケーションが奨励されていたように思います(なお、イントロダクション・スポンサー紹介の各動画はナレーションが声優の緒方恵美さん・三石琴乃さんと、とても豪華でした。生放送中のコメントや、18年の弊社ブログを見る限りは毎年恒例のようですね。すごいです!)。

 

 

セッションについて

昨年iOS13とともに発表されたSwiftUIへの移行や、コード移行・モジュール分割等、プロジェクトの最適化についてのトピックが多かったように思います。

SwiftUIは、従来Storyboardで設計していたUIをコードベースで記述できる画期的なフレームワークですが、SwiftUIを使ったアプリはiOS13未満の端末では利用できなくなってしまうこともあり、アプリの公開対象を広めにもっておきたい場合はなかなか乗り換えづらい印象でした。2020年6月現在でiOS13のシェアが9割以上となったことで、ちょうどiOSDCでの発表トピックを決めるころに導入作業を行った(かつ苦労した)というケースが多かったのかな、と思います。

以下、視聴したセッションのうち気になったものをいくつかご紹介いたします。

 

オープンソースのAltSwiftUIの発表

fortee.jp

楽天のエンジニアの方による、SwiftUIの提供するネイティブコンポーネントに対応しつつ、iOS11以上で利用可能なオープンソースフレームワークAltSwiftUI公式Doc)の開発についてのセッションでした。

iOS12以下の対応を切らずにSwiftUIへの乗り換えを進められる(かつ本家と違ってオープンソースである)便利さもそうですが、別途フレームワークが出来上がってしまうあたりに、SwiftUIへの移行対応への苦労がしのばれる内容でもありました(ストアにある楽天提供のiOSアプリの数を考えると乗り換えコストが大変そう…)。

 

「それ、自動化できますよ」: note を支えるワークフロー大全 speakerdeck.com

改修要望が上がってから、実際に改修を行ってアプリをリリースするまでの作業をできる限り自動化した、というセッションです。CLINICSでも、「証明書の有効期限確認、プッシュからのテスト、マージからのリリース準備」はBitriseのトリガを利用して自動化しています。

上記のような、GitHub上でのアクション(プッシュ、マージなど)をトリガとする自動化はよく聞く話ではあるのですが、Slackのポストに特定のスタンプつけるとIssue化、はちょっと目新しくて面白いなと思いました(気をつけないと表記揺れで同じようなIssueが乱立しそうですが)。

Issueもきちんと管理しておかないとトラブルの起きやすい部分ですよね。起票者と実装者の間でボールが浮いてしまったり、プロジェクトに紐づいていなかったために対応から洩れてしまったり…。

また、このスライドですが終始手書きの挿絵がかわいくて、そういった意味でもコメント欄が盛り上がっていたのが印象的でした。

 

100人でアプリをリファクタリングして見えてきた、最強のiOSアプリ設計に求められることfortee.jp

アプリを長期に運用していくとほぼ必須となる課題でありながら、人ごとに基準が曖昧だったり、機能開発におされて対応が後手後手になったり…と、何かとつらい話をよく聞くソースコードリファクタリングに関するセッションでした。

同じ状態のソースコードを多数のエンジニアがリファクタした結果を比較することで、「良いリファクタリングのための考え方」とは何か?を模索した内容です。

ビューとロジックの分割をしっかり行う、というのはPRレビューでエンジニアが口を酸っぱくしてよく言われることではありますが、「ロジックの中でも、アプリの仕様に依存するものとそうでない普遍的なものは分離すべき」というアイデアは個人的には眼から鱗が落ちるものでした。

また、これを説明するリバーシの具体例(「対戦相手が人間かAIか」はアプリ仕様に依存するロジック、「そこに石を置けるか」は普遍的なロジック=リバーシのルールそのもの)も非常にわかりやすかったです。

 そのほか、React / Reduxでフロントエンド開発を行っている人にはお馴染みのAction / Reducerを使った単一方向のデータフローの導入なども紹介されています。

 

新規機能開発からモジュール分割を始めてみる

speakerdeck.com

 一つのアプリが長期間運用されていくなかで、複数の機能が統合されたスーパーアプリになることがあります。そうなった場合、ソースコードが肥大化→ビルド・テストも長大化、となってメンテナンス性が低下するため、対策としてコードを分割してテストやビルドの単位を小さくする必要があります。

いきなりアプリ全体をモジュールに分割するのは時間がかかるため、本セッションではまず第一段階として新規に開発する機能を別モジュールとして実装し、その時得た知見について触れられていました。

「分割したモジュール側でのサードパーティフレームワークのリンク方法(※リンクを正しく行わないと、ビルドして動作はするのにアーカイブに失敗してリリースできなくなる)」などは、今後の開発にモジュール分割を取り入れていく際に参考になりそうです。

 

Swiftで始める静的解析

speakerdeck.com

 Swiftソースコードからの構文木の生成、解析を行うライブラリSwiftSyntaxの紹介と、それを用いたソースコード重複検出機能の実装についてのセッションでした。

普段Xcodeを始めとしたIDEで開発していると、コード重複、不要なローカル変数、型やNullableの不一致に変数リファクタリング…等々の便利な機能を気軽に使えてしまいますが、その裏の動作を改めて一つずつ具体的に追っていくと、そのありがたみが身に染みます…。

静的解析そのものはSwiftに限らず様々な言語のソースコードに対して適用できるトピックではあるのですが、普段何気なく使ってしまうIDEの機能について考えるよい機会になったため、紹介させていただきました。

 

まとめ

ちょうど業務でもiOSアプリ開発を担当していることもあり、興味深い知見が得られ、よい経験となりました。また、事前録画形式になったことで発表の構成がよく練られ、結果として聞きやすく(皆様かなり気をつけてゆっくり発声されていました)、個性のある発表が多かったように思います。

今回、初のオンラインでの開催ということで、運営委員会の皆様もいろいろと苦労されていらっしゃるようでした。ただ、その甲斐あってか当日の進行はスムーズで、会場はとても盛り上がっていました。関係者の皆様、本当にお疲れ様でした。

情勢を踏まえ、来年度の開催可否・形式は未定とのことでしたが、オンライン・対面のそれぞれの良さを取り入れつつ、より多くの人が参加できる形態になっているとよいなと思います。

公式YouTubeチャンネルで過去の発表を視聴できますので、ご興味のある方はぜひどうぞ(今年の発表分も一ヶ月ほどしたら公開されるとのことでした)。

またメドレーではiOS / Androidネイティブアプリ開発エンジニアを募集しています。興味がある方、ぜひお気軽にお話しましょう!

 

www.medley.jp

2020年度新卒エンジニア研修について

こんにちは。ジョブメドレーの開発チームでエンジニアをしている新居です。

はじめに

2020年4月に、新卒エンジニア3名が入社しました。 入社後は新卒エンジニア研修を実施し、先日8月25日の最終報告会をもって終了しました。

コロナウイルスの影響で入社間もなくフルリモート勤務となり、不慣れなところもありましたが、本年度の研修の取り組みを紹介します。

f:id:medley_inc:20200924130505p:plain

2020年度新卒エンジニア

研修の概要

メドレーでは昨年度から新卒エンジニアを迎えており、合わせて研修も開始しました。

初めての研修をどのような視点で計画・実施したかについては、昨年平木がこちらにまとめています。

2019年度エンジニア新卒の研修について - Medley Developer Blog

今年は人事部のご協力もいただきながら、昨年の内容を少しアップデートして行いました。

研修の目的は、新卒メンバーが同じ空間で互いに刺激し合いながら、社会人への思考転換をはかり、業務遂行に必要となる基礎知識とスキルを習得することです。

研修は以下の4つのフェーズに区切って行いました。

f:id:medley_inc:20200924130533p:plain

研修のフェーズ

研修の内容

ここから4つのフェーズ毎に内容を紹介します。

フェーズ1:社会人&メドレー基礎研修

1. オリエンテーション

  • メドレーの事業や組織、大切にしている行動規範などの概要説明
  • セキュリティ研修とコンプライアンス研修

2. ビジネス研修

  • ビジネスマナー研修
  • ビジネススキル研修
  • ビジネススタンス研修(外部研修)

フェーズ1では「医療ヘルスケアの未来をつくる」メンバーの一員として大切にして欲しいことを学ぶフェーズでした。

社会人としての最低限のマナーやスタンスは勿論ですが、メドレーで働く上で土台となるマインドをここで学び、医療ヘルスケア分野の課題を解決する一員として共にプロダクトを作るためのベースを築けたと思います。

フェーズ2:エンジニア基礎研修

1. 開発基礎1

2. 開発実践

  • チーム開発体験

3. 開発基礎2

フェーズ2から開発の研修がスタートしました。

開発基礎1

開発の研修に入る前に、エンジニアの執行役員 田中から「メドレーが求めるエンジニアとは」というテーマで講義を行いました。メドレーがどういうエンジニアを求めているのか、目指すところの視点合わせを行い、これから行う研修に対する意識や取り組みの質を上げることを目指しました。

メドレーが求めるエンジニア像についてはCTO平山の記事にも詳しく書いています。

メドレー平山の中央突破: THE エンジニア

その後ジョブメドレーとCLINICSの事業・プロダクトについての概要説明、Railsの基礎トレーニングを行いました。メドレーのプロダクトはRails製です。Railsウェブアプリケーション開発に慣れていない新卒メンバーは、Railsの基礎トレーニングでRuby on Railsチュートリアルを使って基礎からみっちり学びます。

f:id:medley_inc:20200924130918p:plain

Ruby on Railsチュートリアルの進め方

ここで大切なことは、漠然とひたすら写経してチュートリアルを進めるのではなく、毎日のフィードバック会でしっかりその日の進捗や学びを共有し、不明点はメンターに質問してもらうようにすることです。

メンターは、新卒メンバーが理解が浅いまま進めてたり、理解していて欲しいところがいい加減になってたり、進め方や学びの方向性がズレてる場合などはアドバイスを入れて軌道修正することを心掛けました。

また「実際の開発ではこうだよ」といった実務を踏まえたアドバイスや、意識していることも伝えていきました。

20新卒Sさんの感想

「毎日のフィードバック会の中で、その日学んだ技術がジョブメドレーではどのように利用されているのか、どういったことに留意して利用しているのかなどを確認できたので、現場の人の感覚を少しずつ知ることができた。」

新卒メンバーは毎日リズム良く進捗を出し、メンターは新卒メンバーのフォローと引き上げを意識し、成果を最大化できるよう努めました。

開発実践

続いて開発実践ではチーム開発を行いました。前回までは各自個別に進めていましたが、ここではジョブメドレーに関する課題解決を目的としたプロジェクトに対して、チームで向き合う研修でした。

f:id:medley_inc:20200924131002p:plain

開発実践の目的と達成すべきこと

実務ではチーム開発が基本となり、チームメンバーとの協働は必須です。学生時代に業務レベルのチーム開発を経験しているのは稀ですし、実務に入る前にチームでプロジェクト推進するとはどういうことかを知るのは、とても価値があると思います。

加えて、チームで課題をどう解決していくのかも、新卒メンバー同士で話し合って決める必要があるので、課題解決力も養われたと思います。

今回はプロトタイプを作って成果発表するところまででしたが、プロジェクト推進においてはスケジューリング、要件定義、各種設計、開発フローやコミュニケーションフローの整備、実装、テスト、などなど、やることは尽きません。

また、このプロセスの中で密なコミュニケーションが必要不可欠となるので、新卒メンバー間のチームワークも向上し、お互いのことを更に知ることができたと思います。

この段階で、チームでプロジェクトを推進することの全体感を知り、プロジェクト推進の苦悩苦闘を実体験できたのは大きな経験値になったと思います。

20新卒Oさんの感想

「各機能の影響を互いに受けないためにブランチを細分化するブランチ戦略やGitHubを用いたコード管理について理解できた。一方で、UIを考える際にチームの各メンバーの認識のズレが生じたことや、序盤は各メンバーの進捗の詳細を把握できていなかったことから報・連・相の重要性を再認識した。」

20新卒Tさんの感想

「初めてのチーム開発であったことから、実装の序盤は、どのファイルなら編集しても他のメンバーの作業に影響がないのか、動作確認のための画面を作るファイルは自由に作成して良いのか、どのテーブルから関係する他のテーブルの情報を含めた情報を取得をするかなどに悩んでいた。今になって振り返るとチーム内で話せば解決することに対して、技術的にも心理的にも難しさを感じた。」

開発基礎2

フェーズ2最後の開発基礎2では、書籍『Webを支える技術 -HTTP、URI、HTML、そしてREST』の輪読会を行いました。もっと前のフェーズでの実施も検討しましたが、開発基礎1と開発実践を経た後の方が書籍の内容の納得感が高くなるだろうという判断で、この段階での実施となりました。

その後、中間報告会に向けたドキュメンテーション研修とプレゼンテーション研修を行いました。仕事を進めていく上では、背景や目的を正しくステークホルダーへ共有しながら進めていくことが必要で、伝えたいことを適切に文章として整理し、他者へ分かりやすく伝えていくことが求められます。中間報告会では、そういったことを意識しながらこれまでの研修でやってきたことや成果、学びをレポートにまとめ、プロダクト開発室の室長と副室長、メンター陣の前でプレゼンテーションして報告しました。

フェーズ3:事業部OJT

1.代表取締役医師 豊田の講義

  • 日本における医療制度の課題とそれに対するメドレーの位置付けについての講義

2.ジョブメドレー開発OJT

  • ジョブメドレーの実際の開発Issueに対応し、ジョブメドレーの開発プロセスを体験

フェーズ3の最初は豊田代表の講義を受けました。基礎的な研修を終え、ジョブメドレー開発OJTに入る前にメドレー社の社会的意義などを改めて代表から伝えていただきました。

続いて、ジョブメドレー開発OJTは以下の狙いを持って進めました。

f:id:medley_inc:20200924131055p:plain

ジョブメドレー開発OJTの狙い

実際に行ったことは、手始めに小さい不具合系Issueの対応に取り組んだ後、サーバーレスポンス改善のIssueに取り組むというものでした。

サーバーレスポンスの改善は、1人1画面を担当し、「プロファイルツールで分析 → 改善できそうな箇所を調査 → 改善方針の検討 → 提案 → 実装 → レビュー → リリース」というサイクルを回しました。

1つ目のIssue対応でも心掛けたことですが、言われたものを実装するのではなく、ある課題を解決するためにどうしたら良いかを自分で主体的に考えることを重視しました。実装力と同じくらい課題解決力も大切にしているためです。

とはいえ成果が何も出せないというのは、精神衛生上良くないので、日々の朝会と夕会にて進捗や状況をしっかり確認しながら適宜フォローやインプットを行い、ヒントになりそうな過去Issueのリンクを渡して参考にしてもらったり、メンターの適切なバックアップも必要です。

今回のOJTを通じて実務を知ることで、実際にエンジニアとして仕事をするイメージが沸き、同時に仕事をする上で足りないことも明確になります。自分の課題と向き合うことで、直近の自身の学習プランの軌道修正もできます。

課題は簡単なものではありませんでしたが、最終的に1人1つ以上のサーバーレスポンス改善PRをリリースすることができました。

Sさんの感想

「速度パフォーマンスの悪いコードに対する嗅覚、オブジェクトを生成しすぎていないか、無駄に通信を走らせていないかなどを学べた。」

Oさんの感想

「Issueを本質的に解決するメドレーの開発姿勢について学んだ。Issueを表面的に解決するのではなく、背景や目的、関連するコードなどの不明点を調査し、十分に理解・納得した上で修正することの意識付けができた。また、Issueに関連する一部分のコードを修正すれば良いという狭い視野を持たず、修正による影響範囲を考慮した上で全体の最適化を考えることが重要であると学んだ。」

フェーズ4:最終報告

1. 最終報告会

  • 最終報告会の準備と実施

最後のフェーズ4では、これまでの研修でやってきたことや成果、学びをレポートにまとめ、役員陣の前でプレゼンテーションして報告しました。

役員陣の前なので緊張は最高潮になりますが、自分達が研修を通じて何を得てどう成長したか、今後どういうエンジニアを目指していくのか、などを役員陣の前でアピールする貴重な機会となりました。

1人10分の枠内で役員陣にどういう情報をどういう表現でプレゼンテーションするかを考える機会にもなったので、情報整理力や表現力が培われる場にもなりました。

さいごに

2020年度の新卒エンジニア研修も無事終了することができました。改めて、新卒メンバーのみなさん、関係者のみなさん本当にお疲れ様でした。

振り返ると、メドレー社員としてのマインドや開発の基本的なことをしっかりインプットしつつ、新卒メンバーが主体的に課題解決に取り組む研修ができたように思います。

必要な技術スタックを1から10まで懇切丁寧に資料に落とし込み、講義形式で行う研修も身になることは多いですが、メドレーの研修のような課題解決を実体験する研修はより実務に繋がる実践的な研修だと思います。

少しハードな面もあるかもしれませんが、このような研修を乗り越え、医療ヘルスケア分野の課題解決に取り組みたい学生エンジニアのみなさん、少しでも興味を持っていただけると幸いです。

もちろん中途エンジニアの方もぜひお気軽にお話をしましょう。

www.medley.jp

Fargate上で動くコンテナアプリケーションにSessionManagerで接続する

自己紹介

株式会社メドレーのエンジニア阪本です。

9月に入っても暑い日が続く中、皆さんはいかがお過ごしでしょうか。

前回のブログでも書きましたが私は野球観戦(虎党)が趣味で、毎日の試合結果に一喜一憂しています。 このブログの執筆時点ではセ・リーグは首位巨人にマジックが点灯し、残試合50を切った状況でのゲーム差10。優勝を目指す阪神にとっては厳しい状況となりましたが、残り直接対決をすべて勝てば可能性は見えてくるはず。ここは諦めずに応援しようと思います。

次の記事を書く頃には何らかの決着が着いていると思いますので、その時には喜びのメッセージが書ける事を願っています。

はじめに

突然ですが、皆さんはFargateを使いこなしていますか? 今までECS(EC2)での運用がメインでしたが、ジョブメドレーのシステムでもFargateに触れる機会が増えてきました。 筆者自身は初めてのFargateでしたが、EC2の存在が無くなることに不思議な感覚を覚えつつも、管理するものが減って運用が楽になったと実感しています。

しかし、EC2が無くなった事によりサーバ内にターミナルで入る手段を失いました。 公式のガイドでは

質問2:コンテナの中に ssh や docker exec で入ることは出来ますか?

こちら現状サポートしておりませんが、コンテナワークロードでは「同一の環境でしっかりテストを行う」ことや「ログを外部に全て出す」ことがベストプラクティスとされていて、コンテナに入る必要性を出来る限り減らす方が将来的にも好ましいです。

と「事前にテストを十分に実施する」「ログは(S3やCloudWatchLogsなど)外部に出力する」 さえ出来ていれば入る必要が無いはずと記載されているものの・・・心配性な自分は不測の事態が発生した時の事を考えてサーバに入る手段を求めてしまいます。

そこで代替手段を模索していた所、SessionManagerを使えば可能との文献を見つけました。 すでにSessionManager自体はEC2に対して運用を行っていたため導入の敷居は低いと考え、この手段を採用することにしました。

Session Managerとは?

Session ManagerとはAWSのSystems Managerサービスの1機能で、AWS上で管理しているサーバ(マネージドインスタンス)に対してターミナルのアクセスを可能にするものです。

ターミナルへのアクセス手段は、よくある手段だとSSHがありますが この方法はSSHポートを外部に開放する必要があるため攻撃の対象になりやすく、あまり好ましくありません。

それに比べてSession ManagerはSSHポートの開放は不要でサーバから見てアウトバウンド方向のHTTPS通信の確保で済む為、外部からの攻撃も受けず安全にアクセス経路の確保が実現できます。 ※通信経路の確保以外にもIAMロールの設定などが必要となります。詳しくはこちらを参考

AWS上で管理しているサーバ」と先に記載しましたが、このサーバはEC2インスタンスに限らないのが本記事の重要なポイントになります。 オンプレミスなサーバもAWS上で管理されているのであれば、SessionManagerエージェントをインストールする事により管理対象に含めることが可能になるのです。

今回はEC2で動いていたSessionManagerエージェントをFargateで動くコンテナにインストールする事によりコンテナ自体をサーバと見立ててマネージドインスタンスとし、SessionManagerでアクセスする事を目指します。

f:id:medley_inc:20200918142724p:plain

対応

Systems Managerインスタンス枠をスタンダードからアドバンスドに変更する / AWSコンソールでの設定

オンプレミスなサーバにSessionManagerにてアクセスする場合、Systems Managerのオンプレミスインスタンスティアをスタンダードからアドバンスドへと変更する必要があります。

f:id:medley_inc:20200918142745p:plain

この変更作業はAWSコンソールから行う事になりますが、アドバンスドへの変更に当たって既存のマネージドインスタンスに影響することはありません。 ただし、この逆の場合、スタンダードに戻す際には考慮が必要となるのでこちらを参照ください。

SSM Agentのインストール / コンテナに対する設定

ここからは実際に動くコンテナに対する設定になります。 AWSのドキュメント手動でインストール SSM エージェント EC2で Linuxのインスタンスを参考に、OSに合った方法でSessionManagerエージェントのインストールを行います。

インストール作業には通信などの時間が必要となるので、事前にコンテナイメージにインストールする形としました。

コンテナをマネージドインスタンスとして登録する / コンテナに対する設定

コンテナをマネージドインスタンスとして登録するため、コンテナのスタートアップ(Entrypoint)にて下記スクリプトを実行します。

# 1. ハイブリッドアクティベーションの作成
SSM_ACTIVATE_INFO=`aws ssm create-activation --iam-role service-role/AmazonEC2RunCommandRoleForManagedInstances --registration-limit 1 --region ap-northeast-1 --default-instance-name medley-blog-fargate-container`

# 2. アウトプットからアクティベーションコード/IDの抽出
SSM_ACTIVATE_CODE=`echo $SSM_ACTIVATE_INFO | jq -r '.ActivationCode'`
SSM_ACTIVATE_ID=`echo $SSM_ACTIVATE_INFO | jq -r '.ActivationId'`

# 3. コンテナ自身をマネージドインスタンスへの登録
amazon-ssm-agent -register -code $SSM_ACTIVATE_CODE -id $SSM_ACTIVATE_ID -region "ap-northeast-1"

# 4. SessionManagerエージェントの起動
amazon-ssm-agent &

これらのコマンドについては各行ごとに説明します

1.ハイブリッドアクティベーションの作成

マネージドインスタンス登録に必要なアクティベーションコード/ID取得のため、ハイブリッドアクティベーションの登録を行います。 後々AWSコンソールにてインスタンスの識別ができるように、--default-instance-nameオプションにてmedley-blog-fargate-containerという名前を付与しています。

このコマンドのアウトプットにて下記のようなJSONが返される為、一旦変数に格納しています。

{ "ActivationId": "<<アクティベーションID>>", "ActivationCode": "<<アクティベーションコード>>" }

また--iam-roleオプションでサービスロールAmazonEC2RunCommandRoleForManagedInstancesを使っています。 このロールがまだ存在しない場合、AWSコンソールからハイブリッドアクティベーションからIAMロール→「必要な権限を備えたシステムのデフォルトコマンド実行ロールを作成」により作成してください。

f:id:medley_inc:20200918142823p:plain

2. アウトプットからアクティベーションコード/IDの抽出

前項のアウトプットからアクティベーションコード/IDを個々の変数に分離しています。

3. コンテナ自身をマネージドインスタンスへの登録

取得したアクティベーションコード/IDを利用し、コンテナ自身をマネージドインスタンスとして登録します。 環境変数AWS_DEFAULT_REGIONのようにAWSのCredentialにてデフォルトのRegion設定があった場合でも、このコマンドではオプションでRegion指定が必須となるのでご注意ください。

4. SessionManagerエージェントの起動

最後にSessionManagerエージェントを起動します。 これによりAWSとの通信が確立され、SessionManagerが利用できるようになります。

この状態でマネージドインスタンス画面にて目的のインスタンスが「オンライン」であれば設定が完了です。

f:id:medley_inc:20200918142901p:plain

接続確認

設定が完了したので、実際にSessionManagerにて接続してみます。 AWSコンソールのセッションマネージャからセッションの開始を選択し、名前が事前に登録したmedley-blog-fargate-containerであるものを選択します。 外見は他のEC2と変わらない表示ですが、この手段で登録したものはインスタンスIDがmiから始まるIDになります(通常のEC2はiから始まるID)。

f:id:medley_inc:20200918142910p:plain

後は普段通りにセッションを開始するとコンテナ内へのアクセスが開始されます。 これでEC2の無いFargate上のコンテナに対してもターミナルに入ることができました。

運用してみての感想

Fargate上のコンテナに直接入ることにより、今まで出来なかった topコマンドによるプロセス状態の確認 dfコマンドによるDisk容量の確認 などの環境調査が出来るようになりました。 利用頻度が多い訳ではありませんが、調査の選択肢を増やす事により有事の際の早期対応に繋げれられていると感じています。

注意点

ここからは運用に当たっての注意点について数点紹介します。

料金

EC2でのSessionManagerと違い、この方法で登録したサーバへのSessionManager通信は料金が発生します。 正確には 「SessionManagerエージェントが起動しAWSと通信が確立している状態」 での時間課金でSessionManagerでの接続有無は問いません。 よって、常時必要ではない場合はSessionManagerエージェントを止めて節約する方法を検討してください。

アクティベーションやマネージドインスタンスがリストに残る

コンテナ終了時でもAWSコンソールのハイブリッドアクティベーション一覧やマネージドインスタンス一覧に表示が残ってしまうようです。 一覧の上限の記載は見つからなかったものの、無限に増えるとも思えないので適時Lambdaを使って削除しています。

SessionManagerでの操作について

EC2インスタンスに対してのSessionManagerと同様ですが、セッション開始直後のユーザはssm-user固定になるようです。 特定ユーザでの操作が必要となる場合、suコマンドでのユーザ切り替えが必要になります。

さいごに

今回のようにメドレーでは新たな技術を取り入れつつ、サービスの安定を目的とした様々な施策を導入しています。 こういった働き方に興味を持たれた方、まずは下記リンクからお気軽にお話しませんか?

www.medley.jp

iOSDC 2020にシルバースポンサーとして協賛します

f:id:medley_inc:20200914173618p:plain

みなさん、こんにちは。エンジニア・デザイナー採用担当の平木です。

メドレーではiOS開発コミュニティに微力ながら還元したいと、2017年よりiOSDCに協賛をさせていただいておりますが、今年もシルバースポンサーとして協賛させていただくことになりました。

過去の参加レポート

developer.medley.jp

developer.medley.jp

iOSDC初のオンライン開催

今年のiOSDCは初のオンライン開催ということで、例年とはまた違った楽しみ方ができそうです。

公式スタッフブログに記載されていますが、今年はノベルティグッズが配送されるとのことで、既に届いている方もいらっしゃるようです。弊社のパンフレットも同封させていただいてます。

今年のタイムテーブルも大変興味深い内容が多く、今から視聴が楽しみですが(スポンサーチケットを頂いてはいますが、筆者も自腹でチケット購入しています)ニコニコ生放送での視聴ということで、例年とは違い、コメントなどで盛り上がりがあるのではないかと、大変期待しています。

Ask the SpeakerではDiscordを使用するということで、対面とはまた違ったコミュニケーションが取れそうです。参考URLや図などがすぐに出してもらえたりなど、さらに学びが深くなるのではないかと思っています。

最後に

今回は直接会場でみなさんとの交流はできませんが、弊社のエンジニアも参加予定ですので、一緒に楽しんでいきたいと思います。後日イベントレポートもこちらで公開したいと考えています。

また、メドレーではこうしたイベントにも興味をお持ちのiOSエンジニアを絶賛募集中です。お気軽に下記よりご連絡いただければ、カジュアルにお話をしたいです!

www.medley.jp

OpenAPI や Protocol Buffers のおかげで開発がかなり捗っている話

こんにちは、インキュベーション本部エンジニアの加藤です。 主に CLINICS アプリの開発を担当しています。

はじめに

CLINICS アプリの開発では OpenAPIgRPC を利用しています。 OpenAPI と gRPC の間には何の関係もないのですが、どちらも API の仕様をスキーマ言語で記述するという点では共通しています。 今回はこの API スキーマが開発にもたらすメリットについて紹介していこうと思います。

API ドキュメントとしてのスキーマ定義

既存のコードに機能を追加する際や修正を加える際に気にすることの多い部分は API の仕様ではないかと思います。 「リクエストやレスポンスはどのようなデータなのか」「この値は必須なのか、任意なのか」「データの型は数値なのか、文字列なのか」「フォーマットは決まっているのか」など、多くのことを把握する必要があります。

しかし、こういった API 仕様のドキュメントが整備されていないということも多いのではないでしょうか。 また、ドキュメントはあるけれどリクエストとレスポンスのサンプル JSON が貼ってあるだけだったり、時間が経つうちに実装とドキュメントが乖離してしまいアテにならなくなってしまっている場合もあります。 参考にできるドキュメントがない場合は、直接バックエンドの実装を見に行くこともあるのですが、目的のコードを探し出して読み解くのは意外と時間がかかります。 特に自分以外のエンジニアが実装した機能の場合、API の仕様を実装から紐解くのはかなり骨が折れる作業です。

CLINICS アプリの開発ではこういった手間を減らすために OpenAPI や gRPC を利用しています。 REST APIスキーマは OpenAPI を使って記述しています。 gRPC を利用している部分は Protocol Buffers で RPC のインターフェースが記述されるため、これが APIスキーマになっています。 OpenAPI や Protocol Buffers の定義を参照することで API の仕様が容易に把握できるため、非常に便利です。

OpenAPI や Protocol Buffers などのスキーマ言語の良い点は、宣言的な DSLスキーマを定義できる点です。 実装言語に依存しない形での記述ができ、自然言語のような曖昧さもないためより正確に API 仕様を記述することができます。

ここからは OpenAPI や Protocol Buffers の実際に記述例を挙げながら、どういった形でスキーマを記述していくのか簡単に見ていきたいと思います。

OpenAPI

OpenAPI は REST API のインターフェースを記述する仕様です。 エンドポイントのリクエストパラメータやレスポンスの構造などを JSONYAML で記述していくことができます。 かつては Swagger という名称だったため、そちらの名前で知っているという方もいらっしゃるかもしれません。

実際の OpenAPI の定義は以下のような形になります。

openapi: 3.0.2
info: { title: OpenAPI Sample, version: 1.0.0 }
paths:
  '/users/{user_id}':
    get:
      parameters:
        - name: user_id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:   { type: string }
                  name: { type: string }
                  age:  { type: integer, nullable: true }
                required: [id, name, age]
        '404':
          description: Not Found
        '500':
          description: Internal Server Error

例としてユーザー ID からユーザーのデータを取得する API を記述してみました。 上記の定義を見ると、

  • GET: /users/{user_id} というエンドポイントがある
  • ユーザーの ID (user_id) を string でパラメータとしてパスの中に埋め込む
  • レスポンスは 200, 404, 500 が返ってくる可能性がある

といったことが読み取れるかと思います。 また、レスポンスは以下のような JSON が返ってくることもスキーマから読み取ることができます。

{
  "id": "12345678-1234-1234-1234-123456789abc",
  "name": "user name",
  "age": 25
}

ここでは OpenAPI の記述の仕方についてあまり深く触れませんが、この他にもデータのフォーマットや省略された場合のデフォルト値などの記述なども可能です。 より詳しくはこちらを参考にしてみてください。 これらをうまく使うことでより正確に API の仕様を記述することができます。

Protocol Buffers

Protocol Buffers は主に gRPC で用いられるデータのシリアライゼーション形式です。 専用のスキーマ言語を用いてデータの構造や RPC のメソッドの定義を .proto ファイルに記述していきます。

実際の .proto ファイルは以下のような形になります。

syntax = "proto3";
package example.protobuf;

service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
}

message GetUserRequest {
  string id = 1;
}

message GetUserResponse {
  User user = 1;
}

message User {
  string id = 1;
  string name = 2;
  int32 age = 3;
}

少し独特な見た目をしていますが、message として構造体のようなデータ構造が定義されていることが見て取れると思います。 各メッセージにはフィールドが定義されており、型とフィールド名が宣言されています。

スキーマ言語を使うメリット

スキーマはドキュメントの代わりとして使えるだけでなく、他にもいくつか使い道があるので紹介していこうと思います。

スキーマからソースコードを自動生成できる

スキーマ言語による記述は人間にとって読みやすいだけでなく機械的に処理できる形式でもあるので、スキーマからソースコードを自動生成することも可能です。 プログラミング言語や使っているフレームワークによらず、サーバー側ではリクエストのバリデーションを、またクライアント側ではレスポンスの JSON をクラスや構造体に詰めるような処理を書くことが多いのではないでしょうか。 事前にスキーマ定義を書いている場合はスキーマを見ながらこういったコードを書き起こしていくことになるのですが、せっかく machine-readable な形のスキーマがあるのだから自動でコードを生成したくなるのが自然な考えでしょう。 自動で生成してしまえば定型のコードを書く手間を減らせるだけでなく、手書きするとどうしても起こしがちな JSON のキー名を間違えるといったミスを防ぐこともできます。 また、Web, iOS, Android などの複数プラットフォームでサービスを展開している場合でも、それぞれの実装が乖離しないように管理していくことも容易です。

gRPC の場合は Protocol Buffers からソースコードを生成するのがほぼ前提となっています。 protoc コマンドを利用すると .proto ファイルから各言語のサーバー・クライアントコードを生成することができます。

OpenAPI の場合、openapi-generatorswagger-codegen などのツールを利用することで各種言語のコードを自動生成が可能です。 openapi-generator や swagger-codegen には多くの言語とフレームワークのサーバースタブと API クライアントのジェネレータが用意されています。

既存のジェネレータを使うだけでも十分に強力なのですが、さらに自前でコードジェネレータを書けばプロジェクト固有のルールでコードを生成するといったことも可能です。 OpenAPI のドキュメント自体はただの YAML/JSON なので、パースしてスキーマ定義を再帰的に読んでいけばコード生成に必要な情報を集めることができます。 Protocol Buffers からコードを生成する場合は protoc のプラグインを書くのが簡単でオススメです。

モックサーバーを使ってクライアント開発を進められる

コードの自動生成の他にもスキーマからモックサーバを立ち上げるといった活用方法もあります。 Prism のようなスキーマ定義から固定のデータを返すモックサーバを立ち上げるツールを利用すれば、クライアント側の開発もしやすくなります。 特にフロントエンドとバックエンドで担当が分かれているような場合は、開発初期はモックサーバーを使って開発を始め、バックエンドの実装ができてきた頃に結合するという流れを踏むことで、フロントエンドもより早いタイミングから開発に着手することができるようになります。

実際に Prism を使ってモックサーバーを立ち上げるとこんな感じになります。

f:id:medley_inc:20200821181330p:plain

f:id:medley_inc:20200821181342p:plain

スキーマファースト開発

このような開発スタイルはスキーマファースト開発・スキーマ駆動開発などと呼ばれています。 明確な定義や出典があるわけではないのですが、スキーマファーストな開発は以下のような開発スタイル全般を指しています。

  • スキーマは実装言語によらない machine-readable な形で記述する
  • ドキュメントをスキーマから自動生成する
  • クライアント/サーバーのコードをスキーマから自動生成する

実際にスキーマファーストな開発を実践するためにはスキーマをメンテナンスするモチベーションを高く保つ必要があります。 コードも書いた上でスキーマも書かないいけないとなるとおそらくスキーマが更新されなくなっていくので、可能な限りスキーマからコードを生成する努力が必要になります。 一方、うまく実践すればスキーマという形で 100% 信頼できる API ドキュメントが手に入り、クライアント/サーバー間での齟齬も減らせるので、実践してみる価値はあるのではないかと思います。

まとめ

今回は CLINICS アプリの開発でのスキーマ言語の活用例について紹介しました。 実際に開発の中でスキーマ言語を使うことで API 仕様について把握する労力が減り、エンジニア間のコミュニケーションも取りやすくなったと感じています。 また、一部のクライアントコードは OpenAPI や Protocol Buffers から自動生成しているのですが、かなり手間が省けると同時に人間の手で書くと起こりがちなミスも防ぐことができています。 OpenAPI であれば既存の REST API の仕様を書き起こすところから使い始められるので、興味のある方はぜひ一度使ってみてはいかがでしょうか。

最後に

インキュベーション本部では「医療ヘルスケアの未来」をつくる新規事業の立ち上げに挑戦しています。そんな私たちと一緒に働いてみたいと思った方は、ぜひ以下の採用情報もチェックしてみてください。

www.medley.jp