基本情報
| key | value |
|---|---|
| 氏名 | 大出 達也 |
| 生年月日 | 1991/07/14 |
| github | @machamp0714 |
| Zenn | @machamp |
スキル
職務経歴詳細
ラフノート株式会社(2020/05〜現在)
TimeCrowdのバッチシステムのインフラの改善
プロジェクト概要
TimeCrowdのバッチシステムは、これまでAWSアカウントの運用を外部の企業に運用を委託していた。 そこで、バッチシステムを自社で管理する AWS アカウントへ移行することとなり、アカウントの移行作業と、移行先となる新アカウント上でのインフラの設計・構築を担当。
基本情報
| 規模 | 3名(自社3名) |
|---|---|
| 役割 | メンバー |
| 担当 | • インフラ設計・構築 |
主な機能・業務
- AWS アカウントの移行
- AWS Organizations & IdentityCenter の導入
- IaC の導入
- ECS Fargate・EventBridge Scheduler を利用したバッチ実行基盤の構築
- Datadog を使用したバッチの監視体制の構築
- リザーブドインスタンス・Savings Plan の購入
課題
- スタンドアロンなアカウントがサービスごとに存在し、IAM ユーザーも各アカウントに存在するなど、IAM リソースが重複して適切に管理されていなかった。
- EC2にグローバルIPが紐づけられ、アタックサーフェスが広い、S3 にアクセスポリシーが設定されていない、RDS などのリソースが暗号化されていないなど、セキュリティに課題があった。
- 一台のインスタンスで複数のバッチがcronで稼働しており、今後顧客が増えた場合にスケールしにくいという課題があった
成果
- AWS Organizations を導入し、スタンドアロンなアカウントを組織下にまとめました。また IdentityCenter を導入し、Google Workspace と連携することで、各アカウントで IAM ユーザーが重複している問題を解消しました。
- Fargate で1バッチ1コンテナで実行できるようにして、1つのバッチのパフォーマンスの悪化が他のバッチにも影響してしまう問題を解消しました。また、独立した環境でバッチを実行できるため、サーバーの台数を増やすことなくビジネスの成長に対応できるようになりました。
- セキュリティ上の課題に対しては下記の施策を実施しました。
- Internet Gateway にルーティングされていたのを、NAT Gateway にルーティングするようにネットワークの設計から見直しました。また VPC エンドポイントを追加し、AWS サービスとの通信に関してはプライベートなネットワーク内で完結するように構成しました
- S3, ECR, SNS などアクセスポリシーを設定する必要があるリソースに関しては最小権限のポリシーを適用しました。
- RDS、Elasticache のようなサービスは KMS を利用してデータの暗号化を実施しました。
- リザーブドインスタンス・Savings Plan の購入により年間$1,000のインフラのコストを削減
工夫した点
stateを環境ごと(staging,production...)で分割すると、コードの理解やplanの実行に時間が掛かり、インフラのテストが大変になると考え、networkstorageなどのコンポーネント単位で分割しました。ただし、この方法ではコンポーネント同士で依存が発生したり、コンポーネントごとに設定ファイルを書かなければいけないなどの課題もありましたが、terragruntを採用することで、依存関係をdependenciesで明示的に管理し、設定ファイルも DRY にすることが出来ました。- Datadog のアラートメッセージ中に、runbook を記載した上で Slack にアラートを通知する体制を作りました。runbook にはバッチを再実行する
aws cliのコマンドを記述し、AWS の知見がない開発メンバーも AWS Chatbot で Slack から aws cli を実行できるようにしました。 - 開発メンバーが AWS 上で作業することなく、スケジュールをデプロイできる体制を作りました。スケジュールは yaml で記述し、それを EventBridge Scheduler 用の module に渡すことで、GitHub Actions でスケジュールを自動でデプロイできるようにしました。
研修予約システムの開発・運用
プロジェクト概要
化粧品・医薬品メーカーが利用する研修予約システムの開発・運用に、開発リーダーとして参画しました。 営業担当が予約の申請を行い、上長が承認、研修担当者が予約を確定するという承認フローがあり、最終的に研修担当者がフィードバックを営業担当に実施するシステム。顧客折衝、要件定義、技術選定、開発、インフラの構築を担当。
基本情報
| 規模 | 3名(自社1名,業務委託2名) |
|---|---|
| 役割 | 開発リーダー |
| 担当 | • 設計・コーディング • インフラ構築 • 保守・運用 |
主な機能・業務
- 月・週表示の切り替え、予約情報の確認、研修の空き状況表示が可能なカレンダーの実装
AASMを利用した承認フローの実装- 研修の修了証を PDF で発行する機能
- 日本語・英語の2言語に対応した多言語化対応(i18next を使用)
- Fargate を利用したコンテナ基盤の構築
課題
- 「顧客管理のマスタに Salesforce を使用したい」というご要望をプロジェクトの初期段階で頂いていたが、Salesforce の設計が完了しておらず、また完了時期も未定でお見積もりを作成できない状況だった。
- 予約の承認状態は、「仮予約申請中」、「上長承認済み」、「却下」など、合計10種類の状態が存在しました。さらに、「管理者」、「一般ユーザー」といったユーザー権限に応じて、それぞれ操作できる項目(予約の日程など)が異なるため、UIの全容を把握することが困難だった。
成果
- 第一フェーズでは DB に顧客情報を持たせ、第二フェーズで Salesforce と連携する方針を提案しご承諾頂きました。開発方針としては、API をフェーズごとにバージョンを分けて開発し、段階的に移行できる体制を作りました。
- チーム開発におけるコード品質と保守性の向上を目的とし、bullet proof react のアーキテクチャパターンを採用し、コーディング規約をドキュメント化することで、メンバー間で認識を統一しました。
features/featureAはfeatures/featureBに依存してはいけないなど、特定フォルダからのimportを禁止することで、依存関係が複雑化することを回避し、他の開発メンバーが実装されている場所を見つけやすい設計を実現しました。
工夫した点
- OpenAPI によるスキーマ駆動開発を導入し、
openapi-typescriptを利用して、定義したスキーマから TypeScript の型を自動生成しました。これにより、フロントエンドとバックエンドの開発を並行して進めることができ、作業の振り分けがスムーズになりました。また、API の仕様と型定義のずれが発生することを防ぐことができました。 - Storybook を採用し、全ての承認状態(10種類)の Story を定義することで、開発者は各々テストデータを用意することなく各状態の UI を確認できる体制を整えました。また、Storybook の Decorator と ArgTypes を利用して、ユーザー権限を切り替える仕組みを実装しました。これにより、実際にログインユーザーを切り替えることなく、動作検証する体制を作ることで、UI のテストに掛かる時間を削減することができました
技術選定について
プロジェクト初期の要件定義の段階で、下記の課題が存在し、フロントエンドの開発の重要性が高いと判断しました。
- 月・週表示を持つカレンダーやモーダル内フォームなど、インタラクションが豊富で複雑なUIの実装が求められており、jQuery や Stimulus では、これらの UI を品質と保守性を維持しながら実装するのは困難だと判断した
- フォームで扱うデータ構造が、配列内に配列が含まれるなど複雑だった
- 10種類にも及ぶ承認状態に応じてUIが変化するため、UIテストに多大な工数がかかることが予想された
これらの課題を考慮し、React の導入を検討し始め、他社の採用実績や、React の開発経験がある先輩のエンジニアがいる考慮して、React が最適であると判断しました。 TypeScript も併せて使用することで型安全性の恩恵を受けつつ、React の宣言的 UI の特性により複雑な UI をコンポーネント単位で管理することで、コードの見通しが良くなり保守性が向上できると考えました。 また、フォームの実装に関しては、 react-hook-form などのライブラリを活用することで、ネストされた配列などの構造が扱いやすくなると見込みました。さらに Storybook を利用し、承認状態ごとに UI を確認・テストできる環境を用意することで、テストに掛かる時間を削減できると考えました。 導入コストに関しては、フロントエンドとバックエンドを完全に分けるのではなく、mastdon のリポジトリを参考にしたモノレポ構成にすることで、Rails の資産(認証、ルーティング)を活かしつつ、React は部分的に適用することで導入コストが下げられると考えました。また、 状態管理については、Redux, Recoil, Zustand など多数の選択肢がある中で、本プロジェクトでは管理したいグローバルな状態がユーザーの認証情報と、Feature Flag の値と少ないかつ、今後も増えることもあまり無い判断し、React Context を採用することで学習コストを下げられると考えました。
助成金支援サービスの開発・運用
プロジェクト概要
中小企業向けに、補助金申請のプロセスを効率化し、採択率向上を支援するサービスの開発・運用に開発メンバーとして参画。運営者が作成した補助金申請の解説動画を視聴したり、コンサルタントとメッセージのやり取りをしながら経営者の助成金申請の書類作成をサポートする。 会員向けの機能の開発とインフラの構築を担当。
基本情報
| 規模 | 3名(自社2名,業務委託1名) |
|---|---|
| 役割 | メンバー |
| 担当 | コーディング インフラ構築 保守・運用 |
主な機能・業務
- Sendgrid を利用したメール送信機能
- コンサルの予約機能
- セキュリティチェックシート対応
- 外部からの攻撃対策として WAF の設定
- Fluent Bit を利用したログ基盤構築
- インフラ変更の迅速化と属人化防止を目的とした IaC の導入
課題
- セキュリティチェックシートの記入を求められ、特に管理画面へのアクセス制御とログ管理において厳格な対応が必要だった。
- 弊社はフルリモートだが管理画面へのアクセスにはオフィス内に専用のエリアを用意して、専用の端末からのみアクセスできるようにする、という物理的な制限を設ける必要があった
- 機微情報を含むログとそれ以外のログで保管期間が異なるため、ログの出力先を分ける必要があった(機微情報を含むログは7年間、それ以外は3ヶ月)
- インフラの変更の手順は全て文書化し、監査することが求められた
成果
- AWS Workspaces を経由したアクセスのみを許可する構成を構築し、管理画面への不正アクセスリスクを最小限に抑えることができました。
- Fluent Bit を活用し、ログ内の項目(例:ユーザーID、操作内容など)に応じてログを出力するログストリームを分け、機微情報を含むログストリーム内のログに関しては S3 にエクスポートする Lambda Function を月初に実行する仕組みを構築した。
- Terraform を用いた IaC を導入することで、インフラを手動で変更するのではなく、開発メンバーのレビューを経てデプロイできるワークフローを GitHub Actions で実現しました。これにより、いつ、誰が、どのような変更を実施したのか記録できるようになりました。
工夫した点
- lograge gemを使用して、Rails のログを json 構造に変換することで、CloudWatch Logs Insights を利用してログを検索しやすくしました。また、
Rails.logger.infoを利用した場合は lograge を使用しても json 構造に変換されないという問題があったため、ログフォーマッターを独自に実装しました。
社内ポータルサイトのリニューアル・運用
プロジェクト概要
社内報システムのリプレイス
社内報システムのリプレイスプロジェクトに、プロジェクトリーダー兼開発エンジニアとして参画しました。先方が社員マスタとして Okta を、ファイルの管理として Box を採用したため、それらのシステムと連携することと、新機能実装のためフルリプレイスすることとなりました。私は、入社1ヶ月目から本プロジェクトにアサインされ、顧客折衝から要件定義、設計、開発、テスト、リリースまでの一連の工程を担当しました。
主な機能・業務
- Okta 認証基盤の導入
- TinyMCE を活用した WYSIWYG エディタの実装と、記事内に挿入された画像の Box へのアップロード機能
- 記事公開時に、記事タイトルと本文を Slack の指定チャンネルに自動通知する機能の実装
- Ruby/Rails の最新バージョンへのアップグレード対応
基本情報
| 規模 | 2名(自社1名,業務委託1名) |
|---|---|
| 役割 | 開発リーダー |
| 担当 | • 設計・コーディング • インフラの移行 • 保守・運用 |
課題
- 前任者がおらずドキュメントもないシステムだったので、直接 DB を確認しないと設計の詳細が分からない状況だった
- データの冗長性と不整合を解消するため、テーブルを正規化しつつ、移行する必要があった
- サーバー上に保存されていた数千件の静的ファイル(画像、PDFなど)を全て Box へ移行する必要があった
成果
- 旧 DB の dump を新サーバーに転送し、新しいスキーマに反映する Rake タスクを実行することで、DB の移行を実現しました。
- 静的ファイルをまず新サーバーへ転送し、Box へアップロードする Rake タスクを実行することで、全ファイルの移行を完遂しました。
- EC2 上に Rails 環境を構築し、ALB と ACM を活用し、HTTPS 通信を実現しました。
工夫した点
- CircleCI で CI/CD パイプラインを構築し、単体テスト(RSpec)と結合テストの自動化、および Capistrano による本番環境への自動デプロイを実現しました。これにより、開発効率の向上と人為的ミスの削減を実現しました。
- 記事内の画像をBox へ移行する際、正規表現による抽出ではなく、Nokogiri を使用した HTML パース処理を採用することで、より堅牢な実装を実現しました。
- 先方からのご要望で、コスト最適化のため、1台の EC2 インスタンス上で Nginx によるバーチャルホストの設定を行い、ホスト名に応じて puma に振り分ける構成にして、ステージング・本番環境を同居させました。
業務外活動
| タイトル | 説明 | github | URL |
|---|---|---|---|
| timecrowd-tracker | Raycast Extension | https://github.com/machamp0714/timecrowd-tracker | https://www.raycast.com/machamp0714/timecrowd-tracker |