株式会社ヘンリー エンジニアブログ

株式会社ヘンリーのエンジニアが技術情報を発信します

わけのわからないバグに遭遇したときの生き抜き方

株式会社ヘンリーで医療会計部のエンジニアの一條(GitHub: @rerost , X: @hazumirr)です。

これはHenryアドベントカレンダー 2025 シリーズ 1 における7日目の投稿です。昨日の記事は スタートアップで経営を執行から引き剥がした10ヶ月間 でした。

僕は今まで、

  • 複雑な診療報酬をちょっとずつ理解しながらの開発
  • インシデント時のコマンダー
  • ロジックが複雑かつ機械学習を入れた検索システムの構築(前職)

といったことをしていました。 なので、わけのわからないバグに遭遇する機会は多い方だったと思います。 この経験の中で僕が実践していたことについて書きます。

目次

バグ自体の分類

割とここが肝だと思っていて、バグ自体が分類できたら対応の9割は終わったと言っても過言ではないと思います。 僕は、発生源・影響度の二軸で考えています。

緊急度

緊急度はバグ対応中にかなり早くに明確にしておくと対応がスムーズです。

  1. リリース済み機能でユーザーの行動がブロックされることがあり、即座に対応しなければいけない
  2. リリース済み機能でユーザーでの回避策などがあるが、早めに直さないとユーザーに手間を取らせてしまう
  3. 未リリースなどでユーザーに影響しない

1なら、まずは回避策を練るか一次対応するなどで根本対応より先にでること。対応へのリードタイムを減らすためにも、人を集めましょう。 2なら、落ち着いて原因を探りつつ、ユーザーへの案内などを速やかに行いましょう。 3なら、ゆっくり調べましょう。

といった具合です。

バグの発生源の種別

発生源は多くの場合、以下のどれかに分類されるかと思います。

  • 実装のみからくるもの。例: 外部ライブラリの使い方やアップグレードなど
  • 現状動いているものと、以下のどれかとのズレ
    • 過去の仕様
    • 関連するルールや法律など
      • 例: 診療報酬制度

2つ目の部分の説明をしていくと、まず具体例としては以下があります。

発生源
過去の仕様 昨日まで検索でヒットしていたものがヒットしなくなった。
先月まで自動で入力されていた部分が入力されなくなった。
関連するルールや法律など XXを算定すると、自動でYYも算定されるはずだが、算定されない。

このどちらかが、実装とズレていることでバグは発生します。

実装とどれかが異なるか

更にたどると、実装者がどれとズレているか、実装者の意図しない実装になっているのか、もしくは実装者自身が過去仕様・関連するルールの理解がズレているかがあります。

実装者と何がズレているか

これらの要因は、実装者のバグが入ったPRの文章やバグを報告してくれた方に話を聞いていくことで多くの場合は特定できるかと思います。

対応の流れ

  1. 再現する
    1. 手元環境で再現する
    2. 具体のバグ発生パターンをいくつか集める
  2. 原因を特定する
    • 状況を言葉にし、まとめる
    • 関連するものを図に起こす
    • 発生しないという主張・発生するかもしれないという主張、を交互に繰り返し出し続ける
  3. 修正する

再現する

手元で環境構築などをし、報告されたスクリーンショットや報告内容から同じ状況を再現し、試しましょう。

うまく再現できない場合、弊社の開発する電子カルテ・レセコンだと、医療機関の設定や患者の状態(過去の操作)が影響するので、以下を確認するのが良いです。

  • 医療機関設定
    • 病棟・病床の設定
    • 都道府県
    • 連携する検査機関の設定
    • 機能の有効無効
    • etc...
  • 患者の状況
    • 過去算定されたもの(※ 制度上、過去の会計データに依存するロジックなどがある)
    • 保険
    • etc...

また、報告されたケースと類似のバグが再現するケースを集めておくと、修正時のチェックで役に立つのでおすすめです。

原因を特定する

原因の特定ですが、まずはここまで得られた情報を元に、特定していきましょう。 無論、ここまで集まった情報で原因特定が済んでいるのであれば、スキップしましょう。

コードなどを読みながら、状況を言葉や図にしてまとめていくのが肝で、わけがわからない状況のとき、言葉や図にしておくことで頭で抱え続ける情報を減らすことができます。

また、自身で

  • このバグは発生しない。なぜなら〜、と主張をする
  • このバグは発生する。なぜなら〜、と主張をする

を繰り返していくこともおすすめです。

例えば、昨日まで検索でヒットしていたものがヒットしなくなった場合だと、

  • このバグは発生しない。なぜなら検索対象のデータは昨日と変化しておらず状況が変わらない
  • このバグは発生する。なぜなら検索対象のデータは先程の調査で確認した部分以外も対象だからだ
  • ....

みたいな形で進めて行くと、仮説を立てながら調査していくのがスムーズにできるし、見落としが減ります。

修正する

修正の際、考慮する必要があるのは、

  • 二次被害を産まないか?
  • 十分な対応か?

です。

例えば、ブログが昨日まで検索でヒットしていたものがヒットしなくなった場合には、直したが、下書き状態のブログまで検索の対象になってしまう、だと二次被害を産んでしまっています。

また、十分な対応か?で言えば、検索でヒットしないが問題なので、それ以外の要因でもヒットしなくなっていないか?は確認する必要があります。

特に、わけのわからないバグに遭遇した場合、こういったリスクがあるので注意する必要があります。

最後に

このあたりの話をもっと知りたい方や、ヘンリー全体のこと、などを知りたい方はぜひ一度カジュアル面談しましょう!

hrmos.co

スタートアップで経営を執行から引き剥がした10ヶ月間

株式会社ヘンリーでVPoEを務めている戸田id:eller)と申します。これはHenryアドベントカレンダー 2025 シリーズ 1における6日目の投稿です。昨日の記事は kobayangデザインシステムライブラリを実装するためのテクニック でした。

本日は弊社で経営と執行を分離するためにどう権限委譲を進めてきたかをご紹介したいと思います。スタートアップのVPoEって何をやってるんだろう、という疑問にお答えできれば幸いです。

目次

解きたい課題

この6月に「ヘンリーで初めて製品部室長合宿をしました」で触れたように、弊社では長らくCEOである逆瀬川がエンジニアリングチームのマネジメントを兼務していました。2024年末に組織再編を行い部長・室長・本部長などのポジションが明確になりましたが、その後も逆瀬川が部長を兼務していた状態でした。

図1 電子カルテや医事会計などの開発を逆瀬川が直接見ていた

この状態には多くの利点があります。逆瀬川はお客様のペインも業界の課題も頭に入っていますし、サービスを黎明期から見てきているので深く理解しています。またヘンリーを起業してまで解決しようとする社会問題へのハングリー精神を持っていますので、常に学んでおり顧客と十二分に会話できます。さらにデザイナーやPdMとしての経験もお持ちですから要点を抑えたマネジメントを行えますし、様々な複雑さを巻き取ってITエンジニアを製品実装に注力させることもできます。こうした多くの利点があるからこそ、逆瀬川が部長を兼務することに対して慣性が働いてきました。

しかし組織が大きくなってくると、利点以上に課題が目立つようになってきます。事業戦略上エンジニアリングチームを増やすことの必要性は以前から明らかでしたが、1人で2つ3つとチームをマネジメントすることには限界があります。また事業戦略を考える人と部長が同一人物であるために事業戦略を部長に説明するというプロセスが省略された結果、トップダウンとボトムアップをすり合わせる機会が失われました。このすり合わせこそが組織としてSECIを回し学ぶ機会を生み出すことが「知識想像企業」に書かれていますが、これが行われなかったわけです。結果としてチームで「なぜこれを優先するかがわからないが、責任を取る人が言うんだし問題ないのだろう」「この壮大な計画をどう実現するのかイメージ湧かないけど、きっとやらないとまずいんだろう」のような忖度が働くなどして、早い段階でリスクを洗い出す機会が失われたと考えています。

何よりもCEOという会社のトップが、最もすべき「意思決定」に時間を使えていないこと が課題です。製品の実装が事業における最重要課題であることを踏まえると確かにエンジニアリングチームのマネジメントも大切です。しかしそれらは信頼できる人に任せて、もっとCEOがやるべきことに注力できる環境が必要だと考えました。

何がブロッカーだったのか

弊社は「理想駆動」を基本原則としており、共感を呼ぶ理想を描いて人を巻き込む「燃える理想」や自ら手を挙げて成果を作りに行く「自分起点」を行動規範に掲げている会社です。なので実現するべき理想が明確であれば、周囲の理解や協力は得やすい環境にあります。それでもこの慣性に抗うことは難しかったわけですが、何がブロッカーだったのでしょうか。

ひとつは弊社が扱うドメインの複雑さにあります。当時は電子カルテと医事会計という2つのエンジニアリングチームがひとつの製品を実装する形を取っていましたが、「電子カルテ」ひとつを取っても多数の関係者、多数の業務、多数の連携、そして多数の状況が想定されます。さらにすべての機能に診療報酬制度という共通する概念が串刺しで関わるため、「電子カルテ」と「医事会計」で製品を割ることそのものもチャレンジだと言えます。この技術ブログでもコードベースの分割統治が難しいことに繰り返し触れてきましたが、製品やコードベースが割れない状態でチームを割ることをトップダウンで進めることは困難です。

dev.henry.jp

もうひとつはゴールが遠すぎてどうすればできるかがイメージできないことです。「マネジメントを他の人に任せてCEOを経営に注力させる」ことそのものは正しいように見えますが、今までそうではなかったものを変えていくために何をすればよいのかがイメージしにくい状態でした。

このため2024年末時点では、本質的な解決である権限委譲は難しいのではないか、仮に医事会計側はチャレンジできても電子カルテ側はまだ先になるのでは、という見方が強い状況でした。組織にあるこうした問題意識を踏まえて、経営を執行から引き剥がす活動を進めていきました。

課題を解く10ヶ月

1月: 方針の明確化と障害の分析を行い、戦略を立てる

まずこの時点で、全従業員が見えるNotion上に「逆さんの製品本部長としての負荷を下げる」と題したページを作成して方針を明記し、なぜ難しいと考えるのか、どのような障害がありそうなのかをひとつずつていねいに言語化しました。その結果として解けそうな課題に分解できたため、それを解決するアプローチとして2つの案を作り、どちらの方が適切かをCEOとして判断いただく材料としました。

図2 作成したNotionの目次。この下には四半期ごとの実績と起動修正の記録が並んでいる

こうして整理した結果、意思決定ではない業務から渡していくアプローチと、価値のデリバリーから渡していくアプローチであれば、段階を踏んで試しやすいということがわかりました。また不安に名前をつけて細分化していくことで、これだったら彼に任せられる、それだったら自分でカバーに入れば渡しやすい、あの問題はもう逃げようがないんだからとっとと意思決定しないといけない、といった意思決定がやりやすくなり、多くの社員の「自分起点」の引き金を引くことができました。その結果として、逆瀬川自身に自信を持ってやっていけそう!というモードになっていただけたと感じています。

図3 製品本部長として持っていた責務を整理した図。不安に名前をつけることが大切です。

3月: 医事チームを分割して権限委譲できる大きさにする

喫緊の課題としては医事業務を支えるチームが20名を超えており、朝会をはじめとしたコミュニケーションが機能していない問題がありました。このままではマネジメントの責任を委譲することもままならないため、ドメインをどこで割るべきかをエンジニアを巻き込んで話し合い、請求レセプトチームを立ち上げています。逆瀬川から2名のエンジニアを指名して両チームのマネジメントを委ね、3月から試行のうえで6月から本実施としており、1月に決めたスコープや委譲する順番を踏まえて着実に権限委譲を進めました。

ここでVPoEとして見ていたのは主に朝会で逆瀬川が発言せずに済んでいるかどうか、でした。朝会で引き続き逆瀬川が発言してしまうと権限委譲が有名無実化してしまいますので、逆瀬川と筆者とで目標を設定し、基本的にマネジメントに任せること、フォローは朝会以外の場で1対1で行うこと、第3四半期には逆瀬川が朝会参加をやめることを握りました。特に「逆瀬川は部長ではないがプロジェクトマネジメントは兼務していた」時期があり、このあたりの匙加減は相談しながら走っていました。

図4 朝会の反省をマネジメント陣で実施していた際の筆者によるフィードバック例

結果的にこれらの目標は期日通りに達成されることになり、コンティンジェンシープランを発動させることなく速やかに権限委譲が完了しました。

7月: 電子カルテチームを分割して権限委譲できる大きさにする

医事チームの権限委譲が完了した7月には、残る電子カルテチームの権限委譲について議論しました。電子カルテチームが医事チームに比べて難しいのは、電子カルテという仕組みがかなり巨大であり、ドメインを2つに割ることが事実上不可能であろうと思われたことです。ここについてはVPoEがトップダウンで決めても禍根を残すだけだということが明らかだったため、部長候補やエンジニアリングマネージャに判断を委ね、筆者と逆瀬川はリマインドをするにとどめていました。

特にこの時期は全社で「Team Topologiesを参考にバリューストリームでドメインを割ることを考えてきたが、このアプローチは診療報酬という制度が背骨のように全体を貫いているHenryには合わない」という事実を認めて次の組織の在り方を模索しており、その最初の例を作ろうとしていた電子カルテチームのプレッシャーは大きなものだったと感じています。実際にSquad制度をはじめとしていくつかやり方が検討されていたようですが、ここでは詳細を割愛します。

また請求レセプトチーム発足の反省として、切り出したチームの目的は明瞭だったが残された方のチームはそうでなかったこと、チーム間の人員計画を流動的に行えなかったことの2点があったため、電子カルテチームの分割では二の舞を踏まないようマネジメントとエンジニアリングマネージャとで議論を重ねました。

最終的にはLeSSフレームワークを参考にして、組織としてはひとつだが実装や意思決定は独立して行える2つのチームを作る方向としました。もう少し思い切った判断をしたほうが良かったのかもしれないとは今も思いますが、少なくとも半年ほど動かしてみて破綻せず協調して動けているため、判断としては間違っていなかったのだと考えています。

9月: 逆瀬川の部長兼務が終了する

電子カルテチームの権限委譲が9月1日付けで完了し、逆瀬川が部長を兼務することがなくなりました。これによって逆瀬川は製品本部長のみを兼務することとなり、個別のチームを見る必要がなくなりました。筆者と逆瀬川は他の経営関係者と権限委譲を進めるための予算・稟議周りの整理や人事制度の刷新を進めることに注力できるようになったため、12月までを見込んでいた一大プロジェクトが早めに片付きました。

と、ここで満足しないのが我らがCCOの林太郎です。まだ4ヶ月あるやん!という激励をいただきまして、本部長と部門長の責務を具体化したうえで、逆瀬川に製品本部長をも権限委譲してもらうべく動きました。ここで指名されたのが1日めのアドベントカレンダーを書いてくれた縣(id:agtn)ですので、よろしければ彼の投稿も読んでもらえれば楽しんでいただけると思います。

dev.henry.jp

その後は順調に話が進み、縣が製品本部長に加えてVP of Productないし製品部門長を担うことになりました。これについては私が扱う内容を離れているので、いずれ役員が書いてくれるかなと思います。

図5 本記事執筆時点での組織。逆瀬川がCEOとしての責務に注力できるようになった。

11月: 縣が製品部門代表としてお客様にご挨拶をする

そして11月7日には弊社がお客様をはじめとした関係者を招いて地域医療の理想をともに語る場を設けたのですが、この場では逆瀬川ではなく縣が製品部門代表としてお客様にご挨拶をしています。これがかなりエポックメイキングな出来事であったことは、ここまで読んでいただけた方には伝わるでしょうか。

またこの頃には逆瀬川は CEOとしての活動、特に採用や意思決定に全力で取り組めるようになりました 。わかりやすいところでは第1四半期ではCEOの対社外の露出がnote記事2本に留まっていましたが、第4四半期ではまだ1ヶ月を残している12月頭の時点で記事3本、登壇3件とかなり増やせています。こうした地道な露出が将来の顧客や採用などの機会に繋がることを考えると、かなり良い改善状況ではないでしょうか。

振り返って、VPoEは何をしたのか、その存在意義はなにか

1年前は開発組織のほとんどのマネジメントを経営が兼務していた状況でしたが、我々は10ヶ月でこの問題を解消しマネジメントに権限委譲をするとともに、経営が採用や意思決定などの活動に注力できる状況が生まれました。また私や縣のような執行役員に執行が任せられる体制も整いました。これは拡大期のスタートアップにおける経営のあり方としてひとつの理想形だと考えており、結果が出せたことにひとまずホッとしています。

ただこの10ヶ月でVPoEがやったことを振り返ると、実はそんなに多くのことはやっていません。1月に方向性を示してやるぞとコミットしたこと、3月にスコープを決めて実際に権限委譲を進めたこと、その反省を踏まえて7月に最後の権限委譲を進めたことだけです。しかも3月と7月に悩みながら意思決定したのは筆者ではなく、対象チームの皆さんでありマネジメントであり、逆瀬川でした。筆者は「分割と権限委譲、するから。」と早期にスタンスを明示しておき、その成功を信じてビジョンを描き、あとは適切と思われるタイミングでリマインドを実施したのみです。

おそらく重要だったのは不安に名前をつけて整理して解決可能であることを示したことと、逆瀬川ではない他の人が部長を務めても充分に回るしむしろ理想に近いと言い続けたことです。これは連結6,000人のメガベンチャーでマネジメントを経験した筆者だからこそ、マネジメントが少ない段階でも確信を持って言えることだったのかもしれません。VPoEがあるべき姿を描いてその実現を信じて諦めていない、そのことを日々行動で示すことで一時期止まっていた検討が再開したり、理想的ではないかもしれないがそのときのベストを決めて次に行く動きが起こせたりといった効果があったと思っています。

株式会社ヘンリーはエンジニアリング組織の理想を追求していきます

権限委譲の浸透はひとまず行えましたが、SECIを回して学べる組織になるのはこれからです。また各チームが自律的かつ短時間に顧客と向き合って価値をデリバリーしていける状態を作るにも課題があると感じています。加えて縣とも話している課題として、チームの割り方がFeature Factory的になっていないか、バリューストリームで分けられないとしてももっと顧客価値に沿ったチームの形があるのではとも検討しています。デザイナーやQAといった専門家の知見を開発プロセスに横断的に組み込んでいく挑戦もまだ始まったばかりです。

株式会社ヘンリーではチーム作りのために泥をかぶり東奔西走しながら重要だけどとても地味なエンジニアリングを積み重ねられるVPoE室付きエンジニアを募集しています。エンジニアリング組織や社会課題解決、そして仲間が好きなエンジニアに来ていただけると嬉しいです。よろしくお願いいたします。

hrmos.co

デザインシステムライブラリを実装するためのテクニック

株式会社ヘンリーでソフトウェアエンジニアをしている小林(kobayang)です。 最近、社内のデザインシステムライブラリの更新を行った際に、汎用的なコンポーネントの実装について整理したので、その内容について記述します。

おことわり

この記事は Henry アドベントカレンダー 5 日目の記事です。 この記事は 電子カルテの開発を支える技術3 ~ モダンな技術で再発明する ~ の、「デザインシステムライブラリを実装する」から「汎用的なコンポーネントを実装するテクニック」の節を切り出した内容になります。 なお、この記事の内容は React 前提になります。

Props の定義

汎用的なコンポーネントを作る上で考慮すべき Props 定義について記述します。

HTML Attributes を公開する

HTML Attributes を UI コンポーネントから提供することで、Native の HTML と同様に UI コンポーネントを利用者が使用でき、汎用性が上がります。 たとえば、シンプルなボタンの UI コンポーネントを作ることを考えた時に、Props を次のように定義します。

type ButtonProps = {
  // 特定のButtonのプロパティを定義
  size: ButtonSize;
  // HTML Attributesを定義
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

onClickonMouseEnter などのイベントハンドラ、または aria などのアクセシビリティに関するプロパティを一度に定義することができます。

forwardRef で ref を公開する

汎用的なコンポーネントを作る際は、フォーカス管理やその他さまざまな理由で ref を使いたいケースがあるため、受け渡しができるようにしておくと便利です。

React 19 以前のバージョンをサポートする際には forwardRef による ref の受け渡しが必要になります。

ref の受け渡しは次のように記述できます。

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  (props, ref) => {
    return <StyledButton ref={ref} {...props} />;
  }
);

なお、React 19 から ref は forwardRef を使用しなくてもよくなったので、最新の React では直接 Props に ref を定義して良くなりました。

HTML 要素を変更可能にする

アプリ開発側がセマンティックを柔軟に指定できるようにするために、HTML 要素の設定を、UI コンポーネントから変更可能にしたいことがあります。 例としてよくあるのが、ボタンの UI コンポーネントが button 要素として使われるのか、または a 要素として使われるかを変更したい場合です。

一方で、JSX は HTML と紐づいているため、このような HTML 要素を変更可能にするためにはひと工夫が必要となります。 このような HTML 要素を変更できる UI コンポーネントのことを Polymorphic Component と呼びます。

ライブラリにおける Polymorphic Component の例

Headless UI(UI を持たない汎用的なコンポーネントライブラリ)や、スタイリングライブラリでは HTML 要素を変更するためのプロパティが定義されています。Chakra UI1、Radix UI2 などの Headless UI や styled-components3 のコンポーネントは、as プロパティによってコンポーネントの HTML 要素を切り替えることができます。Material UI4 では、component プロパティによってコンポーネントの HTML 要素を切り替えることができます。

const Button = styled.button``;

// Anchor Button として使うことができる
<Button as="a" href="/example_page" />;

Polymorphic Component を実装する

後述する styled-components と併用する場合のように、自前で Polymorphic Component を実装することが必要になるケースがあります。少々複雑ですが、PolymorphicComponent を次のように定義することで、自前で HTML 要素を外側から変更できるコンポーネントを実装することができます。ここでは tag というプロパティでコンポーネントの HTML 要素を変更することにします。

import * as React from "react";

type TagProps<C extends React.ElementType> = { tag?: C };
type PropsToOmit<C extends React.ElementType, P> = keyof (TagProps<C> & P);

export type PolymorphicComponentProps<
  C extends React.ElementType,
  Own = object
> = Own &
  TagProps<C> &
  Omit<React.ComponentPropsWithRef<C>, PropsToOmit<C, Own>>;

type PolymorphicRef<C extends React.ElementType> =
  React.ComponentPropsWithRef<C>["ref"];

export type PolymorphicComponent<
  DefaultC extends React.ElementType,
  Own = object
> = {
  <C extends React.ElementType = DefaultC>(
    props: PolymorphicComponentProps<C, Own>
  ): React.ReactElement | null;
};

UI コンポーネントの実装は次のように行います。

export const Button: PolymorphicComponent<"button", ButtonProps> = ({
  tag,
  ref,
  ...rest
}) => {
  const Component = tag ?? "button"; // ここでHTML要素を変更
  return <Component ref={ref as any} {...rest} />;
};

// Anchor Button として使うことができる
<Button tag="a" href="/example_page" />;

React 19 以前のバージョンをサポート対象とする場合は、ref を直接定義できないため、forwardRef の Helper も用意しておくと便利です。

// forwardRef の helper
function forwardRefWithTag<DefaultC extends ElementType, OwnProps>(
  render: <C extends ElementType = DefaultC>(
    props: PolymorphicComponentProps<C, OwnProps>,
    ref: PolymorphicRef<C>
  ) => React.ReactElement | null
): PolymorphicComponent<DefaultC, OwnProps> {
  return React.forwardRef(
    render as unknown as any
  ) as unknown as PolymorphicComponent<DefaultC, OwnProps>;
}

export const Button = forwardRefWithTag<"button", ButtonProps>(
  ({ tag, ...rest }, ref) => {
    const Component = tag ?? "button";
    return <Component ref={ref as any} {...rest} />;
  }
);

styled-components を使用する場合の注意点

styled-components で styled を使うと、コンポーネントのスタイルを追加することができますが、as を複数回使用すると、上書きする元のスタイルが失われてしまうため注意が必要です。UI ライブラリ自身で styled-components を利用しつつ、アプリケーション側でも styled-components によってスタイルの上書きを可能にしたい場合は、as の適用を集約するようにしましょう。

Slot Pattern

Polymorphic Component を使わない別の方法として、children で指定したコンポーネントを代わりに使用するパターンもあります。Radix UI はこのパターンを Slot コンポーネントという名前で提供しており、Slot Pattern と私は呼んでいます。

Polymorphic Component で紹介した Button と同等のサンプルを記述します。

import { Slot } from "@radix-ui/react-slot";

type Props = {
  // true の場合、子要素のコンポーネントを使用する
  asChild?: boolean;
  // button の プロパティを定義
};

const Button = React.forwardRef<HTMLButtonElement, Props>(
  ({ asChild, ...rest }, ref) => {
    const Comp = asChild ? Slot : "button";
    return <Comp ref={ref} {...rest} />;
  }
);

// Anchor button として使うことができる
<Button asChild>
  <a href="/example" />
</Button>;

Polymorphic Component と比較すると、Button の Props 定義がシンプルになるメリットがあります。また、コンポーネントごと分けることができるので、こちらの方が汎用的ではあります。一方で、子の要素でカスタマイズできることが暗黙的になるため、利用側のインターフェースは複雑になるデメリットがあることや、Slot は内部で cloneElement を使っており、React Server Component の互換性の問題がある5ため、使用は限定的にすると良いかもしれません。

セマンティックを自動化する

先ほど、HTML 要素を変更可能にすることでセマンティックをアプリ開発側で柔軟に設定できる方法について記述しました。一方で、ライブラリの方針次第ではセマンティックをコンポーネントの利用側で考えさせないようにする方向も考えることができます。

具体的な例として、h1-h6 の要素の自動化について考えてみます。

h1-h6 の自動化

Heading のセマンティックについて考えると、h1-h6 のレベルを使い分けることは重要です。なお、この項は 「React で h1-h6 を正しく使い分ける」6の記事を参考に記述しています。

Heading のレベルが何かは、実装するコンポーネントだけでなく、外側の HTML の構造に依存します。Context API を使うことで、h1-h6 の使い分けを行うことができます。

const HeadingLevelContext = React.createContext({ level: 1 });

export const useLevel = () => {
  const context = useContext(HeadingLevelContext);
  return context.level;
};

const Section = () => {
  const level = useLevel();
  const nextLevel = Math.min(level + 1, 6);

  return (
    <HeadingLevelContext.Provider value={{ level: nextLevel }}>
      {children}
    </HeadingLevelContext.Provider>
  );
};

const Heading = ({ children }) => {
  const level = useLevel();
  const H = `h${level}`;
  return <H>{children}</H>;
};

上記のように SectionHeading コンポーネントを定義することで、Heading のレベル制御の使い分けが可能になります。次のように定義することで、タイトルを h1 として、サブタイトルを h2 として描画できます。

<Section>
  <Heading>タイトル</Heading>
  <Section>
    <Heading>サブタイトル</Heading>
  </Section>
</Section>

機能を提供するデザインパターン

UI コンポーネントから何かしらの機能を提供する場合に、いくつかのデザインパターンを用いることがあります。代表的なパターンとして、 Render Props Pattern、Getter Props Pattern、Compound Pattern を紹介します。

Render Props Pattern

子要素の中身に依存せずに、子要素に機能を与えることができます。例として、ホバー状態を管理するコンポーネント Hover を考えてみましょう。

Render Props Pattern を用いることで、次のような使い方でホバー管理ができます。

<Hover>
  {({ hovered, getProps }) => (
    <div {...getProps()}>{hovered ? "Hovered!" : "Hover me"}</div>
  )}
</Hover>

実装としては次のようになります。

type Props = {
  hovered: boolean;
  getProps: () => React.HTMLAttributes<HTMLElement>;
};

const Hover: React.FC<{ children: (props: Props) => ReactNode }> = ({
  children,
}) => {
  const [hovered, setHovered] = useState(false);
  const getProps = () => ({
    onMouseEnter: () => setHovered(true),
    onMouseLeave: () => setHovered(false),
  });
  return <>{children({ hovered, getProps })}</>;
};

型定義が、children: ReactNode ではなく、children: (props: Props) => ReactNode となっていることがポイントです。Render Props Pattern は hooks で記述する機能を隠蔽することができるメリットがある一方、render の実装部分が複雑になるデメリットがあります。

私の体感では、最近のライブラリは hooks 自体を提供することが多い印象があります。

Getter Props Pattern

ライブラリのインターフェースで、UI コンポーネントに aria や event handler の機能を隠蔽しつつ提供する方法として Getter Props Pattern がよく使用されます。

たとえば、SelectBox のアクセシビリティを提供するライブラリである Downshift7useSelect という hooks を例に出します。この hooks は Native の Select 要素ではなく、自前で SelectBox を実装する際に必要なメニュー表示であったり、開閉管理やキーボード操作などのさまざまな機能を提供します。

実装の全貌は省略しますが、useSelect の返り値には getXXXProps というプロパティがあり、これらを UI コンポーネントに差し込むことで、機能が提供されます。

const { getToggleButtonProps, ... } = useSelect(...);

return <button {...getToggleButtonProps()} />;

getToggleButtonProps は、button をクリックした際の選択メニューの開閉機能であったり、aria-expanded などの aria 属性などを自動的に提供します。このような get props をコンポーネントに差し込んで機能を提供するパターンを Getter Props Pattern と呼びます。

Compound Pattern

Render Props や、Getter Props のデザインパターンは、プロパティが render 実装に露出する構造になっています。一方で React Context を使うことで、さらにそれらを隠蔽して見かけ上シンプルに機能を提供することができます。

次の例のように、<UI.Feature /> のような形で提供するデザインパターンで、Context をコンポーネントに隠蔽しつつ、機能を提供します。例として、トグルの状態を管理するコンポーネント Toggle を考えてみましょう。トグルの状態で、表示する内容の出し分けを行い、またボタンでトグルを行います。

<Toggle>
  <Toggle.On>The button is on</Toggle.On>
  <Toggle.Off>The button is off</Toggle.Off>
  <Toggle.Button>Toggle</Toggle.Button>
</Toggle>

実装としては次のように記述できます。

const ToggleContext = createContext();

function Toggle({ children }) {
  const [on, setOn] = useState(false);
  const toggle = () => setOn(!on);

  return (
    <ToggleContext.Provider value={{ on, toggle }}>
      {children}
    </ToggleContext.Provider>
  );
}

Toggle.On = function ToggleOn({ children }) {
  const { on } = useContext(ToggleContext);
  return on ? children : null;
};

Toggle.Off = function ToggleOff({ children }) {
  const { on } = useContext(ToggleContext);
  return on ? null : children;
};

Toggle.Button = function ToggleButton(props) {
  const { on, toggle } = useContext(ToggleContext);
  return <button onClick={toggle} {...props} />;
};

このような Context を使って複数のコンポーネント群を提供する実装パターンを Compound Pattern と呼びます。Context を使っている分、UI コンポーネントの実装は複雑になっており、一方で、利用側は内部実装のことをほとんど考えなくてよいというメリットがあります。

どのデザインパターンを採用するか?

3 つの代表的なデザインパターンを紹介しました。

体感として、Headless UI では Compound Pattern が内部実装を隠蔽できることから、多く採用されていることが多い印象があります。一方で、Render Props Pattern や、そもそも hooks を提供する方がライブラリの実装の見通しがよいため、そちらを採用するという視点もあるでしょう。

どのパターンにも一長一短があり、ライブラリの課題感や提供する規模感などに応じて、適切にパターンを採用することが重要です。

コンポーネントにスタイルプロパティを提供する

Headless UI などのライブラリでは、スタイリング機能を提供するプロパティをコンポーネント自体に追加していることがあります。Chakra UI、Radix UI、Material UI では Box という名前で、スタイリングを行うベースコンポーネントを提供しています。

Box

Chakra UI を例にとると、次のように Box を使うことができます。

<Box bg="tomato" w="100%" p="4" color="white" _hover={{ bg: "green" }}>
  This is the Box
</Box>

Chakra UI は _hover でホバーリアクションなど、擬似クラスも定義できることが特徴です。一方で、擬似クラスが提供されている場合は、スタイリング用のライブラリにも依存しているため、既存で使用しているスタイリング用のライブラリとの衝突が起きないか注意が必要です。

styled-system による Box の定義

styled-components を使用している場合、styled-system8 というライブラリを用いて、Box を自前で定義できます。

簡単に提供するなら、次のように記述できます。

import styled from "styled-components";
import { space, layout, typography, color } from "styled-system";

const Box = styled.div`
  ${space}
  ${layout}
  ${typography}
  ${color}
`;

自分で定義をカスタマイズして実装することもできます。自前で CSS プロパティを定義する Box の実装例を次に挙げます。

const StyledBox = styled("div").withConfig({
  shouldForwardProp: (prop) => {
    return !stylePropNames.has(prop);
  },
})<StyleProps>`
  box-sizing: border-box;
  min-width: 0;
  ${styledSystemConfig};
`;

export const Box = forwardRefWithTag<"div", StyleProps>(
  ({ tag = "div" as ElementType, ...rest }, ref) => {
    return <StyledBox as={tag} ref={ref} {...rest} />;
  }
);

スタイル提供用の設定は次のように記述できます。

import { CSSProperties } from "react";
import { compose, Config, system } from "styled-system";

const paddingConfig = {
  p: { property: "padding" },
  pt: { property: "paddingTop" },
  pb: { property: "paddingBottom" },
  pl: { property: "paddingLeft" },
  pr: { property: "paddingRight" },
  px: { properties: ["paddingLeft", "paddingRight"] },
  py: { properties: ["paddingTop", "paddingBottom"] },
} as const satisfies Config;

const padding = system(paddingConfig);

const stylePropConfig = {
  ...paddingConfig,
  // 他に必要なスタイル定義を登録する
} as const;

export const styledSystemConfig = compose(
  padding
  // 他に必要なスタイル定義を登録する
);

export const stylePropNames = new Set(styledSystemConfig.propNames ?? []);

type StyleConfig = typeof stylePropConfig;

type PrimaryCssPropName<Config> = Config extends { property: infer Property }
  ? Property & keyof CSSProperties
  : Config extends { properties: readonly [infer First, ...unknown[]] }
  ? First & keyof CSSProperties
  : never;

type CssPropertyValue<Config> = PrimaryCssPropName<Config> extends [never]
  ? CSSProperties[keyof CSSProperties]
  : CSSProperties[PrimaryCssPropName<Config>];

export type StyleProps = {
  [Prop in keyof StyleConfig]?: CssPropertyValue<StyleConfig[Prop]>;
};

このように記述することで、Box へのスタイルを型付きで組み込むことができるようになります。

既存ライブラリに実装を移譲する

ユーザビリティやアクセシビリティを考慮したコンポーネントを自前で実装するのはとても難しいです。

たとえば、ボタンなどを押下したときに表示される Popup パネル(Popover)を実装することを考えると、次のような機能を満たす必要があります。

  • フォーカス管理
    • 開いたら最初のフォーカス可能要素をフォーカス
    • 閉じたら元のトリガーにフォーカスを戻す
  • キーボード操作
    • Esc で閉じる
    • パネル内の Tab キーによる移動
    • 矢印キーによる選択項目の移動
  • 開閉管理
    • 外側クリックで閉じる
  • 位置決め・衝突管理
    • 決められた位置に表示する
    • ビューポートの大きさによって上下や左右の位置を入れ替える

また、さらに rolearia-expanded などのアクセシビリティ属性、アニメーションなど、プロダクトの性質やユーザー属性によって追加で対応が必要になります。

自前で上記の機能に対応するのは割に合わないことが多く、特にこだわりがなければ既存のライブラリを使うことをオススメします。ここまでに紹介した Radix UI などの Headless UI ライブラリがその一例で、一般的なユーザビリティやアクセシビリティを担保することができます。

Floating UI を用いた Popover 実装

ここでは、Floating UI9 というライブラリを用いたコンポーネントの実装を紹介します。

ライブラリ名のように、ボタン押下で浮かび上がる Popup や Tooltip などのコンポーネントのユーティリティであることはもちろんですが、それに加えて、Menu や SelectBox、ダイアログなど、何かしらのトリガーアイテムによって表示される要素全般に対して機能を提供しています。

Floating UI を使った Popover の実装を考えます。次のような hooks を提供し、Popover のコンポーネントに Props を当てることができます。

function usePopover<ReferenceElm extends HTMLElement>({
  placement,
  offsetPx,
}: PopoverArgs): PopoverProps<ReferenceElm> {
  const [open, setOpen] = useState(false);

  // For Floating UI Positioning
  const { refs, floatingStyles, context } = useFloating({
    open,
    onOpenChange: setOpen,
    placement: placement,
    whileElementsMounted: autoUpdate,
    middleware: [
      offset({ mainAxis: offsetPx }),
      flip({ padding: FlipPadding }),
      shift({ padding: ShiftPadding }),
    ],
  });

  // For Interactions
  const { getReferenceProps, getFloatingProps } = useInteractions([
    // Dismiss
    useDismiss(context, {
      escapeKey: true,
      outsidePress: true,
      bubbles: true,
    }),
    // Role
    useRole(context, {
      role: "dialog",
    }),
  ]);

  return {
    open,
    setOpen,
    referenceRef: refs.setReference,
    getReferenceProps,
    floatingRef: refs.setFloating,
    getFloatingProps,
    floatingStyles,
    context,
  };
}

内容は割愛しますが、referenceRef と Getter Props である getReferenceProps をトリガーとなるボタンに、floatingRefgetFloatingProps を Popup したいコンテンツに差し込むことで、Popover 機能を実現することができます。詳しくは Floating UI のドキュメントを参照していただけると嬉しいです。

まとめ

汎用的な UI コンポーネントを作る上でのテクニックについて記述しました。

複雑に思える既存のライブラリの実装も、分解すると上記のテクニックやパターンの組み合わせであったりします。たとえば、Radix UI では、Compound Pattern と Polymorphic/Slot Pattern を組み合わせることで、高い汎用性と機能の凝集性を持ったコンポーネントの提供を実現しています。

この内容が、デザインシステムライブラリのUI実装などの参考になれば幸いです!

【2025年版】ヘンリーのオンボーディング体制の現在点

この記事は

qiita.com

の4日目の記事です。

本記事の目的

はじめまして、11月にヘンリーにレセコン開発エンジニアとして入社した Masaki Sugimoto(id:msksgm) です。 株式会社ヘンリー エンジニアブログには、複数の入社エントリ(はじめての転職で難易度鬼のレセコン開発に挑戦しているはじめまして nabeo です)があります。 入社してから1ヶ月ですので、まだまだ業務に慣れない部分がありつつも、最近のヘンリーのオンボーディング情報をアップデートしたり、ヘンリーに少しでも興味がある方に向けて解像度を上げるために執筆しました。

入社後のあれこれ

オンボーディング

入社後の1ヶ月間はオンボーディング期間として設定されています。 この期間は常にMTGがあるわけではなく、最初の2週間ぐらいに1日2~4時間のオンボーディングMTGをやりつつ、チームのMTGに参加したりメンバーとの1on1をこなします。 最初の2週間が終わったら、ほとんどオンボーディングMTGが終わり各チームに本格的に配属していくので、そこからたまにあるオンボーディング系の業務をこなしながら、本格的にチームの業務にとりくんでいきます。

オンボーディングについては、nabeo(id:nabeop)さんと岡部さん(id:takamizawa46)の記事でも取り上げられていますが、エンジニア30名程度、全体で120名程度のスタートアップにしては充実していると思いました。 むしろ充実しすぎているほどの印象を受けました。 個人的なスタートアップの印象は、初日か次の日にはタスクがアサインされるものだと考えていたため、良い意味で面食らいました。

dev.henry.jp

dev.henry.jp

オンボーディングプログラムの内容をいくつか抽象化して列挙すると、以下のようなプログラムが含まれています。 どれも、医療業界未経験の私にとって勉強になる部分が多く、事業の意義やなぜヘンリーで働くのかについて理解を深めることができ非常にありがたかったです。

  • 会社の沿革について
  • 医療業界まわりの情勢
  • 組織説明
  • プロダクトのワークショップ

岡部さん(id:takamizawa46)の記事では、チームのオンボーディングについて未整備の部分が多いことが言及されていますが、比較的改善されたと考えています。 入社人数が増えるにつれてドキュメントや Slack が成熟していきました。 最近では Notion AI に質問すると、連携アプリケーション(Notion、Slack など)を横断的に検索してまとめてくれます。これにより、暗黙知や Slack でやりとりされただけの情報も発見しやすくなりました。 整備がしっかりしているかと言われたら、まだまだと考えているので、自分を含めて組織全体で整えていく必要があります。

未成熟だと感じている部分は、チームが担当しているドメイン(特にレセプト業務や診療報酬請求の仕組みなど)知識のキャッチアップ体制です。 私が担当するチームでは、レセコンの開発をしています。 レセコンに関係する、公費、点数、算定といった内容は、専門用語や専門的なワークフローが多く、日本語で会話しているのに内容を理解できない瞬間が多々あります。 上述のワークショップでまったく説明がないことはありませんが、新規参画者が慣れるには時間がかかる内容です。

お客様との関わり

自分の入社タイミングが良かった点が大きいですが、入社してから 病院DXカンファレンス2025を聴講したり、お客様訪問をする機会に恵まれました。

病院DXカンファレンス2025は、ヘンリーが主催したお客様を招待したイベントで「地域医療の理想を共に語る」をテーマに最新技術の共有、成功事例の紹介などをするイベントです。 私は現地参加ではなく配信を聴講しましたが、お客様がHenryを導入することで、どれくらい業務が変わったかを知ることができました。

お客様訪問とは、実際に電子カルテ・レセコンHenry(以下、Henry)を導入しているお客様の病院に訪問することです。 導入してから数ヶ月経過したお客様に訪問したときには、ペーパーレスが進んだことで業務スペースが増えたり特定の業務を削減できたことをお伺いできました。 実際に Henry を使って、業務をこなしている様子をみると Henry を開発する意義を実感しますし、新規参画者目線で現場における Henry の使われ方を見て勉強になりました。 しかし、まだまだ機能不足な点を指摘されたり、数多くの要望をいただいたりすると、ヘンリーが提供したい価値や実現したい地域医療にほど遠いことを痛感し、エンジニアとして身が引き締まる思いになります。

業務に関して

レセコンチームでは、だいたいマネージャー 1 名、PM 1 名、FE 2 名、BE 3 名、テスター 2 名、ドメインエキスパート 1 名という体制で開発をしています。 デイリースタンドアップミーティングやスプリントプランニングのタイミングでドメインエキスパートからフィードバックをもらえる機会が自分にとっては新鮮な環境です。 レセコンの使われ方についての知識がなくても、気軽に聞ける環境であるため、プロダクトづくりにおいて心理的安全性を保ちながら進められています。

技術的な側面では、Henry の BE 開発ではプログラミング言語に Kotlin を利用し、トレースツールには Honeycomb を利用しています。 これらの技術スタックは、私個人の技術的な関心事であるサーバーサイド Kotlin とオブザーバビリティと完全に一致していました。 Kotlin に興味がある理由は、複雑なドメインロジックを安全に表現するのに適していると考えているからです。 オブザーバビリティについては、開発と運用を続けるうちに複雑さと不透明さが増していくシステムにおいて、問題の早期発見と原因特定を可能にする重要な技術だと考えているからです。 ヘンリーでは、これらの関心が高い技術がすでに導入済みであるため、一個人のエンジニアとして手を動かして楽しく、成長を期待できる環境です。

採用技術については、以下の Speaker Deck やエンジニアブログで詳細に紹介されています。 これらに興味がある方は、そちらも参照してみてください。

speakerdeck.com

dev.henry.jp

一方で、ドメイン知識が圧倒的に不足しているため、IC としては業務に苦戦しています。 新規参画したときに、最初から活躍ができないのは当たり前なので、予想はしていましたが、いざ直面すると焦りを感じます。

個人で実践していること

ここまで、組織の現在のオンボーディング体制について記述しました。 ここからは、入社してから実感した自分の不足している点を解消するために、通常業務と合わせて、おこがましく取り組んでいることを記載します。 N=1 であるため参考にならないかもしれませんが、ヘンリーにはこれらの取り組みを受け入れてくれる組織であることが伝われば幸いです。

ドメインエキスパートとの対話でプロダクトの理解を深める

先述したチームでドメイン知識をキャッチアップできる体制が整っていないことに対する打開策です。 ヘンリーでは、Henry の標準業務運用フローと呼ばれるものを作成中です。 標準業務運用フローでは、Henryが実際にどのように使われるかのフローを定義しています。 中長期的には、CUJ(Critical User Journey)の定義や自動テストの取捨選択に利用されることを期待しています。 運用フローの定義はされているものの、フローが実際にどの画面を利用するのかはわかりづらい状況でした。
そこでどのように使われるかを最も知りたい新規参画者である私がドメインエキスパートとともに実際の画面動作をおさらいしています。 毎朝30~45分程度時間をとり、プロダクトとドメイン知識と業務フローを擦り合わせています。 それを私が持ち帰りドキュメンテーションやコードとの対応をまとめています。 中長期的には新規参画者が運用フローを見るだけでHenryのプロダクト理解が進んだり、フローをコードで表現できないかと画策しています。

興味のある MTG に参加してみる

ヘンリーではギベンと呼ばれる技術勉強会だったり、ドメインの知見共有会だったりと、ドオープンな勉強会が多く開催されています。 すでに、それらにも参加しているのですが、ほかのチームの MTG にも参加してみたりしています。 私はオブザーバビリティや SRE にも興味があったため、SRE 室のランチ会やパフォーマンス分析会にも参加しています。 まだまだ組織的にカオスな側面が多く、MTGの出入りがしやすいため、興味がある特定の分野に参加しやすい状況です。

DevRel 活動に関わる

入社前からヘンリーがカンファレンスのブース出展が多いことから DevRel が盛んであることを知っていました。 過去の経験から、DevRel 運営のつらみも知っているため、どのように運営をしているのか気になっていました。 そこで、先述した興味のある MTG に参加してみるにも近いですが、ヘンリーの DevRel 運営に関わってみることにしました。

スポンサーをしているカンファレンスのブースを手伝ったり、技術書典で売り子になったり、ヘンリー主催の勉強会の裏側で、DevRel 活動の大変さや楽しさを目の当たりにしてきました。 運営側として活動することで新たな発見がありました。特に、ヘンリーを初めて知る人への説明を通じて、プロダクトの価値や事業の意義について改めて理解を深めることができ、普段の業務以上に勉強になることが多いです。

一緒に仕事をする仲間を募集しています

ここまで読んでいただき、ありがとうございます。
エンジニアの数が増えるにつれて不足していた部分が明確になり、オンボーディングも安定しつつあります。 しかし、組織・事業・エンジニアリングのそれぞれの面で、カオスな部分が残っており、そのカオスを一緒に楽しめる仲間を募集しています。

興味のある方は以下の採用サイトから、ぜひコンタクトしてみてください。

技術広報をすると何がいいのか? 〜得られる効果とコスパについて〜

こんにちは、ヘンリー開発者のタケハタです。
普段はエンジニアとしてプロダクトの開発をしつつ、技術広報ギルドという有志の横断組織で、技術広報の活動をしています。

本記事は株式会社ヘンリー Advent Calendar 2025 3日目の記事になります。
昨日はSREの(id:nabeop / @nabeo)によるなぜ AWS 移設をするのかでした。

目次

技術広報の成果は見えづらいとよく言われる

技術広報は「成果が見えづらい」と言われがちです。 売上に直結するわけでもなく、採用効果も長期的に見ていく必要があり、「施策を一つ実施したら即KPIが伸びる」という性質のものでもありません。 その一方で、ある程度の費用や人的工数はかかります。

そこで本記事では、ヘンリーが実際に取り組んできた技術広報の活動を例に、どのような効果が期待できるのか を具体的に紹介します。

効果として期待できるもの

まず、効果として期待できるものをいくつか紹介します。
主に採用とブランディングになってくるのですが、もうちょっと具体的に書きます。

認知の獲得

まず、会社の名前が知られているということはとても重要なことです。
例えば転職活動をしている時、転職エージェントで渡された大量の求人票をパラパラとめくっていると、名前を知っている企業でないとほぼ目に止まりません。スカウトサイトやSNSで大量のスカウトが来ている場合なども同じでしょう。

逆に聞いたことある企業であれば「なんか聞いたことあるな」と動機になりえますし、さらに"いい印象"を持った上で知っている企業であればとりあえず見てみようとは思えます。 もし本当に強い興味を持ってもらえていたら、「転職しようかな」と考えた時に自分たちの企業の名前を思い浮かべてもらえるかもしれません。

コネクションの形成

採用では候補母集団の広さが重要です。
仮にこちらが採用したいと思った人の候補が10人いたとして、その中で自分たちに興味を持ってもらえるのは2〜3人かもしれませんし、1人もいないかもしれません。その候補を増やしておく必要があります。

いわゆるタレントプールを充実させるという話ですが、そのためにも技術広報は有効です。
今はスカウト媒体やSNSでスカウトを送ってつながることもできますし、社員のリファラルで増やす方法もありますが、あくまで自分たちで見つけられた範囲の人にしかアプローチできません。

それに対して例えばイベントに登壇したりブース出展したりすると、不特定多数の人がこちらの話を聞きに来てくれます。
そこには自分たちの検索には引っかからなかった人や、そもそもオンライン上に現れないような人もいます。
スカウトを送っても見られずに終わるだけだった人が、イベントで自分たちに興味を持って来てくれて、話を聞いてもらえるかもしれません。

ブランド力の向上

エンジニアについて発信することで、自分たちの会社に優秀なエンジニアや、取り組みを発表することで組織の印象を上げることができます。
「この会社はこんなに優秀なエンジニアがいるのか」「こんなすごい取り組みをやっているのか」と思われれば、企業イメージが向上します。

また、技術広報をやっていることで"エンジニアに理解のある会社"というイメージも持ってもらいやすいです。
冒頭で書いた通りお金も工数もかかることなので、会社として理解がなければ基本的にできません。

社内のエンジニアのモチベーションとスキル向上

モチベーション向上

私がブログを初めて書いた時(発信を始めた時)は、義務感にかられてでした。
しかし、今はブログを書いたり登壇したりと、発信すること自体が楽しいと感じています。

その理由の一つとしては、見た人から反応をもらえるのが嬉しいです。
そんなに多いわけではなくても、社内外の誰かしらからポジティブな感想をもらえるのは嬉しいものです。

また、自社の説明やPRをするために語っていると、自分の組織のよさを言語化して理解が深まり働くモチベーションが上がることもあります。

スキル向上

また、アウトプットをすること自体が自分のスキルアップにもつながります。
自分がよく知ってる分野の技術でも、ブログや登壇ではより正確に伝える必要があるため、改めて調べて理解できてなかった部分に気づくことがあります。
また技術的な話でなくても、自分の考え方を言語化することで、強みや課題に気づくこともります。

あとはイベント出展などをしていると、前述のように多くのエンジニアと話す機会ができるので、自分の知らない考え方に触れて見聞を広げることにもつながります。

施策ごとの効果

もう少し具体的に、技術広報の施策と期待できる効果を紹介していきます。

技術ブログ

採用候補者へのPR

ブログが一番力を発揮するのは、採用の候補者が選考に進む前に読めることです。
その会社がどんなことをやっているのか、どんなエンジニアがいるかなど、読むことで雰囲気を掴むことができます。
候補者が読んで面白いと思う記事があれば、受けるか迷っている人へのPRにもなります。
人によっては定常的に発信していること自体に魅力を感じる場合もあります。

また、面談や面接で質問をされた時、その回答として合致する記事があれば渡すこともできます。
その場で説明するのは時間が限られてしまうので、より詳細に伝えることができるものが用意されているのは、とても有効です。

認知の獲得

あとは技術的な内容は、エンジニアの調べ物の検索に引っかかって目にとまることもあります。
記事が多ければそれだけヒットする可能性も上がり、目に留まる頻度が上がれば前述の認知の獲得にもつながります。

そしてもちろんバズる記事を書ければ、その単発で大きな宣伝効果を生む可能性もあります。
しかし、これはめったに起こらないものなので、積み上げが大事ということを意識する方が重要です。

イベントへのスポンサード、ブース出展

多くの人と会いプチカジュアル面談のようなことができる

イベントのスポンサーメニューで鉄板のブース出展は、とにかく不特定多数の参加者と直接話せることが有益です。
多くの企業でクイズやノベルティ配布などコンテンツを用意していますが、大事なのは来てもらった方に自社の話をできることです。
私は何度もブース出展に参加していますが、普段カジュアル面談などで話しているような内容を1日に何十人にも話していて、プチカジュアル面談を大量にしている感覚になります。

スカウトやエージェント経由などでこの人数感と合うには膨大な労力と時間がかかるので、お互い気軽に会って話せる場があるのはとても貴重です。
イベントのテーマに沿って話題も作りやすいので、面談などで話すのが苦手な人にも優しいです。

技術領域へのブランディングとしても有効

会社の使っている技術領域に関連する内容のカンファレンスなどでは、特にマッチする人が来てくれる可能性が上がります。
その領域への会社としての本気度も伝わることで、技術に関心の高いエンジニアが興味を持つ可能性もあり、ブランディングとしても有効です。

自社イベント開催

ブース出展は外のイベントを行ってのアピールする場になりますが、自社でイベントを主催するのはまた違った効果があります。

まず主催者なので、全面的に自社のことを打ち出すことができます。
また、会社を全面に打ち出したイベント来てくれる参加者なので、会社に興味を持ってくれた人も多くなります。
ブース出展などで興味を持ってくれた人に、「こういうイベントやるので来ませんか?」と誘い、さらに会社について深く知ってもらうこともできます。

一番は会社のファンになってもらうことが狙いになります。

ヘンリーで2025年にやってきた施策と成果

では、実際にヘンリーでやってきた施策と、得られた効果を紹介します。

やってきた施策

まずはやってきた施策です。
2025年は技術広報の活動が活発になり、多くのことに取り組みました。

技術ブログ

まずは本ブログです。 dev.henry.jp 月2本以上は書けるように運用しており、今月はQiita Advent Calendarに参加中のため更新も多くなる予定です。

ポッドキャスト

「理想駆動ラジオ」というポッドキャストもやっています。 open.spotify.com こちらはヘンリーの社員を一人ずつインタビューし、ヘンリーでの働き方やパーソナリティを深掘っていく形式になります。
「ヘンリーでどんな人が働いているのか?」を知っていただくためのコンテンツになっています。

スポンサー、ブース出展

以下のイベントにスポンサードし、ブース出展してしました。

技術書典18
技術書典19
CoLab Conf(コラコン) 第1回
CoLab Conf(コラコン) 第2回 ※12/13開催予定
Cloud Operator Days Tokyo 2025
Kotlin Fest 2025
アーキテクチャカンファレンス 2025

技術書典はスポンサードしていますが、ブースは有志のサークルとして申し込んで毎回本を出しています。

カンファレンス登壇

以下のカンファレンスでヘンリーメンバーが登壇しました。

CoLab Conf(コラコン) 第2回
Cloud Operator Days Tokyo 2025
Kotlin Fest 2025
アーキテクチャカンファレンス 2025

自社イベント(コラボ、コミュニティ参加含む)

自社イベントとしては以下を開催しました。

Henry Engineer Meetup #1
Henry Engineer Meetup #2
Henry Engineer Meetup #3
Henry Engineer Meetup #4 ※12/11開催予定
QAの理想を語らNight!
Server-Side Kotlin Night 2025

主には「Henry Engineer Meetup」が定期的な自社イベントとなっており、ヘンリーや医療に興味を持っている方や、社員の知り合いもお誘いしながらヘンリーの開発について知っていただく内容です。
また、Kotlin Fest 2025の非公式アフターイベントやQAに関するイベントを開催したりと、技術領域にフォーカスしたイベントも行っています。

他社コラボイベント

さらに他の企業様ともコラボして、以下のようなイベントもやっています。

シネマ de LT会〜あなたのナレッジ大上映〜
HealthTech Meetup
HealthTech Meetup vol.2
Server-Side Kotlin LT大会 vol.14
Server-Side Kotlin LT大会 vol.15
Server-Side Kotlin LT大会 vol.16

ヘンリーはServer-Side Kotlin Meetupというコミュニティに会社として参加しており、「Server-Side Kotlin LT大会」はそのイベントになります。
最近はHealthTech Meetupという医療系のテック企業による合同イベントも立ち上げており、多くの方にご参加いただいています。

ヘンリーで得られた効果

実際に得られた効果を紹介します。

採用の中で聞いた声

まず、面談などでお話した方から以下のような声をいただきました。

  • ブログの記事がいっぱいあったので見て雰囲気がわかった
  • ポッドキャストを聞いてどんな人がいるのかわかった
  • Kotlin Festでスポンサードしているのを見てヘンリーの名前を知った
  • 技術書典の記事で興味を持った
  • 候補にしていた企業の中で、選ぶ際に発信しているかを足切りに条件にしていた

やはりブログは面談や選考に来ていただいた候補者の方が、会う前に情報を得るために読んでくださっていることが多かったです。
ポッドキャストも同様の効果がありますね。

スポンサード、ブース出展で知ったという声も非常に嬉しいものでした。
より多くの方に知っていただくためにやってきた施策なので、こちらも期待した効果が出始めていると言えます。

自社イベントから選考につながった

主な自社イベントであるHenry Engineer Meetupでは、そこで興味を持ち選考に進んでいただいた方もいます。
ヘンリーのエンジニアによる発表もありますし、それ以外の社員も多く参加し会社のことをお話しするので、働くイメージが具体的になって決められたようです。

社員の知り合いの方や、過去にカジュアル面談などでお話した方で「もう少し話を聞いてみたい」という方をお招きすることもあります。
もちろん「このイベントに参加したから絶対選考を受けてくれ」というわけではなく、あくまでヘンリーや医療ドメインの面白さを知っていただき、将来的にでも興味を持った時にご一緒できたら嬉しいと考えています。

カジュアル面談数の増加

2024年末と比べて、右肩上がりに増えています。

カジュアル面談数の推移

人事の方でスカウト強化などの動きを他にもしているので、すべてが技術広報の効果というわけではありません。
しかし会社としての露出が増えたことで認知され、スカウトで返信していただけることが増えたり、前述のようにイベントに参加して決めていただいたりと着実につながっています。

前提として、施策1つで直接的な効果は出にくい

効果を色々と書きましたが、施策を1つやっただけで直接的に採用などの効果につながることはまずありません。
例えば大きなカンファレンスに初めて登壇者を出したとして、いきなり「あのセッションを見て入りたいと思いました!」とは普通なりません。
ブログなども数記事書いていきなりバズって、「あの記事を見て転職したいと思いました!」となる人もまずいないでしょう。

なのでやはり積み上げが大事です。
いざ転職しようと思った時に、多くの人が「そういえばヘンリーって会社あったな」と思い浮かべるようになったら勝ちです。

コスパってどうなの?

技術広報に価値があること自体は知っていただけたかもしれませんが、ではそのコストパフォーマンスはどうなのか?と考える人もいるのではないでしょうか。

他の採用やPRをした時の比較をした時

採用は必要なコストが高い

採用やPRは基本的にお金と労力がかかります。
採用に関してはエージェントやスカウト媒体の利用料、サービスによっては成約手数料がかかる場合もあります。PRのために広告を出すのも、もちろん費用がかかります。
さらにそのお金と労力をかけても、自分たちの求めている人と出会うまでには何十人もの人と時間をかけて会う必要があり、さらにそこから候補者から自分たちを選んでもらう必要があります。

技術広報でかかるコスト

それを考えると、一見労力が大きいように見えるブース出展などの活動も、コスパは悪くないのではないかと考えています。
例えばブース出展であれば、使うコストとしては主に以下のようなものがあります。

  • お金
    • スポンサー費(ブース出せるプランは大体100万前後〜)
    • 配布するノベルティ制作(新規に作成する場合)
  • 作業
    • 運営との事務的なやり取り
    • ブースコンテンツの企画、制作
    • ノベルティの考案(新規に作成する場合)
    • 会場への発送対応
    • 当日のブース対応

これらは広報に関わるメンバー何人かが中心になって、必要に応じて社員に協力を仰ぎながら進めます。
ただ、通常の採用でも前述のようにスカウトや面談・面接の工数や、様々な手数料などの費用がかかります。
なのでそこの差分はあまりないと考えています。

その上で採用以外の効果もある

その上でさらにやることでスキルアップやモチベーション向上につながるという効果も得られます。
さらにヘンリーでは、今のところ協力してもらったメンバーはみんな楽しみながらイベントなどに関わっており、「楽しく採用・PRに関われる」というところも隠れたコスパの良さだと思っています。

もちろんどちらがいいというわけではなく、両軸でやる必要があります。
採用サービスの活用をある程度やりきっている企業であれば、単純にそこにさらに多く工数をつぎ込むよりも、新たな層にアプローチできる可能性がある技術広報に工数を使うのは有効な選択肢になります。

その工数をエンジニアが開発に使ったほうがいいのでは?

広報のような活動は、開発が忙しくなってくるとどうしても後回しにされがちです。
技術広報もエンジニアの力が必要になってくるので、「その工数を開発に使ったらもっとリリース早められるのでは」と思う人もいるでしょう。

採用を止めないのであればやるべき

しかし、それは「エンジニアが面談・面接する時間を開発に回した方がいいから採用止めよう」と言っているのと同じようなことだと思います。
ここまで書いてきた通り、技術広報は採用施策の一つとしても多くの効果が見込めます。
今後も採用を続けて、組織を拡大していくような想定があるのであれば、そのための手段の一つとしてやっておくことは強くおすすめします。

社員のエンゲージメント向上にもつながる

また、この活動により社員のモチベーションが上がり、会社で長く働くことにつながるのであればそれも大きなプラスです。
広報活動に参加したり、広報の成果を見て自分のいる会社を好きになり、3年で辞めてたかもしれない人が10年働いたらそれは1人採用する以上のとてつもない成果です。
私も技術広報ギルドに参加していることが、ヘンリーで楽しく開発できている理由の一つでもあります。
開発だけをやっていたら、今ほどヘンリーのよさを語れなかったと思いますし、技術広報のおかげでより価値を感じながら開発ができています。

組織を拡大していくのであれば技術広報の価値は高い

繰り返しになりますが、組織の拡大をするつもりでエンジニアが必要なのであれば、技術広報をする価値は非常に高いです。
もし「やりたいけど、どれだけ価値があるのかわからない」「成果が見えないので続けるモチベがない」と思っている方がいたら、この記事を参考に自信を持ってやっていただけたら嬉しいです。

ヘンリーでは来年以降もさらに積極的な技術広報の活動をしていこうと考えていますので、イベントなどで見かけた時はぜひお立ち寄りいただければと思います。

告知: 「Henry Engineer Meetup #4 電子カルテ開発の学びと働くリアル」を開催します!

最後に告知です。
本記事の中でも書いていた、「Henry Engineer Meetup」の#4を開催します!

henry.connpass.com

もしこのブログを読んでヘンリーに興味を持っていただいた方は、ぜひお越しください。

なぜ AWS 移設をするのか

ヘンリーで SRE をやっている id:nabeop です。

これは株式会社ヘンリー Advent Calendar 2025 (シーズン1) の2日目の記事です。昨日は VPoP (VP of Product) の縣 (id:agtn / @agatan) による事業戦略は技術戦略に影響を与えるが、技術戦略もまた事業戦略に影響を与えるべきでした。

今年の SRE チームの大きなトピックとしてクラウド基盤を Google Cloud から AWS に移設するプロジェクトが進んでいます。プロジェクト自体は去年から始まっており、粛々と進めていたのですが、ある程度の目処が立ってきたので今年の10月に外部向けにもプロジェクトの存在を公開しました。

カジュアル面談やイベントなどで AWS 移設について言及することがあったのですが、一番質問されたのは「なぜ、クラウド基盤の移設をするのか?」という内容でした。そこで、今回は Google Cloud を選択した経緯と、クラウド基盤の移設を決定した背景について説明したいと思います。

続きを読む

薬学部からITコンサルへ、大企業からスタートアップへ。ヘンリーに入社しました。

はじめに

はじめまして。@ryugen04です。 2025年11月に株式会社ヘンリーに入社しました。

経歴を一言でいうと、「薬剤師免許を持っているけど、薬局で働いたことがないエンジニア」です。薬学部の研究室で医療情報学を学ぶ中でプログラミングに出会い、ITコンサルティング企業で4年、医療系を含む様々なプロジェクトを経験しました。

なぜ大企業からスタートアップへ移ったのか。入社1ヶ月の今、実際に働いてみての所感もあわせて書いてみます。

前職での経験

四苦八苦して大学を卒業したあとに前職のITコンサルティング企業には新卒から4年間在籍し、ありがたいことにシニアランクまで昇進しました。ウォーターフォールもアジャイルも経験し、医療系プロジェクトでは診療報酬に関する開発にも携わらせていただきました。

会社規模が大きかったこともあり、基幹系システムや官公庁系案件、小規模なBtoC案件など、様々なインダストリーに関われたのも良い経験でした。 リーダー的な役割も任せてもらい、マネジメントの基礎を学んだり、スクラムマスターの真似事のような経験もさせてもらいました。

様々な経験をさせてもらった一方、大企業や受託開発に近しい領域ゆえの課題も感じていました。

  • 仕様を自分たちで決められない
  • プロジェクト体制のため、プロダクトへの継続的なオーナーシップを持ちにくい
  • 技術選定や変更に組織的な制約が大きい

これらは会社の良し悪しではなくトレードオフな側面だとは思います。

他に組織面としても、私が志す医療やITの分野に全員が同じ方向を向いているわけではない、といったことに個人的に考えることがありました。

転職を決めた理由

こうした経験を経て、次のような環境を求めるようになりました。

  • 技術か医療、あるいはその両方が好きな人たちが集まり、組織全体が同じ方向を向いている
  • 小さな規模でスピード感を持ったプロダクト開発ができる
  • 技術的により大きな挑戦と成長ができる
  • 医療に大きなインパクトを与えるプロダクトを、自分がオーナーシップを持って開発できる

また、個人的な年齢も30手前だったことも意識しました。挑戦をするなら今だろう、と。

ヘンリーに決めた理由

転職では医療×ITという軸で働こう、と考え、いくつかの企業を受けました。医療系テック企業にはアンテナを貼っていたので、ヘンリーのこと自体はもともと知ってはいました。 その中で、ヘンリーを選んだ理由は主に3つあります。

  • 目標の大きさ
  • アウトプット文化
  • 病院見学での印象

「目標の大きさ」としては、ヘンリーは「ノーベル平和賞」を企業理念の中間ゴールとして掲げています。大きな目標ですが、だから良い。 自分のやりたいことである、医療に大きなインパクトを与えるプロダクト開発というところにこの上なくマッチしていますし、持続可能な医療体制という社会課題に本気で取り組む会社の姿勢の表れであり、かつ全員がこの目標の方向を向いているということに大きな価値を感じました。

「アウトプット文化」としては、connpassイベントの開催や、技術書典への出展をしていることに大きな魅力を感じました。 転職当時では以下のような本を2冊出しており、かつそれぞれ100p超という結構なボリュームがあったりします。 techbookfest.org プロダクトの内情をここまで積極的に発信できる、またこのボリュームは個人の気まぐれや献身だけでなく、チームとしてアウトプットを推奨や協力している姿勢を感じました。

「病院見学での印象」としては、選考が進んだ内定承諾前に提案いただき、病院見学をさせてもらいました。印象的だったのは、ヘンリーの社員が現場に複数人入り込み、医療職の方々とラフにコミュニケーションを取っていたことです。電子カルテやレセコンの導入は一般的には経営のトップダウンで決まり、現場的にはnot welcome。もう少し冷たい距離感や殺伐とした雰囲気をイメージしていたので、実際に医療現場を一緒に支えているような風景に好感を覚えました。

丁寧な採用に力を入れていること、病院との距離が近いこと。選考を通じてこれを肌で感じられたことも大きかったです。

入社1ヶ月の実際

スタートアップなので、正直入社初日から修羅場に放り込まれるくらいの覚悟はしていました。 実際はオンボーディングがしっかり設計されていて、良い意味で意外でした。Notionに共通タスクリストやドキュメントがまとまっていて、全社的なキャッチアップがしやすくなっています。スタートアップ特有の「組織が崩壊寸前のカオス」といった雰囲気は正直あまりなく、組織設計がしっかりされているぶん安定感があります。

技術面では、Kotlinがバックエンドのメインであること、複数のサーバー構成であることなど、前職のJavaメインの環境とは異なる部分のキャッチアップと並行しながらタスクを進めています。コードベースはエンジニアのレベルが高く、いわゆる「神クラス」のような負債は見当たりません。GraphQLなどモダンな技術スタックを使っていることも魅力です。前職から言語的にはすべて新しいものへのチャレンジとなっているため、キャッチアップしながら日々頑張っています。

ドメイン知識については、前職で診療報酬に関わっていた経験が思った以上に活きています。薬学部で学んだ医療制度の知識や、医療現場の肌感覚といった部分も、キャッチアップのスピードにプラスしている実感があります。

もちろんわからないことは多いですが、聞けば親切に教えてもらえます。この領域は医療現場の慣習や、厚生労働省などを主体とした国としてのシステム、歴史や制度的な複雑性があり、はじめて取り組む方には想像以上かもしれません。ただ、それをどう扱うかがエンジニアリングの腕の見せ所なのではと思っています。やりがいはありますね。

今やっていること

現在は製品開発本部に所属し、スクラム開発のエンジニアを担当しています。Henryの機能領域として大きく電子カルテ、レセコン、オーダー機能などがありますが、その中のレセコンのサブ領域ですね。

新規画面機能のフロントエンドからバックエンドまでの開発に関われています。

チームで印象的なのは、1週間サイクルでスクラムが回っていること。そしてドメインエキスパート、マネージャー、デザイナー、エンジニアなどなどがそれぞれ自主的に大きくアウトプットしていることです。 開発中はドメインエキスパートと要件を確認しあい、本番環境へのデリバリー前にはリリースノートの書き方やリリースタイミングまで関係する社内メンバーと相談してチームとしてオーナーシップをもって決めています。これは前職では経験できなかったことで、まさに求めていた環境だと感じています。 このスピード感と自主性は、レベルの高い人材が揃っていないと成り立たないと思いました。

まとめ

入社1ヶ月、まだまだわからないことやサポートが必要なことも正直多いです。しかし、求めていた環境ではあると感じています。プロダクトへのオーナーシップ、技術的な挑戦と成長、医療への貢献。これからどう成長していけるか、楽しみです。

採用情報

ヘンリーでは一緒に働く仲間を募集しています。この記事を読んで少しでも興味を持っていただけたら、ぜひ気軽にカジュアル面談の連絡をしてください。

jobs.henry.jp

hrmos.co