【ゴールデンウィーク営業のお知らせ】
2025年4月29日(火)~2025年5月6日(火)の期間を休業とさせていただきます。
※4月30日(水)、5月1日(木)、2日(金)は通常営業いたします。
※休業期間中にいただいた審査申請については、結果をお返しするために数営業日いただくことをご了承ください。
会社のチームやプロダクトのコミュニティーに影響力のあるエンジニアになりたい。
私自身の情報発信力を高め、影響力のあるエンジニアになりたい。
私自身多くの技術サイトやOSS、カンファレンスの発表等を参考にしているため、自分でプロダクトを作る以外にも、OSSに貢献したり、登壇等を行って、社会(特にプログラマ)に貢献していきたい。
私の会社は新規立ち上げから3年の事業部で、先輩方は皆さん社会人2年目という特殊な環境です。
そんな中新卒入社から2ヶ月後、それまで対話AIを構築していた先輩が退職し、自然と引き継ぐ形に。
しかし構築されていたのは php - socket - pythonソケットサーバ(1つのpathごとにsocketサーバーを建てる)という構成で、並列処理も実装されていない状況だったため、自分の作成していた対話AIの更新とともにシステムをフルリプレイスしましょうと提案しました。ちょうど製品版を制作していこうという流れもあり、企画、設計からやり直すことになりました。
リソースの関係で、サイトを構築できる人がRailsしか扱えなかった
-> Railsの管理サイトのまま、AIのAPIは完全にアプリケーションサーバとするようにしました。
GItがソースコード置きのような使われ方をしていた
-> 先輩方にgitコマンドを一通り教え、複数人開発を可能にしました。
無秩序な開発
-> あまり開発ルールなどが整備されてこなかったからなのか、先輩方の開発方法や環境がバラバラだったため、VSCodeを勧めたり、リーダブルコードを勧めたり、Pythonプロジェクトにはフォーマッタを導入しました。
対話AIが「誰でも文言を変更でき、いつでも学習でき、いつでも返答を行える」という要件
一般的なAIシステムとは異なり、AIをだれでも作成できるシステムだったため、学習済のモデルを複数ロードする必要がありました。しかし返答部を並列処理で動かすとkerasのバグが・・・。詳細には、kerasは学習済モデルからモデルをロードする際にtensorflowのグラフを展開するのですが、グラフを展開するスレッドと推論を行うスレッドは同じでなくてはならないとのことでした。その事が判明してからは返答部の並列処理には問題はなかったのですが、稼働中に学習を行うとスレッドが変わってしまうという挙動のため、最終的には学習サーバーと返答サーバーを分離し、学習済ファイルを送信することで解決しました。
他にも、前々から問題であった同時学習リクエストによりサーバーがビジー状態になってしまう問題は、キューシステムを作成し、同時AIへの複数の学習リクエストは最後のものが適用されるようなシステムを作成し負荷を軽減しました。
返答APIの構築
先述のように、返答APIは複数の学習モデルをプレロードしておく必要がありました。最初はmod_wsgiを利用してapacheから呼び出していたのですが、しばらくリクエストがない場合mod_wsgiのworker が停止してしまうと、再度リクエスト時にすべてのロードが行われレスポンスに時間がかかっていました。解決策として、gunicornでflaskアプリケーションを起動しておくことでworkerの停止問題は解決しました。また、アプリが常時起動している場合にモデルファイルが更新された場合のことを考え、モデルを管理するオブジェクトクラスがファイルの更新を管理するようにし解決しました。
もともとあった企画が前任者の退社で進んでいなかったところ、再度開発しようという流れになりました。しかし前任者の残していったものはセキュリティ面でもシステム面でもそのまま利用できるものではなかったため、再度企画、設計から行うことに。パッケージ商品とのことだったので、Googleカレンダーと連携した受付システム+管理サイトを作成することになりました。
開発人員が2人
-> アプリケーションエンジニア(1人)と私しかリソースがないにも関わらず社内利用できるデモ版の開発期間は2ヶ月とすこしという状況だったため、私がフロントエンドも開発することに。そのためDjangoおよびHTML/CSS/JSをプライベートの時間で勉強し、開発を行いました。管理サイトが用意されているDjangoおよびDjangoのモデルとすこしのserializerを書けばAPIが完成するDjango rest frameworkを用いることで、工数を削減しました。
開発サーバーがない
-> 利用できるサーバーが現行で動いているデモ用サーバーのみだったため、総務担当の方に掛け合い、会社の余ったPCにLinuxを導入、Dockerも利用し開発を進めました。CentOSイメージ上に本番とほぼ同じ環境を構築し、本番デプロイをスムーズにしました。また開発環境をdocker-compose一発で立ち上げられるようにし、開発環境を共有できるようにしました。
OAuth2連携部分
GoogleAPIとの連携にOAuth2を用いたのですが、Django-allauthというOSSパッケージを利用していたところ、特定の条件でaccessTokenが空になってしまう挙動にハマりました。そのため、認可フローを自力実装しました。
通知システム
Windowsアプリへの通知システムには即時かつ双方向性のある通知システムが必要だったことから、Redis Pub/Sub機能を用いました。通知機能のメッセージ送信を担保するため、受信者の受信を確認する通知を送る仕様にし、メッセージ送信機能を担保しました。
テストコード
残念なことに、私の上司はテストを書くこと=めんどくさいこととしか思っていないようでした・・・。私は自分のプロダクトの品質を担保したいという思いからテストコードを書くことにしました。フロント部分までは書けませんでしたが、APIやモデル(DB)、ビュー、フォーム等は一通りテストコードを書いています。メインの機能にはボリュームテストも記述しました。
APIドキュメント
モバイルアプリやWindowsアプリとの連携が必要になり、コミュニケーションコスト削減のためAPIドキュメントをSwagger文章にし、開発サーバに連携しテストできる環境を構築しました。SwaggerサーバはDocker内のnode.jsサーバで、ローカル環境に構築しました。Docker Volumeを利用して開発環境のAPIドキュメントをコンテナと共有し、常に最新のドキュメントが反映されるようにしました。
モバイルファースト
実はこのプロジェクトは一通り完成後紆余曲折を経てまた振り出しに戻り、現在も開発中なのですが、現在はモバイルファーストでサイトを構築しています。scssも利用して開発中です。
このプロジェクト詳細は公開されていません
アウトプットは主にQiitaのみだったが、自分のアウトプットをまとめたブログを持ちたいと思い、Markdownブログを作成。Next.js+Nowで構築。
URL: https://nextblog.ragnar1904.now.sh/
Next 9.3のアップデートからgetStaticPropsというSSG向け機能が実装され、表示の高速化を行えた。
アップデート当日に実装、アウトプットを行いました。
URL: https://qiita.com/ragnar1904/items/9973ac601332c33758a2
markdownのみではサイト構築に限界があったため、GraphQLバックエンドに移行しました。