Medley Developer Blog

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

医療ヘルスケアベンチャーで開発チームとSyncした知財部門を立ち上げた話

はじめに

こんにちは、メドレーのコーポレート本部法務コンプライアンス部で、知的財産関連の業務を担当している鬼鞍です。

1年ほど前に本ブログで「特許とはなにか」というテーマで当社における特許啓蒙活動を紹介させて頂いたのですが、思っていた以上に反響があり、「面白い」とか「わかりやすい」という嬉しいコメントも頂戴しました。

私がメドレーに入社して最初のミッションが知財部門の立ち上げだったので、次はぜひベンチャーでの知財部門の立ち上げ方」的なテーマでブログ発信したいと思っていたのですが、当初はまだ具体的な社内事例が少なかったため、実績ができた段階で改めて本ブログで発表したいと思っていました。

それから1年以上が経過して実際に特許も取得するなど知財活動としての実績が蓄積されてきたため、これを機会にベンチャー知財部門を立ち上げる際にやるべきことについて、実例に触れながら具体的にまとめてみました。

かなり長いコンテンツになってしまいましたが、フェーズごとの知財活動計画であったり、知財ロードマップの作り方など、なかなか表に出てこない知財部門立ち上げストーリーの具体的事例を惜しみなく書かせていただいておりますので、ぜひご一読いただき、お役に立てれば幸いです。

●目次

知財は開発チームとの信頼関係の構築がまず第一

先ほどは知財部門を立ち上げストーリの中で、知財活動計画とか、知財ロードマップであるとか少し格好つけたような文字が羅列していましたが、実は私が知財専任として初めに配置されて最初にやったことはそんな大それたことではありませんでした。

最初になにをやったかというと、エンジニアの方とランチに行く、あるいは飲みに行く、ということでした。当時はまだCovid-19が蔓延する前だったので気軽にそういうことができました。入社して最初の1ヶ月くらいは週2回くらいのペースで誰かとランチか飲みにいくということをしていたと思います。

飲みに行く、というとふざけているとか思われるかもしれませんが、知財部門の立ち上げストーリーを語る上で、このプロセスは無視できないほど重要だと考えています。先に断っておくと私は酒好きでもなければ、家でも一切飲みません。

当たり前のことなのですが、知財というのはプロダクトを生み出す開発組織があって初めて価値を発揮するものです。知財はあくまで事業や開発をサポートするところであって、それ単体で存在意義を発揮することはほぼありません。特に特許活動については開発チームとの連携が非常に重要です。

一緒にご飯を食べることが信頼関係を構築する上で最良の方法、とまでは言いませんが、少なくともご飯を食べない人はいないわけで、時間を無駄にしている感もなければ、オフィスの外で会えば仕事以外のことを話題にし易いので互いの趣味嗜好を知ることができます。みなさんもそうだと思いますが、通常、仲の悪い人とは一緒に食事はしないと思います。

特に、この後にもご紹介する社内のアイデアを発掘するという発明発掘活動は、話しやすいカジュアルな雰囲気で雑談のような感じでブレストするというのが非常に重要で、このときに相手がどんな人間かを互いに知っているか、知らないかでは大きな差がでてきます。

また更に、この後にご紹介する知財計画立案や知財ロードマップを作成することも当然重要なのですが、結局仕事というのは人と人との間を思考がやりとりされて実現化されていくものなので、人間関係・信頼関係が全ての基礎であり、実は一番大切にするべきものだと思います。

これは何も知財に限ったことではなく、部門を跨いで仕事をする上で信頼関係は非常に重要ですし、知財の観点で見ても円滑なコミュニケーションが結果的にいい発明やアイデアを生み出すための土壌づくりに貢献するものだと考えています。

知財活動計画は、事業の成長フェーズに合わせて設定する

知財部門の設立にあたって、エンジニアとのコミュニケーションと並行して進めたのが、知財活動計画の立案でした。知財活動とは、知財サイクルをうまく事業サイクルにインストールしてサイクルを循環させることであり、更にはこのサイクルが循環するための運用基盤を構築することを指します。また、ここでいう知財サイクルとは、例えば、社内に埋もれたアイデアを発掘し(創発)→それを知財権化し(保護)→権利化した知財を活用し(活用)→活用した知財で得られた利益や結果を創発支援に適用できる形に変換する、というものです。

f:id:medley_inc:20211126120413j:plain

このような知財サイクルを、何の計画や戦略もなしに事業サイクルへインストールしようとするとうまくいきません。なぜなら、事業というのは日々成長し変化していくもので、事業の成長に応じて知財活動の目的や課題も変化するからです

例えば、子会社が増えて事業規模が拡大すると、その子会社の事業領域で既に多くの特許出願がされている場合には、発明発掘活動よりもまずは法的リスクを回避することを最優先にして、他社の特許調査をしっかりやってからプロダクトをリリースする仕組みを作ろう、ということになります。あるいは、事業の成長に伴いプロダクトが成熟してきた場面では、似たようなプロダクトが乱立する結果、尖った機能や最先端技術で差別化をするようになるため、こうした場合には先行した特許取得が重要な目的になってきます。

このように、事業の成長フェーズに応じた知財活動の計画を立案するべく、まずはメドレーのミッションおよびそのミッションを実現するためのプロダクトの性質を把握する必要がありました。

メドレーは「医療ヘルスケアの未来をつくる」というミッションを掲げ、インターネットテクノロジーによる医療のあり方の変革を目指す企業です。

このミッションと向き合いつつ、事業プラットフォームの成長フェーズごとに知財活動の方向性・目的を3段階にわけて設定し、成長フェーズごとに知財活動計画を立案しました

f:id:medley_inc:20211126120416j:plain

例えば、プラットフォームの創設期においては新規ユーザ獲得が重要となり、使い勝手のいいシンプルな機能に開発の方向性が向いているため、独自性のある技術を特許化するというよりも、まずは守りを固めるべく知財権侵害のリスクを最小限にして法的安定性の確保に軸足を置いた知財活動を推進します。

このような計画は、知財の観点で一方的にできるものではありません。

知財活動の計画に際しては、開発チームを統括するマネージャにプロダクト開発の方向性をヒアリングして特許取得の判断基準を検討したり、経営層に将来の事業の方向性についてヒアリングをして長期志向で目標設定したりして、ブラッシュアップしていきました。

そういった検討や議論を重ねていくうちに自然と、その企業風土や事業ミッションにあった知財活動計画というものができあがってくるのだと思います。

知財活動ロードマップで現在位置を把握しつつ定期的に軌道修正する

長期的な方向性を可視化したら次はそれをどう実行するかという実行計画が必要になってきました。

そもそも自分たちは今何ができていて、何ができていないのか。またどのようなことを今後やっていかなければならないのかが不明確だよね、という話になり、それを具体的に俯瞰するための知財ロードマッピングというものを作成しました。

f:id:medley_inc:20211126120419j:plain

縦軸に知的財産の種類、横軸に時間軸であるフェーズを設定して、知財活動の内容に過不足ないかをチェックできるようにしました。

定期的に内容を見直してメドレーの事業規模にあった形に修正しながら自分達の現在位置を把握し、今後の方向性を見定めるためのツールとして有効でした。

このようなロードマップがあれば、知財担当者の立場からすると、実績が可視化されるため知財活動を推進していく上での達成感もありますし、逆に知財担当者を評価する立場からしても、明確な評価基準がない中で、知財担当者の評価をする際に役に立ちます。

以上のように、何もないところから他部門と関わりながら知財活動計画を立案し、ロードマップを達成していくのは、知財部門を立ち上げるという業務の面白さの1つでもあります。

初期段階から長期視点で知財素人でも回せる業務運用作りをする

1人法務や1人知財担当という状況は、遅かれ早かれ属人化という問題が必ずやってきます。

属人化は組織運営上、健全ではありません。

そのため、知財に関する知識がない人間でも、誰でもその業務を回すことができるような状態をつくるために、知財部門立ち上げの初期段階から、自分が担当している業務でルーチン化できるものは全て仕組み化してドキュメントに落とし込むようにしていました。

例えば「怪しい特許を見つけた場合の動き方」、「発明報奨金の決定プロセス」、「他社特許調査及び発明発掘のハイブリッド調査の進め方」などなど、ありとあらゆるプロセス業務を全てフロー図や概念図を作成し、誰か見てもわかる業務ということに留意しています。

f:id:medley_inc:20211126120422j:plain

現状はまだ引き継ぎや新たな知財部員の登用という話がないので、わかりやすい効果を発揮しているわけではないのですが、他部門からの問い合わせがあった際は資料だけ渡せば理解してもらえるので、コミュニケーションの効率化には貢献していると思います。

どのような特許を取得すべきなのか

企業としてどのような特許を取得していくべきか、ということは「知財を最大限に活用する」という知財の出口から考えていく上で、重要な事項になります。

そしてどのような特許を取得するかは、事業領域や事業ミッションに沿って設定されるべきです。

メドレーは、オープンプラットフォームによる医療のあり方の変革を目指している企業なので、開発チームから上がってきたアイデアについては、プラットフォーム事業を適切に運営していく上で必要な技術かどうか、という観点で特許化するかどうかを判断しています。

例えば、最近特許を取得した医療データの管理方法(特許第6921177号というものがあります。これは、アプリ端末から入力された患者データと、医療機関の各業務システムから入力された患者データという2つの類似したデータをシームレスに管理するために、両方のデータを2つのデータベース上で統合管理することにより、データ管理の責任分担の明確化及び厳格な情報管理を可能にするというものです。

仕組みとしてはとてもシンプルなのですが、患者の持つ端末と、医科・歯科・調剤等の各業務システムをシームレスに連携させる仕組みが、医療プラットフォームを適切に運営していく上で必要な技術だと判断したため、特許化しました。

f:id:medley_inc:20211126120426j:plain

また、上記事例のように実際にプロダクトに実装されている技術を特許化したものだけでなく、実際にプロダクトに実装するかわからないけれども将来を見据えた先見的な特許として、ブロックチェーンを用いた電子処方箋の管理方法(特許第6936763号という特許を取得しています。

これは、ブロックチェーンを用いたアクセス権の管理機能として全体的に秘密状態を保ちながら電子処方箋を管理するためのアクセス制御に関する仕組みで、ブロックチェーンデータベース上において処方箋データと患者データとを紐づけて、医師端末からの患者レコードへの一時的なアクセス権限を付与し、会計終了時に患者端末の操作に応じて医師端末へのアクセス権限を剥奪するというものです。

f:id:medley_inc:20211126120429j:plain

このような特許を取得した背景には、マーケットを独占して権利主張をするためというよりも、メドレーが考える未来のプロダクトビジョンであったり、開発部門の先見的な創作活動を対外的に発信したい、という思いがあります。

メドレーは、顧客利用率の高いプロダクト、機能拡張性の高いプロダクトの開発を推進しているため、独創的で最新技術を取り入れた尖った機能を目指すというよりはユーザにとって使いやすいシンプルさが多く取り入れられています。また、それだけではなく、前述したブロックチェーンと電子処方箋との組み合わせ技術の先見的な特許取得のように、10年先を見据えた未来のプロダクトのあり方についても日々追求しています。

特許を身近に感じてもらうためのユニークな話も取り入れて社内に啓蒙する

いい特許を生み出すためには地道な社内の啓蒙活動も重要です。

メドレーでは、開発チーム間の技術格差の是正や、技術情報の共有による活性化を目的として、エンジニアが日々の業務で扱っている技術や取り組みについて共有するテックランチという勉強会が定期的に開催されています。

先日そのテックランチで、社内のエンジニアの方達に少しでも特許を身近に感じてもらおうと、「特許の頭体操」というコーナーを設けて、実際に頭を使って体験してもらいました。

下の例では、おたまとスプーンとの違いを考えようというお題を通して、ある物の特徴を把握する際に、「違い」から「もの」を観察すると、その物の特徴が浮き出てくる、というメッセージが含まれています。

f:id:medley_inc:20211126120432j:plain

おたまもスプーンも対象物をすくい上げるという機能においては共通しているのですが、おたまの先端のお皿部分とスプーンの先端のお皿部分とは、その形状が異なります。スプーンのお皿部分は楕円形ですが、おたまのお皿部分は円形になっています。

つまり、おたまの特徴は、特許的にいうと「その先端にあるお皿部分が円形の開口を有した半球状で、対象物をすくうための所定の深さを有している」ということになります。

この辺はちょっと固苦しい表現が続いたせいもあり、「難しい...」というコメントをもらいました。馴染みのない人にとってはただただ面倒な作業だと思います。

しかし、ここで言いたかったのは、これはあくまで構造物についての話であって、ソフトウェアの特徴を把握するということはそんなに難しいことではないのだよ、ということでした。

ソフトウェアの場合は、ちょっとした機能を追加すれば、それが従来のソフトとは異なるものとなり、比較的簡単に特許になってしまうケースが少なくありません。

f:id:medley_inc:20211126120842j:plain

つまり、エンジニアの方は日々新しい機能を実装すべく開発業務を行っているわけなので、知財の観点から言うと、極端なことを言えば日々発明をしているということになります。当然特許になるかどうかは別の話になりますが、日々の開発業務で自分が発明をしていることに気づいていない、という状況が多分にあるということです。

さらに、知財担当がこれに気づかなければ、日の目を見ることない埋蔵知財が量産されるということになってしまいます。

では、どのようにしてエンジニアの方が自ら発明をしていることに気づいていないものを発掘し、社内の知的財産として認定していくのか、というのが次の話になります。

面白いアイデアは雑談から生まれる

日々の開発業務の延長で生まれてくる機能や技術を特許化するという活動が基本であることは間違いないのですが、実際にプロダクトに実装するかどうか不確定要素を多く含むアイデアを特許化するという活動は、エンジニアの開発成果物を知的財産として見える化することで、エンジニアの成果が報われる土壌を作るという意味においては大切な活動になってきます。

ただ、どの企業知財部でも発明発掘業務はされていると思いますし、「アイデアは雑談から生まれる」ということは既に周知の事実かもしれません。また、知財活動として特段新しいことをしているわけではないのですが、実際にそれを実行する際の心構えであったり、具体的に気をつけていることについて、事例を通してご紹介したいと思います。

私は、エンジニアの方というのは、アイデアの卵をもっているという前提に立ってエンジニアの方とコミュニケーションをとるようにしています。

そうすると、「実はアイデアありますよね、なんで言ってくれないんですか〜。」という具合にカジュアルな会話をスタートすることができ、スムーズにブレストを進めることができたりします。大したことではないのですが、意外とこういう心がけが円滑なコミュニケーションを生み出すきっかけになっているかもしれません。

一方で、エンジニアの方は暇ではありません。

日々の開発では、既存機能の修正や新規機能の開発などの案件に追われるため、頭の中にあるアイデアの卵も埋もれてしまいがちです。

以上のことを踏まえ、エンジニアからアイデアを出してもらうためのブレストMTGでは主に以下の点に気をつけています。

  • エンジニアの方の負担にならないように短時間に設定すること(長くて30分)
  • カジュアルに話しやすい雑談ベースの雰囲気にすること
  • そのために少人数で行うこと
  • 出てきたアイデアを楽しむこと

実際に下図に示すような雑談ベースの会話から、「診療方式を患者と医療機関との間の距離に応じて、対面診療かオンライン診療かを自動的に切り替える」というアイデアが生まれ、実際に特許出願につながりました。

f:id:medley_inc:20211126120918j:plain

この時にエンジニアの方々からは「とても面白い!」とか「またやりたい!」という前向きなコメントをもらえて、カジュアルベースの雑談効果を実感しました。

このようなブレストを通して一番大きな気づきというのは、エンジニアの皆さん、本当によくプロダクトについて考えているということ。

エンジニアの方々の創意工夫が全て知的財産「権」になるわけではないのですが、知的財産であることには違いありません。

これからは、そういったエンジニアの方の頭の中に埋もれがちな創意・工夫というものが報われるような土壌作りを、知的財産というツールを使って構築していきたいと考えています。

このブログも「特許を対外的にどう見せるか」という実験の1つ

ここまでご紹介してきた内容は、知財計画を立てて、立てた計画に沿って知財業務を運用し、運用していく中でアイデア発掘して知財化する、という話にとどまってましたが、実際に取得した知財権をどのように活用して企業価値の向上につなげるのか、ということがこれからの知財部門にとっての重要なミッションになると考えています。

従来は、特許権の独占排他権という性質を使って参入障壁として活用したり、模倣の抑止に活用されるのが常識だったと思いますが、メドレーではこれまでにない新たな活用方法を模索しています。

実はこのブログもそうなのですが、特許を対外的にどうみせるか、ということの1つの実験です。

どういうことかというと、ここまでご紹介してきた知財活動自体も人の知的活動によって生み出された知的財産であり、このようにブログで発信しなければ単なる埋蔵知財になってしまいます

例えば、特許取得についてもただ特許を取ったという事実を公表するのではなく、どうしてそのような特許を取得してどのように活用しているのか、またそこに関連したメンバーは誰でどのような検討があったのか、というストーリーメイキングをすると、特許というものを中心とした1つのドラマが浮き上がってきます。

今回は知財活動のご紹介という趣旨で、特許を中心とした内容になっているため、特許に関心がない人にはあまりささらないコンテンツになっているかもしれませんが、例えば特許と広報との掛け算でストーリーメイキングをすれば特許に関心がある人だけでなく、広報に関心がある人にも情報がリーチすることになります

f:id:medley_inc:20211126120933j:plain

これは特許というものが、人材・業務ノウハウ・広報・採用活動等と同列に知的財産であるがゆえになせるものです。これからは、知的財産=特許、商標という視点ではなく、知財=目に見えない創造的な活動という捉え方をした上で、企業価値に貢献していく必要があります。

知財部門が、採用、IR、広報、開発、社内ITといった企業内にある多数の部門とコラボレーションすることでこれまで見たことのない新しい知財活用の形を模索し、知財を最大活用することによって企業価値を向上させていきたいと考えています。

さいごに

ここまで、知財活動の一部をご紹介させていただきましたが、これが知財活動の進め方として正解というわけではなく、企業風土や事業領域によって、知財活動のあり方は異なります。そして、そこを考えながら知財活動を推進していくことが仕事の面白さであり醍醐味とも言えます。新しい知財部のあり方や、新しい知的財産の活用方法を検証しながらも、建設的かつ柔軟に日々の業務を進め、メドレーの事業をしっかりとバックアップしていきたいと考えています。少しでも当社の知財活動が参考になれば幸いです。最後までお付き合い頂きありがとうございました!

www.medley.jp

サービスのダウンタイムなくRDSをAuroraに移行した話

こんにちは、人材プラットフォーム本部 プロダクト開発室 第一開発グループ所属の森川です。医療介護求人サイト「ジョブメドレー」の開発チームの一員として、現在はインフラタスクをメインに取り組んでいます。

今年(2021年)の6月の話ではありますが、ジョブメドレーの連携サービスにて使用しているデータベースを、通常のRDS(Amazon RDS for MySQL)からAurora(Amazon Aurora)に移行しました。

タイトルは自分でも大きく出たなと思ってはいるのですが、サービスの特性に助けられたところはありつつも、ダウンタイムなく移行することができました。今回はそのいきさつについてお話させていただこうと思います。

本稿ではAmazon RDS for MySQLを「通常のRDS」、Amazon Auroraを「Aurora」と表記させていただきます。

ジョブメドレーの連携サービスについて

ジョブメドレーは医療介護従事経験者が運営する就職・復職・転職のための求人サイトです。このジョブメドレーの連携サービスとして医療・介護・福祉・歯科従事者向けの情報サービスを他社と共同運営しています(以降、本サービス)。

本サービスはアプリケーションシステムのバックエンドの開発フレームワークとしてRuby on Rails(以降、Rails)を使用し、弊社で開発・運用を行っています。表示コンテンツは他社から共有していただくものを表示する形となっています。

発端

今年の1月末にAWSから以下のようなメールが届きました(内容を一部抜粋しています)。

Amazon RDS は、MySQL メジャーバージョン 5.6 の廃止 (EOL) プロセスを開始しています。

お客様は古いバージョンで実行されている RDS MySQL インスタンスを1つ以上お持ちであるように見受けられます。

Amazon RDS for MySQL 5.6 は、UTC 協定世界時間の2021年8月3日に廃止されます。

公式のお知らせはこちらです。

EOL通知はドキッとします。できれば見たくないものです。

この対象となっていたのが、本サービスで使用しているRDSのMySQL v5.6.39(当時)でした。

対応方針として以下を考えました。

  • 通常のRDSのままMySQLのバージョンを5.7に上げる
  • 通常のRDSからAuroraへの変更も行いつつ、MySQLのバージョンを5.7に上げる
  • MySQLのバージョンを8まで上げる

MySQL 8系へのバージョンアップは対応範囲が大きくなりすぎるため今回は断念しました。5.6のEOL期限が迫っているため時間の余裕はあまりありません。また、もし8系に上げるとしても、5.7へのバージョンアップは挟む必要がありそうです。

ジョブメドレー本体のシステムにおいても、性能やメンテナンス性の向上の観点から、通常のRDSからAuroraへの移行を計画しております。その足がかりとして、関連アプリケーションの中でも比較的システム規模の小さいものから、先行して移行作業をしておきたいという要望がありました。

これらを加味して、今回のミッションは「通常のRDSからAuroraへの変更も行いつつ、MySQLのバージョンを5.7に上げる」となりました。

検証

インフラ構成に変更を加える際には言うまでもなく検証が必要です。インフラ関連タスクに取り組むにあたって大きなウェイトを占めるのが検討・検証なのではないかと個人的には考えています。

Auroraへの乗り換え検証のために、新たにDBインスタンスを用意しました。既存相当のスペックの通常RDSとそれよりも少しスペックの落としたAuroraです。正確な比較を行う場合であれば、両DBインスタンスのスペックは揃えるべきかとは思いますが、現行のRDSがオーバースペックであることも課題のひとつであったため、検証段階からAuroraのスペックを落として検証を行っています。よって検証結果による成否判断としては「著しい悪化が見られないか」という観点になっています。

既存相当のRDSのスペックはdb.m4.large 、Auroraのスペックは暫定的にdb.t3.mediumを選択しました。また、データベースに流し込むデータは本番相当のものを個人情報などはマスクした上で用意しています。

検証の項目は以下の4点です。

  • レスポンスタイム検証
  • SQLごとの速度検証
  • 実行計画の検証
  • フェイルオーバー後に元writerに対する接続が継続される問題への対応検証

レスポンスタイム検証

まずは、レスポンスタイムの影響について確認しました。

本サービスにおける主要なページのURLを選出します。それぞれのページに対して数回のリクエストを行い「低負荷状態」でのレスポンスタイムを比較しました。Auroraの方が一桁ミリ秒程度遅いという結果となりました。

次にApache Benchを用いて短時間に並列でのリクエストを行い「高負荷状態」を再現して比較を行いました。本サービスはスパイクで負荷が高まるような性質ではないため、普段のアクセス頻度を元に「高負荷状態」がどの程度かを想定して定義しています。結果として、一部のページにて1秒ほど遅くなっていることが分かりました。スペックを上げることで解決ができるのかを調査するため、インスタンスサイズをdb.t3.mediumからdb.t3.largeに変更して改めて試しました。しかしAuroraの方が遅いという結果に変化は見られませんでした。アプリケーション側の調査を進めると、データベースの問題ではなくアプリケーション側の問題であることが分かり、別途対応ということになりました。

以上より、Auroraへの移行によるレスポンスタイムへの影響としては、多少の性能の低下は見られたものの許容範囲内であり、大きな問題は見られないことが分かりました。

SQLごとの速度検証

こちらはレスポンスタイムの検証に近しい検証ではありますが、生のSQLの速度の調査も行いました。アプリケーションを通して実行されるSQLの中でも実行される頻度の高いものを選出し、アプリケーションを介さずクライアントツールから実行しています。

こちらも大きな問題は見られませんでした。

実行計画の検証

この検証でもアプリケーションの中で実行される頻度が高いクエリを選出し調査を行いました。使用したのはお馴染みのEXPLAINステートメントです。

実行計画に差分は見られなかったため問題はありませんでした。

フェイルオーバー後に元writerに対する接続が継続される問題への対応検証

RailsアプリケーションへのAurora導入において、必ずと言ってよいほど障壁となるのがこの問題かと思います。

AuroraのフェイルオーバーとRailsへの影響

Auroraの特徴や通常のRDSとの差分については様々なサイト・記事で詳しくまとまっている情報ですので本稿での詳解は割愛しますが、Auroraのフェイルオーバーについてのみ概要を説明させていただきます。

マルチAZでのAurora DBクラスターのプライマリDBインスタンス(writerと呼ばれる)において障害が発生した場合、フェイルオーバー(待機システムへの切り替え)が自動で実行されます。プライマリDBインスタンスのリードレプリカ(readerと呼ばれる)を配置していた場合は、それが次のプライマリへと昇格し、エンドポイントも切り替わってくれます。

次にRailsActiveRecordのコネクションプールについてです。ActiveRecordはデータベースへの接続情報を保持し、そのコネクションを再利用することで接続時のオーバーヘッドを解消し、高速化を図る仕組みを保有しています。本サービスにおいてMySQLのクライアントとして使用しているmysql2では、コネクションがアクティブであることをmysql_pingが判定してくれるようです。しかし残念なことにAurora側でのフェイルオーバーの発生までは検知することができないようです。

したがって、フェイルオーバーが発生すると、プライマリから降格した元writer現readerであるDBインスタンスに対してコネクションが張り続けられてしまうため、書き込みのリクエストに対してはエラーとなってしまう状態になります。

f:id:medley_inc:20211105182842p:plain

対応策

対応策としては以下を考えました。

  1. Aurora用のクライアントGemを使用する
  2. Mysql2::Errorが発生した場合、サーバーエラーにしつつコネクションを切断して再接続を促す
  3. 一定回数リクエストを処理するごとに再接続させる

今回採用したのは上記の3の「一定回数リクエストを処理するごとに再接続させる」対応です。

当初は対応策1のGemの使用を検討しておりましたが、トランザクション中にフェイルオーバーが発生した際の挙動が本サービスには適合しないことが分かりました。またいくつかの対応策を複合して実装するという方法も考えられました。

今回においては、実装工数や、サービスの規模から考えうる必要十分の最小値を検討した結果、この判断としています。

再接続の度に発生するオーバーヘッドによる速度影響についても低負荷・高負荷の状態で検証を行いましたが、数値的には軽微であり、少々の遅延は許容することになりました。

この対応は、Auroraへの移行の前、つまり通常のRDSで稼働している状態であってもリリースして問題ないものだったため、事前に実装・リリースを行うことができました。

料金

「現行のRDSがオーバースペックであることも課題のひとつ」と上記しておりましたが、その是正による料金の合理化についても副次的効果として期待していました。

Auroraの料金形態には、通常のRDSと同じ「DBインスタンス時間従量課金」「ストレージ時間従量課金」に加え、「I/Oリクエスト数従量課金」という項目が追加されているため、比較を行う際は注意が必要です。

移行前後の条件は以下の通りです。

  • 通常のRDS(移行前)
    • オンデマンド
    • RDSで稼働しているのは本番環境のみ
    • db.m4.large
    • ストレージ 100GB
  • Aurora(移行後)
    • オンデマンド
    • 本番環境だけでなく検証環境もAuroraで稼働させる
    • 本番環境 db.t3.medium, 検証環境 db.t3.small
    • ストレージ 100GB(両環境とも)

移行前の通常のRDSでは本番環境のみで月々4万円以上かかっていたコストですが、移行後は本番環境に加え検証環境においてもAuroraを使用するようにしても合計3万円以下という計算となりました。月々1万円、年額12万円の節約になります。さらにはオンデマンドからリザーブドへ変更することも今後検討ができるため、コストカットの余地がまだ残されているのも嬉しいところです。

リリースに向けた準備

リリース作業のキモとなるデータベースの切り替えは、「リードレプリカからの昇格」という方法を採ることとしました。MySQLのバージョンアップについては、プライマリが通常のRDSからAuroraに切り替わった後に、AuroraインスタンスMySQLバージョンを上げるための変更を実行します。

これらの作業をデータの不整合を発生させることなく完遂させるためには、データベースへの書き込み動作をすべて停止させる必要がありました。

これを実現するためには、データベースへの書き込み処理が発生するケースをすべて洗い出さなければいけません。調査をしたところ、本サービスでは「社内管理画面」と「バッチ処理」でのみ書き込み処理が実行されていることが分かりました。

つまり、一般ユーザからの書き込み処理は本サービスでは保有していないため、書き込みが行われるタイミングを把握・調整することが可能でした。したがって、一般ユーザが見ることのできるページをメンテナンスモードに切り替えるなどの「サービスのダウンタイム」を発生させることなくAuroraへの移行とMySQLのバージョンアップを行える、ということになります。

リリース時に影響が生じる周辺情報の洗い出しも一通り済んだところで、次に「手順書」の作成に取り掛かりました。必要な全ての操作について順序に沿って詳細にまとめます。その中には、各段階にて万が一障害が発生した場合の切り戻し手順についても記載しています。

手順書を元に、検証環境にて同様の手順を実行し、予行演習を行いました。これによって、本番での作業を鮮明にイメージすることができます。また大抵の場合、手順書の不備やブラッシュアップできるところが見つかります。予行演習は本番作業を滞りなく実行するための最も重要なファクターのひとつかと思います。

f:id:medley_inc:20211105182450p:plain
実際に使用した手順書(一部抜粋)

リリース作業

リリースで行った作業の要点をまとめると以下となります。

  • 本番用データベースのリードレプリカをAuroraで作成
  • データベースへの書き込みを停止
    • 社内管理画面の操作を停止いただくよう社内へのアナウンス
    • バッチ処理の実行をすべて停止
  • レプリカAuroraをプライマリへ昇格
  • データベースのコネクション更新のためサーバ1台ずつアプリケーションの再起動
  • バッチ処理の再開
  • 動作確認

大きめのリリース作業はアクセスの多い時間帯を避けて行われることもあるかと思いますが、今回はサービスのダウンタイムなく作業を行えるケースであるため午前中からの作業開始となりました。また作業を行う自分の隣には先輩社員が構えており、ダブルチェックをしていだきました。

手順書の作成と予行演習の甲斐もあって、本番リリースを問題なく進めることができました。

まとめ

サービスの特性に助けられたところは大きいですが、サービス停止などのダウンタイムを発生させることなく通常のRDSからAuroraへの移行を完了させることができました。

スティーブ・ジョブズは数分のプレゼン発表のために数百時間の準備をしていたといいます。プレゼンで言うところのシナリオの作成とリハーサルの実行もそうですが、サービス特性の理解や検証を綿密に行うことも本番を成功させるためには欠かせません。準備を怠らないエンジニアでありたい、と執筆しながら改めて感じているところです。

さいごに

メドレーでは「医療ヘルスケアの未来をつくる」というミッション実現のため、日々開発・運営を行っています。エンジニア・デザイナーをはじめ多くのポジションでメンバーを募集しております。もし少しでもご興味をお持ちいただけましたら、ぜひお気軽にお話しさせていただければと思います。

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

www.medley.jp

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

こんにちは。医療介護求人サイト「ジョブメドレー」の開発を担当しているエンジニアの山田です。 今年の新卒エンジニア研修において、メンターを担当しました。

メドレーでは2019年度から新卒採用を行なっており、今年2021年度は5名の新卒がエンジニアとして入社しました。

例年と同じく4月から9月にかけて、約5ヶ月間の新卒エンジニア研修を実施しましたので、その取り組みを、研修受講者である新卒からの声も交えてご紹介します。

新卒研修の概要

今年の新卒研修の最終ゴールは、「メドレーのエンジニアとして、Our Essentials(※) を体現し、顧客へ価値提供できるようになるための基礎を身につけ、経験を得ること」として掲げました。

※) メドレーの行動原則

メドレーの新卒エンジニア研修では、技術を身につけることだけではなく、ビジネスパーソンとしての基礎を身につけ、メドレーが大切にしている価値観を理解し、体現する意識をもって、顧客への価値提供について自分の言葉で話せるようになることまでを目指してもらいます。

研修は昨年同様、大きく分けて、4つのフェーズに区切って行いました。

f:id:medley_inc:20211013113305p:plain

また、全研修期間を通じて、各新卒にはメンターを一人ずつ付けました。メンターは、一週間に1~2回のペースで新卒と1on1ミーティングを実施し、フィジカルとメンタルの両面を気遣い、個別にフォローを行いました。

新卒研修の内容

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

リスク研修

ビジネス研修

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

フェーズ1では、成果を出し、価値を発揮するために必要なビジネスパーソンとしての基本的な仕事の型を身につけることをゴールとしました。

リスク研修では、メドレー社員として、社会人として、身の周りで起こりうるリスクについて考え、いかにそれらのリスクと向き合うかを講義形式で学んでもらいました。

ビジネス研修では、社会人としての最低限のマナーを学び、論理的思考力、コミュニケーション力など、エンジニア職に限らない課題解決力へつながるポータブルな知識を、座学とワークショップを通じて定着してもらうことを図りました。

また、社会人の基準で仕事と向き合い、適切な報連相によって周囲と協働していくことの重要性についても学んでもらいました。

新卒からの声

  • 質の高い、多量のインプット・アウトプットができた
  • 伝わるメールの書き方、名刺の渡し方など、社会人に必須のマナーやスキルを認識できた
  • ワークを通じて、言葉では理解していても行動するとできないことを洗い出せた

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

開発基礎1

  • メドレーエンジニアとして求めること
  • 事業(ジョブメドレー ・CLINICS・介護のほんね)の概要説明
  • 開発基礎研修(Ruby on Rails チュートリアル
  • 開発実践 (要件定義〜リリースまで)

開発基礎2

  • 技術書の輪読会
  • ドキュメンテーションスキル研修
  • プレゼンテーションスキル研修
  • 中間レポート作成
  • 中間報告会

フェーズ2では、新卒研修後に開発業務に入ってもらえるよう、エンジニアとしての基礎を身につけることをゴールとしました。

メドレーエンジニアとして求めること

開発に関わるこのフェーズにおいても、要件定義を含む汎用的な技術的スキルは勿論のこと、メドレーエンジニアが共通して持つべき価値観などを共有するため、フェーズ2初日は「メドレーエンジニアとして求めること」と題して、エンジニアの執行役員 田中が講義を行いました。

講義では、「エンジニアとは、エンジニアの価値とは、プロエンジニアとはなんでしょうか?」という問いから始まり、講義の終わりにはもう一度同じ問いかけをして締めくくり、新卒がメドレーの求めるエンジニア像について自身の言葉で話せるように考えてもらいました。

メドレーが求めるエンジニア像については、CTO平山の メドレー平山の中央突破: THE エンジニア にも書かれていますので、よろしければ、あわせてご覧ください。

さらに、メドレーが展開する各事業および関連するプロダクトの概要説明をプロダクトマネージャーが行い、メドレーで開発する意義をあらためて認識してもらいました。

開発基礎研修

2日目より、Ruby on Rails チュートリアル(以下、「Railsチュートリアル」)を教材とした、開発基礎研修に移りました。

メドレーのプロダクトはRailsで作られているものが多く、Webアプリケーションを開発するための基礎を身につけるためにも、Railsチュートリアルの内容を実施してもらいました。

単純に、Railsチュートリアルの内容に沿って、ダラダラと写経するのではなく、随時、学んだことはConfluenceにまとめ、GitHub上でPull Requestを作成する形で、ソースコードを共有してもらいました。

学んだことを自分の言葉に置き換えてアウトプットすることで反復学習を促し、Pull Requestを作成してもらうことでGitHubの使い方に慣れてもらうことを図りました。

また、デイリーで朝会と夕会を実施しました。朝会は仕事のリズムを整えるための顔合わせ、夕会は新卒から質問・成果を共有してメンターがそれに対してフィードバックをする場としてそれぞれ実施しました。

研修前に既にRailsチュートリアルを一周していた新卒もいましたが、二周目を実施して新たな気付きを得たり、AWSを用いてクラウド上に環境構築し、作成したWebアプリケーションをデプロイするまでを実践してもらうなど、インフラに関しても理解を深めてもらうことができました。

新卒からの声

  • システムのパフォーマンスを上げるための工夫を知ることができた
  • バグ発生〜原因特定〜修正、というデバッグのスピードが、研修序盤から飛躍的に上がった
  • プロダクトで利用しているAWSの各種サービスの概要を理解できたことに加え、サービス間の繋がりやネットワークの流れに関しても理解を深めることができた

開発実践

開発基礎研修にてWebアプリケーション開発の基礎を学んだ後は、「メドレー/グループ会社で使う来訪者受付システム」を開発題材として、開発実践研修を行いました。

開発業務全体の流れを把握することで、チームで開発(課題解決)することを経験し、今後の仕事に役立たせることを目的としました。

本研修で達成すべきこととして掲げていたものは主に、次の通りです。

  • プロジェクト管理能力を身につけること
  • 開発する対象を体系的に整理できる能力を養うこと
  • システム設計に関する基礎的な物事を理解すること
  • チーム開発を理解すること
  • 品質を理解すること

既に決まりきった仕様書に沿って開発するのではなく、新卒自身が現状の問題把握や課題整理を行って、ユーザーへ価値提供するために何を作るべきかを考えることから始まり、リリース後の運用方法やランニングコストのことまで考え提案してもらいました。

開発実践研修は約1ヶ月の期間をかけて行いました。大まかな流れとしては、次の通りです。

  1. 要件定義(ヒアリング・現状把握・課題整理・要求分析・機能/非機能要件の洗い出し・UI草案)
  2. プロジェクト計画(役割分担・WBS/ガントチャート作成)
  3. 設計(画面設計・機能設計・データモデリング・方式設計・インフラ設計)
  4. 開発(実装・コードレビュー)
  5. QA(テスト設計・テスト)
  6. 成果発表(成果物を関係者へプレゼン・リリース)

方式設計の一部として、開発に使用する言語などの選定も新卒自身が行いました。

今回作成した社員向け管理画面と来訪者向け画面はいずれもSPA(一部、PWA)のアーキテクチャを採用し、主なライブラリ/フレームワークに関して、フロントエンドはTypeScript, React, Next.js, Chakra UI, Ionic Framework、バックエンドはRuby on RailsAPIモード)をそれぞれ利用することとなりました。

選定理由としては主に、次の通りです。

  • TypeScript, React(両画面共通)
    • ロジックからテンプレートまでの全てのコードを静的型付けで書くことができ、堅牢性に優れているため
  • Next.js, Chakra UI(社員向け管理画面)
  • Ionic Framework(来訪者向け画面)
    • iPad上で、ネイティブアプリのようなUI/UXを提供するため
  • Ruby on Rails APIモード
    • フロントエンドとバックエンドを分離して疎結合にするため
    • 短期間で構築するため
    • 社内でもよく使われておりメンテナンスしやすいため

インフラはAWSを採用し、EC2, S3, RDS, CloudFront, Route53, CloudWatchなどのサービスを利用しました。

結果的に、本研修プログラムの成果物としてリリースされたシステムは「Medley Entrance」という名前で、社内ツールとして現在、毎日稼働しており、ユーザーとしてメドレー/グループ社員だけではなく、来訪者の方々にも使っていただいています。

f:id:medley_inc:20211007112134p:plain

f:id:medley_inc:20211007112210p:plain

Medley Entrance(上:社員向け管理画面、下:来訪者向け画面)

チームで課題解決に臨み、価値提供までの実績を残せたことは自信につながり、開発実践研修のやりがいとして、感じてもらえたのではないでしょうか。

要件定義などの期間中、想定よりもスムーズに進められなかった時も他責にせず、各々がリーダーシップを発揮し、建設的に進めていく新卒の様子をメンターの一人として傍で見させてもらいました。

この1ヶ月間の開発実践研修を通じて、技術力はさることながら、課題解決に対する十分な熱意と主体性を新卒から感じられ、とても頼もしい印象として残りました。

新卒からの声

  • 開発の中での方針を意識して設計/実装することができた(シンプルにする)
  • QAとはそもそも何かというリサーチから入り、有識者の考え方を軸に方針を決めてから始められた
  • 各々が最適なパフォーマンスを発揮できる環境づくりを意識して、高速な意思決定が可能な体制を整えることができた
  • 要件が決まりきっていない中で設計するのは難しかった
  • 開発タスクが集中していた時に、プロジェクト全体の現状を把握できていなかった
  • 文章を作るスキルが足りていない

技術書の輪読会

フェーズ2の開発基礎2の輪読会では、 『Webを支える技術 -HTTP、URI、HTML、そしてREST』 を題材書籍として、7日間に渡って毎日、次の手順で実施しました。

  1. 参加者が同じパートをあらかじめ読んでおき、書籍から学んだこと、ネットなどで調べても解消しきれなかった疑問点などをまとめる
  2. その内容をもとに、夕方のミーティング時において、各自が発表してディスカッションを行う
  3. ディスカッションした内容は議事録にまとめる

輪読会は他者からの学びを共有してもらうことで、自分にはなかった視点・気付きを獲得し、その書籍への理解をより深められる効果があります。

本研修プログラムにおける輪読会の目的としては、Webサービスを開発していく上で必要となる知識へ触れることにより、今後獲得していくべき知識のベースラインを理解すること でしたが、輪読会ならではのメリット・楽しさを新卒に実感してもらえたことも、副次的な効果としてあったと思います。

新卒からの声

  • Webの基本的な知識を「なぜ登場したのか」を理解しながら網羅的に学ぶことができた
  • 文書でまとめた後に、口で説明することが学んだ内容の定着に良いと感じた
  • これまでなんとなく実装していたことの仕組みを学ぶことで、知識として定着することができた

中間報告会

フェーズ2:エンジニア基礎研修最後の研修プログラムである中間報告会に向けて、ドキュメンテーションスキル研修、プレゼンテーションスキル研修を実施しました。

上記スキルが必要となる背景は、次の通りです。

  • エンジニアリングを通じた課題解決とはプログラムを書くだけでは解決しない場面もある
  • 背景、目的を正しくステークホルダーへ共有しながらチームとして取り組んでいくことになる
  • 伝えたいことを文章として整理し、他者へ分かりやすく伝えていくことが求められる

また、メドレーの行動原則 Our Essentials を構成する要素として、「ドキュメントドリブン」「全てを明確に」という項目が含まれており、これらを実現するためにも、とても重要なスキルとしてメドレーは考えています。

新卒研修が終わった後も、エンジニアとして技術的なスキルを身につける機会は日常的に多くありますが、上記のようなスキルをまとめて習得する機会は少ないため、このような研修を社会人のはじめから受けておくことで、その後の伸びしろが違ってくるのではないかと思います。

研修が終わった後は、各自で報告会用の資料を作成し、研修講師からの添削を受けました。

中間報告会は各部署の開発マネージャーを発表相手として、当日は程よい緊張感をもって、良い雰囲気で報告会を終えられました。

フェーズ3:事業部OJT

事業部研修

  • 取締役豊田からの講義
  • CLINICS事業部研修
  • ジョブメドレー事業部研修

開発OJT

  • システム全体像説明
  • 環境構築
  • 各プロダクトの開発チームでのOJT

フェーズ3では、顧客の課題と、顧客への価値提供のための各チームの連携を体感し、メドレーの顧客提供価値を自分の言葉で話せるようになることをゴールとしました。

フェーズ3のはじめに、取締役豊田による日本の医療の課題とメドレーの取り組みに関する講義を受講してもらいました。

持続可能な医療体制を構築していくためにメドレーが成すべきことなどの話を聞いた後に、新卒からの質問の受け答えによって理解を深め、メドレーの社会的意義をあらためて認識してもらい、エンジニアとしてだけではなく、メドレー社員としての自覚を強めてもらいました。

事業部研修

開発OJTで手を動かす前に、自分たちが何のために開発するのかを具体的にイメージできるよう、次のように、各現場に参加してもらいました。

  • 見込顧客への架電業務見学
  • 商談前の社内ミーティング参加
  • 商談現場同席
  • 定例会議参加

事業部のスタッフが、顧客の課題に対して、どのような対応をしていて、どのようにプロダクトを説明しているのか、事業部の各チームが、どのように連携して最終的に顧客に価値を届けるのかの全体観を知ってもらうことを狙いとしていました。

開発チームのエンジニアは業務上、プロダクトのエンドユーザーである顧客の声などを商談のタイミングから聞ける機会はなかなか無いので、研修を通じて話を聞けたことは、今後の開発モチベーションにも影響する良い機会だったと思います。

新卒からの声

  • ユーザー、顧客、事業部が抱える課題を確認できたことで、開発以外にも目を向けるきっかけになり良かった
  • 各部署がKPIとして定めている数字を知ることができ、開発に降りてきている施策の影響箇所がどの部分かを理解できた上で、開発に取り組むことができるようになった
  • 各部署のミーディングに参加することで、各部署がどのような考えで何を目指しているのかを理解でき、メドレー全体として目指している方向性が掴めた

開発OJT

事業部研修に続く開発OJTでは、ジョブメドレーCLINICS介護のほんねの開発チームに分かれて、研修を実施しました。

OJT配属先では、メンターとは別に、トレーナーを付けて業務の進め方などをサポートしました。トレーナーは配属先の先輩エンジニアが担当しました。

OJTの流れとしては、初日に、プロダクトがどのように動いているのか、システム全体像を把握することから始まり、各自、ドキュメントに沿って、PCにローカル開発環境をセットアップしました。

その後は、他の先輩エンジニアと同様に、GitHub Issue で管理されている課題を解消することを日々の目標としてこなしてもらいました。ただし、単にIssueに書かれている課題をクリアしようとするのではなく、そもそも、なぜそれをやるのか、Issueの背景や起票者の意図を十分に理解した上で、プロダクトのあるべき姿に導くことを意識してもらいました。

Issueに書かれている内容の理解が不十分だったり、解決方針がうまく定まらない場合は随時、ミーティングの時間を設けて、Issue起票者やトレーナーと認識合わせを行い、認識の相違から生まれるミスコミュニケーションを極力減らすよう、取り組みました。

技術的な質問に関しても、定期的に質問タイムを設けたり、複雑になりそうな実装や、つまずきポイントとなりそうな箇所に関しては、画面共有を用いてレビューを行い、疑問点に関してもその場で確認して、解消してもらいました。

緊急事態宣言期間中だったため、会社全体で原則、在宅勤務の体制となっており、対面でのコミュニケーションが希薄になりがちでしたが、朝会、夕会を含め、たとえ新卒から質問が無くても質問タイムでのミーティングは定期的に実施するなど、できるだけ頻繁に顔合わせして、新卒本人の声と顔を確認するよう心がけました。

Issueへのアサインから始まって、実装 -> レビュー依頼 -> QA -> リリース -> Issue起票者への報告まで、一連の開発フローを経験してもらい、チーム内での開発業務に慣れてもらうことができました。

フェーズ4:最終報告

新卒研修最後のプログラムとして、メドレー役員陣に向けた最終報告会を実施しました。

最終報告会の目的としては、次の通りです。

  • 学んだことの知識を深化させる
  • 自らの得手・不得手を捉え、将来の成長計画を立てる
  • 体系的に整理・文書化して他者へ伝えるスキルを向上させる
  • 役員陣に向けてプレゼンすることで、本配属に向けた決意表明として区切りを付ける

役員陣への発表であることに加え、一人あたりの発表時間にも制限が設けられており、当日の緊張はかなりのものだったと思います。

前日に発表会場を下見して、リハーサルを入念に行うなど、当日の発表会を成功させるため、メドレーのエンジニアとしての自覚を持って、発表準備に取り組んでいました。

技術志向とプロダクト志向の両輪を目指すエンジニア募集中

メドレーの研修では、技術的な講義や実践だけで終わるのではなく、ビジネスパーソンとして必要な基礎も身につけ、なぜ開発するのかを追究し、プロダクトを通じた課題解決を実体験してもらうことを重視しています。

メドレーでは、医療ヘルスケア分野の課題解決に挑みたいエンジニアを募集しています。

新卒の学生に限らず、中途採用も行っているので、エンジニアの方で少しでも興味を持っていただけたら、是非、面談でお話ししましょう。

最後までお読みいただき、誠にありがとうございました。

P.S.

昨年、一昨年の新卒研修の様子はこちらより、それぞれご覧いただけます。

www.medley.jp

新卒エンジニアが2年目でプロジェクトリーダーを経験して得た学び

はじめまして。メドレーのエンジニア熊本です。新卒で入社し今年で3年目になりまして、2019年度エンジニア新卒の研修を終えてから早2年が経とうとしています。

そんな私ですが去年の11月頃から先月までの間、とあるプロジェクトのリーダーを任せてもらっていたので、そのお話をさせていただきます。

はじめに

私は新卒研修を終えてから医療介護求人サイトジョブメドレーのチームで開発をしていましたが、そのジョブメドレーを支える社内管理システムのリニューアルプロジェクトに初期から携わっていました。

こちらのプロジェクトにつきましては、弊社デザイナーの酒井がデザイナーがデザインツールを使わずに、Reactを使ってデザインした話を、弊社エンジニアの山田がGraphQL, TypeScript, Reactを用いて型安全に社内システムをリニューアルした話を以前ブログにしていますので、よろしければあわせてご覧ください。

その社内管理システムをどのような流れでリニューアルし、その中で自分の役割がどう変化しどう対応したのかなどについて、次の章からお話ししていきます。

プロジェクトについて

リニューアルの背景やシステムの概要については上に紹介した記事でも説明しているため割愛しますが、求職者や求人を掲載する顧客に関する業務を行っているシステムをおよそ1年半かけて刷新するという大きなプロジェクトでした。

システムの中でも求職者関連を「Phase1」、顧客関連を「Phase2」として分割し、リニューアルを進めました。

プロジェクト内での自分の役割の変遷

Phase1の最初期は先輩方がアーキテクチャの設計やスケジューリングをしていました。当時まだ新卒1年目で未熟な私でしたが、権限管理のテーブル設計をするタスクをアサインしてもらいました。ここでは詳細を省きますが、初めてのテーブル設計で右も左も分からない状態から責任感を持って何とか形にすることができ、(もちろんリニューアル中に多少の見直しはありましたが)大きな達成感を得たことを覚えています。

各種設計、技術選定、開発の進め方などが大方固まり本格的に開発が始まるわけですが、Phase1の際は先輩社員がプロジェクトリーダーとして引っ張っていただき、自分は開発メンバーの一員としてAPIの作成などに奮闘していました。

GraphQLといった技術やスケジュールが厳密に引かれたプロジェクトでの開発など初めて経験することも多々ありましたが、先輩方にサポートをいただいたり、同期と切磋琢磨しながら取り組めたおかげで、Phase1を乗り切ることができました。

さて、ここからが本題になりますが、Phase2になるとプロジェクトメンバーの入れ替えや私自身の目標設定も重なり、プロジェクトリーダーを任せてもらうことになります。まずはプロジェクトリーダーに任命されてから、どういった仕事をしていたのかご紹介します。

プロジェクトリーダーの仕事

プロジェクトリーダーとして期待されていたことは以下の通りです。

  • プロジェクト管理
  • システム設計
  • 開発
  • チームマネジメント

これを更に細分化し、私の実業務と照らし合わせながら並べてみると、多少粒度にばらつきがあるかもしれませんが以下のようなことが挙げられます。

  1. 要件定義・画面設計
    1. ディレクターとデザイナー主導で進めつつ、エンジニアも実データや既存ロジックを踏まえた観点を持ち合わせて参加しました
  2. 開発方針の検討
  3. 開発タスクへの落とし込み
  4. 技術調査・選定
  5. API設計
  6. 工数算出・スケジューリング
  7. 実装・レビュー
  8. QA(Quality Assurance)テスト
  9. リリースマネジメント

Phase2は段階的にリリースを行ったため、その度に1から9までを繰り返していたような流れになります。また、上記に加え、定例ミーティングでの報告や開発メンバーのタスクマネジメントも随時行っていました。

もちろん苦労したことは多く、全部を挙げようとするとキリがないのですが、その中でもいくつかに絞った上で紹介したいと思います。

苦労と工夫

1. 「そもそも何をやればいいのか」

まず最初に苦労したことは「そもそも何をやればいいのかわからない」ということでした。初めから先ほど挙げたような動きをイメージできていたわけではなく、記事や本を読み漁ったり先輩との1on1で質問攻めにしたりと基本的な知識を叩き込むわけですが、実際にとった最初の動きとしては「できる部分を見つけてやっていく」ということだったと思います。 自分がリーダーに任命された時点でのプロジェクトの状況としては要件定義や画面設計が進んでいる最中でしたが、これらがまとまるのを待つのではなく「全部決まらないとやれないこと」と「現時点でやれること」を切り分けて動きました。こうしたところから少しずつリズムを作り、最終的に先ほど列挙したような一通りのことがイメージ・実行できるようになったのだと思います。

2. 工数見積もり

一般的に工数見積もりに関する記事は世の中に多く存在しますが、私の場合は工数見積もりの方法がわからなかったというよりも、「どういう思想で見積もったのか、どういう選択肢があるのか」を曖昧にしていたことが当初の問題でした。

初めて見積もった時は単に開発タスクを積み上げた工数を報告して満足してしまいましたが、様々な方のフィードバックを受けプロダクト価値を高めるためにどういう動きができるのかを考える必要があったことを痛感しました。単純に工数を積み上げる場合や事業的な都合を踏まえてミニマムで開発する場合など、いくつかの選択肢をそれぞれの軸で考える必要があったことを学びました(この時期は夜な夜な夢の中で工数見積もりをしていたのも今ではいい思い出です)。

3. 意思決定

これはいつになっても正解が存在する類のものではないのですが、特に意思決定には苦労しました。意思決定といっても開発方針から技術選定まで様々な粒度のものがありますが、特に最初から苦労したのは技術的な決定でした。

それまで先輩に頼ることの多かった私がプロジェクトリーダーになった直後から何もかもできるようになるわけではないことは明々白々ですが、「自分が決めないと」と焦ってしまっていた時期もあったと思います。

そこで一度立ち止まって意識したことは、「何ができて何ができないのかを他者に明示する」ことでした。はっきりと自分に足りていないことを他者に伝えることで、周りもサポートしやすくなると思いますし、自分自身なにがやれることなのか明確になるので単純なことですが効果的であったと思います。他にも開発メンバーの提案で、インセプションデッキを取り入れてみたことも効果的でした。

また、意思決定とは文脈が少し変わってきますが、モブプロやペアプロを実施してチーム力を高め属人化をなくしつつ開発効率を向上させる取り組みも、時間が経てば経つほど効果を実感できて良かったと思います。このようにアジャイル開発の手法からチームにフィットする手法をいくつか取り入れることもできました。

プロジェクトを通して成長したこと

これまで小出しで色々とお話しさせていただきましたが、自分が特に成長したと感じていることをまとめさせていただきます。

一通りの経験を通して得られたリード力

API設計だけ」ではなく一通り全てを任せていただいたことはとても大きな経験になりました。初めて個人ではなくチーム・プロジェクト全体として効率が良くなる動きを考える経験もできたと思います。

技術力

もちろん実装を通じて得た技術は数えきれないほどありますが、その中でも特に責任を持って他者のコードをレビューしたり、自分が書くコードの影響範囲やスコープを意識し続けたことが大きな糧になっている気がします。

リスク管理

スケジュール遅延のリスク、方向性がずれてしまうリスク、技術的なリスク、様々ありますがこれらのリスクヘッジを考える力がプロジェクトリーダーには必要です。

リスク管理において「先読みが大切」とよく言われますが、私の場合はある先輩社員から「常に2週間先を見据えておけ」という具体的な日数のアドバイスをいただきました。具体的にすることであらゆることが想像しやすくなりましたし、それを1年以上毎日意識し実行し続けたことが、プロジェクトをやり切ることができた要因にもなっていると思います。もちろんこの言葉は家宝にしようと思っています。

価値に対する視野

何よりも「プロダクトのユーザーに価値を提供すること」の意味を理解しました。ここまでに書いてきたようなスケジュール管理やリスク管理などは、あくまでプロジェクトを遂行する上で必要な仕事の一つでしかないはずです。プロジェクトを通してシステムを使っている社員、更にはその先の顧客・求職者へ如何に価値を提供できるか考えるべきですが、一時期は「どうやるのか・なにをやるのか」というプロジェクト自体を完遂させることしか考えられていない時期もありました。

視野が狭くなっていたことに周りからの指摘で気づくことができ、それ以降は「そもそも本当にこの機能はいるのか」などユーザーの立場からの観点も徐々に身に付けることができました。これがきっかけとなり、周りとも頻繁に「なぜやるのか」を議論できるようになったと思います。新卒1年目で口酸っぱく言われていた「目的意識」をようやく腹落ちさせ体現することができました。

最後に

最後となりますが、プロジェクトリーダーについて語ってきた私ですが、入社するまではWeb開発未経験でして、メドレーでの成長を非常に実感しています。そんなメドレーではエンジニア・デザイナーをはじめ多くのポジションで新たなメンバーを募集していますので、少しでもご興味をお持ちいただけた方は、是非お気軽にお話しさせていただければと思います!

ここまでお付き合いいただき、ありがとうございました。

www.medley.jp

オンライン診察機能に画面共有を実装した話

事業本部 プロダクト開発室エンジニアの日下です。

オンライン診療・服薬指導・クラウド診療支援システム「CLINICS」の、患者・医療機関に向けたアプリケーションの機能開発、開発基盤、インフラ周りを担当しております。

今回 CLINICS が提供するオンライン診療機能に「画面共有機能」を追加しましたので、その背景・技術的な話をまとめます。

画面共有機能実装の背景

CLINICS とオンライン診療

普段皆さんが病院にかかるとき、多くの場合は病院に行き、医師の診察を対面で受け、会計をして帰るといった流れになるかと思います。

CLINICS のオンライン診療はこの流れをインターネットを通して提供するサービスです。

※ オンライン診療は、一度、初診等で対面診療を受けた際に医師が可能と判断した場合、次回以降の診察において可能になります。また、現在は新型コロナウイルス感染症対策時限措置として、初診からオンライン診療を受けることが可能となっています。

CLINICS を利用した場合、事前に予約した時間にスマホまたは PC で待機をする、医師の診察をビデオチャットで受け、会計はクレジットカードで行われるという流れとなっています。

クラウド診療支援システムとしての CLINICS は 2016 年に「オンライン診療のためのシステム」としてローンチされ、2018 年にはクラウド型電子カルテ機能を2019 年には予約管理システム機能を2020 年にはかかりつけ薬局支援システム Pharms との連携機能も追加し、患者向けアプリからオンライン服薬指導をシームレスに受けることができるようになりました。

プロダクト開発室ではこれらオンライン診療機能・電子カルテ機能・予約管理機能・連携機能の改善を日々行っています。

画面共有機能の需要の高まり、実装の決定

このように CLINICS の改善を日々行なっている中、昨年から始まった新型コロナウイルス感染症(COVID-19)の流行に伴った需要の増加により、オンライン診療の件数が急増しました。

CLINICS も数多くの医療機関にご利用いただく中で、オンライン診療に関わるさまざまなご要望をいただくようになりました。その中でも特に多かったものが、今回紹介する画面共有機能です。

対面での診察の際に医師が検査結果などを患者に見せながら説明するように、オンラインで診察する場合でも資料をリアルタイムで共有しながら説明ができるようになれば、今まで以上にオンラインでも質の高い診察を行えるようになります。

こういったユースケース、要望などを検討した結果、CLINICS を利用するすべての医療機関及び患者にとって大きな恩恵が見込まれたため、オンライン診察(ビデオチャット)中に医師の PC 画面をリアルタイムで患者に共有する機能として実装をすることにしました。

f:id:medley_inc:20210729115806p:plain

画面共有機能の実装

画面共有をする医師側向けのコードでどういった実装方法があるのか、大まかな流れをまとめます。

※ 以下に記載しているコードは説明のための疑似コードですので、このままでは動作しないことにご注意ください。また、医師側の実装例を掲載しているため、患者側(画面共有を受ける側)の実装は別途必要になります。

オンライン診察開始までの処理

オンライン診察を開始するには医師側のマイクとカメラで取得した情報を患者側に送付する必要があります。ここではそこまでの実装の流れを見ていきます。

カメラ・マイクのストリームの取得

オンライン診察開始時点で医師側のマイク・カメラの情報を共有するため、まずはそれらのストリームを取得する必要があります。こういったメディアコンテンツのストリームを司るインターフェイスとして MediaStream が定義されています。

マイク・カメラの MediaStream は、例えば MediaDevices.getUserMedia() を利用して取得できます。

const userMediaStream: MediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });

SkyWay 経由でオンライン診察を始める

WebRTC で P2Pビデオチャットを利用するためには、初期の接続のための処理及び接続の維持などの処理を行う必要があります。弊社ではこのあたりの処理を WebRTC SaaSSkyWay 及びその SDK を利用することで簡略化しています。

オンライン診察開始時には、先程取得した医師側のマイク・カメラの MediaStream を SkyWay の SDK に渡すことで、一対一でのリアルタイムビデオチャットを実現できます。

import Peer, { MediaConnection } from "skyway-js";

const peer = new Peer({ key: "your-api-key" });

// 事前に患者と共有しておいたpeer idに対してcallメソッドとMediaStreamを渡すことで診察を開始できる。
const mediaConnection: MediaConnection = peer.call("shared-peer-id", userMediaStream);

// 注: 患者側は送付された処理をハンドリングする機能を実装する必要がある

ここまでがオンライン診察を開始するまでの処理です。

※ 詳細は SkyWay 公式のチュートリアルなどを参照ください。

画面共有の処理

ここまでで患者に対して医師側のカメラ・マイクで取得された映像・音声が表示されている状態のため、これを切り替える処理が必要になります。今回は現在接続に利用している MediaStream を、画面共有用の MediaStream に入れ替えることで実現しました。

画面の MediaStream の取得

まずは共有する画面の MediaStream を取得する必要があります。これは MediaDevices.getDisplayMedia() を使うことで実現できます。

const displayStream: MediaStream = await navigator.mediaDevices.getDisplayMedia({ video: true });

画面共有用の MediaStream を作る

getDisplayMedia() から共有する画面の MediaStream を取得できるものの、そのまま利用するとマイクの音声が入りません。

これは getDisplayMedia() から取れる MediaStream にマイクの音声が含まれていないことが原因なので、必要な画像・音声の組み合わせを持った画面共有用の MediaStream を作成することで対処ができます。

MediaStreamTrack を組みあわせて画面共有用の MediaStream を作る

画面共有用の MediaStream を作成する前にまず、MediaStreamTrack と MediaStream の関係を理解する必要があります。

MediaStreamTrack はストリームに含まれる一つのメディアトラックを表現するものです。 kind という読み取り専用プロパティがあり、オーディオトラックであれば "audio" が、ビデオトラックであれば "video" が設定されています。

また、 MediaStream は複数の MediaStreamTrack から成り、オーディオトラック・ビデオトラックを取り出すメソッドがそれぞれ MediaStream.getAudioTracks()MediaStream.getVideoTracks() として実装されています。

これらを組み合わせることで、マイクと画面の MediaStreamTrack を持つ MediaStream を作ることができ、これを SkyWay の SDK に渡すことで、画面共有を実現できます。

const [displayVideoTrack]: MediaStreamTrack[] = displayStream.getVideoTracks();
// 画面共有の音声はマイクの音声を利用したいので、userMediaStreamからaudioTrackを取り出しておく
const [userAudioTrack]: MediaStreamTrack[] = userMediaStream.getAudioTracks();

// 画面共有するためのMediaStreamを作成する(画面のvideoTrack、マイクのaudioTrackを持つMediaStreamを作る)
const sharingMediaStream: MediaStream = new MediaStream([displayVideoTrack, userAudioTrack]);

MediaStream の入れ替え

最後に画面共有状態への切り替えです。マイク・カメラが共有されている状態からの切り替えにはいくつかの方法が考えられます。

例えば、多重化であれば MediaConnection( Skyway の SDK の単位で、「接続先 Peer へのメディアチャネル接続」を管理する)の多重化、MediaStream の多重化、MediaStreamTrack の多重化がそれぞれ考えられます。これらの方法はマイク・カメラの切り替え時のチラつき抑制など実装上の選択肢が増えるメリットがある一方で、通信量が多くなってしまう点がデメリットと言えます。

今回は多重化をせずに既存の MediaStream を切り替える実装を紹介します。この方法のメリットは、多重化に比べると通信量が少なく、またすでに MediaStream が一つである前提で作られている場合は、画面共有を受ける側の実装の変更が不要という点です。

この方法は、 SkyWay の SDK であれば MediaConnection の replaceStream というメソッドに対して新しい MediaStream を渡すことで実現ができます。

// 画面共有用のMediaStreamを渡すことで、画面共有を開始する
// MediaConnection は先程 `peer.call` した際の返り値として取れているため、それを利用する
mediaConnection.replaceStream(sharingMediaStream);

実装前に懸念していたマイク・カメラの切り替え時のチラつきなども気になるほどはなく、実用に足るような品質を保つことができることを確認しています。

実装の全体概要

以上の流れを実装すると、次のようなコードになります。

import Peer, { MediaConnection } from "skyway-js";

/** 医師側のマイク・カメラを共有してオンライン診察開始するところまで **/
// getUserMedia()でカメラ・マイクのストリームを取得
const userMediaStream: MediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });

// Skyway sdkの初期化処理
const peer = new Peer({ key: "your-api-key" });

// オンライン診察の開始
const mediaConnection: MediaConnection = peer.call("peerId", userMediaStream);

/** 画面共有を開始する処理 **/
// 画面共有する画面のstreamを取る
const displayStream: MediaStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const [displayVideoTrack]: MediaStreamTrack[] = displayStream.getVideoTracks();

// 画面共有の音声はマイクの音声を利用したいので、userMediaStreamからaudioTrackを取り出しておく
const [userAudioTrack]: MediaStreamTrack[] = userMediaStream.getAudioTracks();

// 画面共有するためのMediaStreamを作成する(画面のvideoTrack、マイクのaudioTrackを持つMediaStreamを作る)
const sharingStream: MediaStream = new MediaStream([displayVideoTrack, userAudioTrack]);

// 画面共有用のMediaStreamを渡すことで、画面共有を開始する
mediaConnection.replaceStream(sharingStream);

開発中に遭遇した問題への対応

スリープモード・共有を停止ボタンを押したときの対応

Google Chrome で画面共有の際に表示される「共有を停止」ボタンを押下したり、PC をスリープモードにすると、画面の MediaStreamTrack が途切れてしまいます。

これは該当の MediaStreamTrack に "ended" のイベントリスナを登録しておくことでハンドリングできます。

displayVideoTrack.addEventListener("ended", handleEndedEvent, { once: true });

TypeScript の型の対応

現状 TypeScript の型が getDisplayMedia() に対応していなかったため、今回は実装の参考にしている skyway-conf で利用されている型を流用する形で対応をしました。

declare global {
    interface MediaDevices {
        getDisplayMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
    }
}

これは根本的には TypeScript の dom.d.ts に型定義が入っていないことが起因していますが、TypeScript4.4 で対応がされるようです

まとめ

昨今の状況により、オンライン診察のニーズが高まり、画面共有機能の重要性が高まりました。 診察中の画面共有機能は以下の api を組み合わせることで実現することができます。

  • PC 画面の MediaStream は getDisplayMedia() を使うことで取得
  • MediaStream に含める音声・画像ストリームを変更したい場合は MediaStreamTrack の組み合わせを変えることで作成
  • 接続中の MediaStream の変更は SkyWay の SDKMediaConnection.replaceStream() を使う

最後に

CLINICS では本稿で紹介した画面共有などの新規機能の導入や日々の改善を通じて、医療機関・患者双方に支持されるプロダクトを目指し開発を行っています。興味を持たれたエンジニアの方がいらっしゃいましたらぜひこちらにご連絡いただければと思います。

www.medley.jp

「ChatOps稟議」×「電子契約締結のAPI連携」でワークフローの生産性を追求した話

はじめに

はじめまして、コーポレートエンジニアの山下です。

2020年にSlackを活用したChatOps稟議ワークフローを内製で開発したのですが、さらに、2021年4月にこのSlack稟議と電子契約システムであるクラウドサインを連携させて、電子契約をもっと便利に使い、生産性の向上を実現しましたのでお話しいたします。

まず、当社の稟議システムは2020年12月の当社の記事のおさらいになりますが、稟議の作業がSlack上で完結する、ChatOpsによる稟議ワークフローとなっております。本稿については2021年7月に執筆しておりますので丁度導入から1年程経過し、その間大きなトラブルも無く、今も当社の極めて迅速な意思決定の一助になっています。ChatOpsによる稟議ワークフローについては、直近、2021年6月にLayerX社がLayerXワークフローの新機能として発表し、サービスとしても提供され、日経新聞でも取り上げられていることから、今現在のパラダイムとして、先進的で有効な一手法であったと再認識しております。

今回、新型コロナウイルス感染拡大防止に伴うリモートワークの加速という状況もあり、当社で2021年4月に電子契約システムとしてクラウドサインを導入しました。電子契約に限らず、契約押印作業は稟議の後続作業に当たるため、ただ導入して使用するのみならず、クラウドサインのAPIを利用して稟議上にあるデータを電子契約に送信させることでシームレスな連携を実現しています。本稿では当社が行ったシームレスな連携手法について詳細をご説明いたします。

TeamSpiritとクラウドサインのAPI連携について

実装概要

弊社の稟議システムであるTeamSpiritクラウドサインとの連携についてお話しします。まず、本稿の開発部分とシステム構成は下記になっております。

f:id:medley_inc:20210715210552p:plain

処理内容の詳細は後ほど述べますが、概要としてはTeamSprit(Apex)からクラウドサインのAPIをコールし、クラウドサイン上で作成した契約文書へ稟議に記載されている契約書ファイルや先方担当者等の情報を連携する仕組みとなっております。これにより契約担当者はクラウドサインにログイン後、下記の3ステップで先方に送信できるようになっています。

  1. 記載内容の確認
  2. 押印・署名箇所の設定
  3. 先方への送信

クラウドサインを使用して契約文書を一から作成する場合のユーザ作業と、当社で採用したAPI連携行った場合のユーザ作業を比較したものが下記の表です。作業が半分程度削減されたことが分かります。

作業項番 一から作成する場合 API連携を利用した当社の場合
1 ログイン ログイン
2 契約文書の作成(件名、契約文書としての宛名設定等) なし
3 契約書ファイルのアップロード なし
4 先方の送信先設定 なし
5 押印欄の設定 押印欄の設定
6 先方への送信 先方への送信

実装

今回の開発で使用したクラウドサインAPIは下記の5つのAPIを使用しました (※以降、クラウドサインAPIに倣い、変数を表現する場合は{}で括ります)。

API種類 使用用途
post /token アクセストークンの取得
post /document 契約文書の作成
put /documents/{documentID}/attribute 契約文書の作成で設定できない、細かい項目の設定
post /documents/{documentID}/files ファイルのアップロード
post /documents/{documentID}/participants 先方の送信先設定

全体像で記載したクラウドサインの連携部について、上記のAPIを織り交ぜて詳細化すると下図のようになります。

f:id:medley_inc:20210715210621p:plain

実装方法としてはクラウドサインAPIのリファレンスを参照し、テスト実行時に出力されるcurlコマンドを参考に同様のレスポンスを得るようにApexでHTTPリクエストを実装しました。アクセストークンの取得を例にとると下記のようになります。

APIリファレンスでのcurlコマンド例

curl -X 'POST' \
'https://api.cloudsign.jp/token' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=xxxxxxyyyyyyzzzzzz'

Apexでのリクエスト実装例

HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://api.cloudsign.jp/token');
req.setHeader('accept', 'application/json');
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setBody('client_id=' + 'xxxxxxyyyyyyzzzzzz');

私自身、ApexもクラウドサインAPIもこの案件を担当するまで触ったことがありませんでしたが、リクエストの試行から実装まで2週間かからない程度で実装することができました。

ただし、実装や運用にあたっては下記2点について注意が必要になります。

  1. Apexからクラウドサインへのファイルのアップロードは単純ではない
  2. アクセストークンの有効期限はクラウドサインでコントロールされる

1. Apexからクラウドサインへのファイルのアップロードは単純ではない

ファイルのアップロードについては今回使用したAPIの中で、唯一、テスト実行のcurlとApexのリクエスト実装で差分が生まれます。まず、その差分を確認するためにcurlコマンド例とApexのリクエスト実装例でheader、bodyにセットしている値を比較してみます。

APIリファレンスでのcurlコマンド例

curl -X 'POST' \
'https://api.cloudsign.jp/documents/{document_id}/files' \
-H 'accept: application/json' \
-H 'Authorization: AAAAAABBBBBBCCCCCC' \
-H 'Content-Type: multipart/form-data' \
-F 'name=テスト' \
-F 'uploadfile=@テスト.pdf;type=application/pdf'

Apexでのリクエスト実装例

HttpRequest req = new HttpRequest();
req.setMethod('POST');
     req.setEndpoint('https://api.cloudsign.jp/documents/{document_id}/files');
req.setHeader('accept', 'application/json');
req.setHeader('Authorization', ‘AAAAAABBBBBBCCCCCC’);
req.setHeader('Content-Type', 'multipart/form-data; boundary={boundary}');  // ※1
req.setBodyAsBlob({multipartBody});  // ※2

主な違いは ※1, ※2 とコメントした部分になります。

ApexではHTTPリクエストの値を手で書いていくことになるので、テスト実行例のようにcurlがよしなに処理している部分(-Fオプションの部分やApexで記載しているboundary)も実装しなければなりません。これが単純に実装できない理由になります。

boundaryについてはmultipart/form-dataを送信する際に必要な境界でヘッダーでどの文字列が境界であるかを設定します。curlの-Fオプションで定義していた文字列とファイル指定部分は、Apexでファイル(バイナリ)を扱うため、そのbodyに含まれる文字列も含めてBlob型で扱う必要があります(Content-Transfer-Encoding: base64API提供側が対応している場合は例外になります)。そのため、文字列とバイナリデータを結合し一つのBlobにする方法は下記になります。

  1. 「バイナリデータ」、「bodyの開始からバイナリデータまでの文字列」、「バイナリデータ以降から終端までの文字列」の3グループに分ける。
  2. 3グループをそれぞれBase64で符号化する。
  3. 符号化した「バイナリデータ」と「bodyの開始からバイナリデータまでの文字列」について、Base64のデータパディングを示す”=”が含まれないように改行コードで調整する。
  4. 「bodyの開始からバイナリデータまでの文字列」、「バイナリデータ」、「バイナリデータ以降から終端までの文字列」の順で結合する。
  5. 結合したBase64のデータを復号して、一つのBlobとする。

2. アクセストークンの有効期限はクラウドサインでコントロールされる

アクセストークンやその有効期限はtoken APIを発行した際のレスポンスとしてクラウドサインから発行されます。

発行されたレスポンス例

{
     "access_token": "AAAAAABBBBBBCCCCCC",
     "token_type": “xxxx”,
     "expires_in": 3600
}

このレスポンスの内、expires_inの値がトークンの有効期限になります。掲題の通り、有効期限の管理はクラウドサイン側で行われ、有効期限内に再度トークンのリクエストを行った場合、経過した時間だけexpires_inの値が小さくなった結果が返ってきて、access_tokenなどは同じ値が取得されます。有効期限内にtoken APIを再度実行した結果が下記になります。

有効期限切れ前にtoken APIを発行した際のレスポンス例

{
     "access_token": "AAAAAABBBBBBCCCCCC",
     "token_type": “xxxx”,
     "expires_in": 762
}

一方、有効期限後にトークンのリクエストを実行すると、それまでと異なるアクセストークンを取得し、新しい有効期限が設定されます。

有効期限切れ後にtoken APIを発行した際のレスポンス例

{
     "access_token": "XXXXXXYYYYYYZZZZZZ",
     "token_type": "xxxx",
     "expires_in": 3600
}

そのため、API連携が一度動いた後、有効期限ぎりぎりでもう一度API連携が動いてしまった場合、タイミングが悪いと契約文書の作成から最終処理である先方の送信先設定までのプロセス内のどこかから、トークンの有効期限切れが発生する可能性が想定されます。実際に期限切れが発生した場合、発生時以降に発行したその回のAPI連携処理が失敗します。

トークンの有効期限切れが発生した際、APIリファレンスよりHTTPステータスコードが401かつエラー内容が”unauthorized”で応答されることから、当社ではこのエラーを受けた場合にトークンを再取得して処理をリトライするように実装しました。

押印文書作成を例にとると下記のような実装イメージになります。

//クラウドサイン上に押印文書を作成し、作成した文書IDを取得する
public String getDocumentId(String authToken, String title, String message){

    ・・・中略・・・

    HTTPResponse res = http.send(req);

    if (res.getStatusCode() == 200){
        ・・・正常に終了した際の処理・・・
    }
  
    //タイミングが悪くtokenがタイムアウトした場合、トークンを取得し直して、リトライする
    else if (res.getStatusCode() == 401){
        //レスポンスの内容を確認するため、エラーレスポンスの中身を取得する
        Map<String, Object> responseBody = new Map<String, Object>();
        responseBody = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
        String errorVal = (String)responseBody.get('error');

        //リファレンス上、アクセストークンが無効(有効期限切れ)の場合、'unauthorized’となる
        if (errorVal.equals('unauthorized')){
            //クラウドサインのアクセストークンの再取得
            authToken = getAuthToken();
            //単純再帰で再実行する。
            documentId = getDocumentId(authToken, title, message);
        }
        ・・・中略・・・
    }
    ・・・以下省略・・・
}

実装を終えて

上記を実装した結果、稟議と入力内容が同じ、または、稟議から生成できる内容は全てシステム連携で自動生成するため、押印担当は稟議とクラウドサインの画面を並べて転記するような煩雑な作業を必要としない環境になりました。また、契約書の製本、郵送等の紙媒体であるが故の事務の削減ができるようになる等の、電子契約を導入することのそもそものメリットも併せて享受しています。

当社では2021年4月後半からクラウドサインを導入しましたが、2021年6月時点ではすでに月間で締結した契約書の「3割以上」が電子契約を活用しており、押印担当の展望として今後も利用を拡大していく予定です。

コーポレートエンジニア募集中

メドレーのコーポレート部門では、本稿のように、SaaSの導入ひとつとっても検討を尽くし、既存のシステムと有機的に結合させることで「徹底的に合理性を追求した組織基盤や、仕掛けづくり」を行っています。

面白そう!興味がある!と感じた方は、ぜひ当社採用ページからご応募お願いします!

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

www.medley.jp

Pharmsのブランドルーツを辿る

「2020年9月に調剤薬局向けのプロダクトをリリースする」

このプレスリリースが発表されたのは、COVID-19の感染拡大に端を発する緊急事態宣言が発令されていた2020年4月半ば。その1ヶ月後、私はリモートワーク下でのオンラインMTGになじめない状態のまま、調剤薬局向けプロダクトのブランディングについて役員陣や主要プロジェクトメンバーにプレゼンを行っていた。

今回は当時のプレゼン資料をたどりながらPharmsのブランド設計について説明していこうと思う。

医薬分業のルーツとは

デザイナーとして前田がメドレーに入社してから、オンライン診療や電子カルテなど、主に医療機関向けのプロダクトデザインを担当していたものの、調剤薬局のプロダクトデザインは未知の領域。ブランディングを検討する上で、薬の処方を行う医師と調剤を実施する薬剤師が分担して行う医薬分業のルーツついて調べることからはじめた。

医薬分業は、毒殺を恐れたフリードリヒ2世が主治医の処方した薬を、毒が盛られてないか他者にチェックさせたのが始まりとされている。

(参考:公益社団法人 日本薬剤師会HP|医薬分業とは

f:id:medley_inc:20210625142428p:plain

医療プラットフォームの未来を見据えたブランド定義

次に、調剤に関する法制度や競合などの外部要因、メドレーとしてのブランド力や開発力などの内部要因について簡易なSWOT分析を行い、調剤薬局のプロジェクトの妥当性を検証。メドレーが取り組む医療プラットフォーム事業(※)に、あらたに調剤薬局プロジェクトが加わることによる他のプロダクトとのバランスも考慮しながらブランドネーミング検討を行っていった。

f:id:medley_inc:20210625142452p:plain

※) 医療プラットフォーム事業では、患者と医療領域の業務システムをSaaSプロダクトでつなぎ、患者と医療機関双方にとって、テクノロジーの恩恵を受けることのできるプラットフォームづくりを行っている。主要サービスはクラウド診療支援システム「CLINICS」やオンライン診療・服薬指導アプリ「CLINICS」。

メドレーのこれまでの歴史を振り返ると、プロダクト内容を明確かつ端的に表したネーミングが多く、メドレーらしさ = 「中央突破なネーミング」ということを定義し、ネーミングを検討していった。

f:id:medley_inc:20210625142510p:plain

最終的に調剤薬局を表す「Pharmacies(ファーマシーズ)」と「Pharms(ファームス)」の2案に絞込み、それぞれのメリット・デメリットを整理していった。

f:id:medley_inc:20210625142528p:plain

当時、社内では調剤薬局システム = Pharmaciesと呼ばれており、その中央突破なネーミングが最有力候補であった。一方で、ブランドで体現すべきアイデンティティの欠如や、呼びづらさなどが課題として散見された。さらには医療プラットフォーム全体を見据えたブランド構築という観点から考慮すると、バランス面での課題が浮き彫りになり、それら課題をクリアにして誕生したのがPharms(ファームス)である。

ヴィジュアル・アイデンティティの設計

ブランド名が固まれば、あとはヴィジュアル・アイデンティティを突き詰めていくのみ。視認性や可読性を考慮したフォントフェイスの検証や調剤薬局と想起させるブランドカラーの選定、またシンボルの設計などに取り掛かっていく。

ブランドカラーの選定においては、なんとなく「緑」というイメージがチーム内でもあったが、より精緻化するため、薬の起源や調剤薬局本来の役割を踏まえ詳細に落とし込んでいった。

f:id:medley_inc:20210625142546p:plain

ロゴにシンボルを含めるか、含めないかも検討のひとつであったが、医療プラットフォーム事業にあるCLINICSのロゴがシンボルマーク付きであるため、医療プラットフォームに関連するプロダクト = シンボルを定義するというルールを策定しシンボルも設計。シンボルは薬の構造式に利用される「ハニカム構造」をモチーフとし、ブランドカラーと合わせて詳細に作り込んでいった。

f:id:medley_inc:20210625142603p:plain

また、Pharmsの製品紹介用ランディングページやプロダクトデザインのモックアップを作成し、ロゴとのバランスなども考慮しながら調整を行っていった。

f:id:medley_inc:20210625142619p:plain

最終的に、患者・調剤薬局医療機関の3者のつながりを三角形で表現しつつ、中心を先述した「ハニカム構造」をモチーフとした形状と、Pharmsの頭文字「P」をカプセルと錠剤で表現して、調剤薬局システムとしてシンボルマークに命を吹き込んだ。

f:id:medley_inc:20210625142638p:plain

まとめ

このような過程を経て、Pharmsのブランドが完成したのだが、これらは調剤薬局システムの開発としては氷山の一角でしかない。本丸はプロダクトデザイン。一般的にはロゴとプロダクトデザインは別プロジェクトで進行したり、担当するデザイナーが別だったりすることも多いのではないだろうか。

Pharmsはブランド設計、プロダクトデザイン、マーケティング資材といったデザイン領域をすべて私が担当していくことになるのだが、それ故に事業全体を俯瞰し理解しながらデザインやUIデザインに魂を込めて携わることができた。デザイナーキャリアとしてもここまで幅広く携われたことは非常に貴重な経験を得ることができたと自負している。

続いてプロダクトデザイン開発の秘話について語りたいところだが、現在Pharms以外の医療プラットフォーム事業に関連する新たなプロダクト開発に注力しているため、その話はまたの機会に。


医療プラットフォーム事業に関連するプロダクトをこれからも創出し成長させていく面白い時期にあり、現在デザイナーを積極採用中です。カジュアルに話を聞きたい、医療領域のデザインに興味があるといったデザイナーの方は、ぜひこちらまでご連絡いただけると幸いです。

www.medley.jp