株式会社シムックスイニシアティブ / Webエンジニア
IoT Webサービス開発
【プロジェクト概要】 - プロジェクト規模: 3 ~ 4 人チームでのアジャイル開発(スクラム) 新規プロジェクト。立ち上げ当初から参画。 ビッグデータをもとにした様々なデータを、ブラウザにてグラフや表で閲覧できるwebアプリの開発。 仕様の複雑な部分に関しては開発チームのメンバーに相談することもありましたが、 基本的には設計からリリースまで一人称で開発を行いました。 【使用技術】 OS : Linux(CentOS7) Language : PHP(v7.4), Python, JavaScript Framework & Library : Laravel(v6.20), Django, CodeIgniter,(v2), jQuery DB : PostgreSQL, MongoDB Middleware : nginx, php-fpm, Apache, ApacheKafka, Redis IaC Tools : Ansible, Docker CI/CD Pipeline : Gitlab Runner, CircleCI Other Tools : phpmd, php-cs-fixer, ESLint, prretier, PHPUnit, Git, GitLab 【担当業務概要】 - 営業・企画チームとの要件のすり合わせ - APIを用いたWebサービスの開発 - 新規機能開発を担当 - 使用ライブラリの選定 - インシデント発生時の調査 - バッチ処理プログラムの作成 - プライベートクラウドを用いたインフラ構築 - Webサーバーの設定 - DB設計(NoSQL) - CI/CDパイプラインの構築& 運用改善 - 静的解析ツール、及びフォーマッターの導入 - PHPUnit を用いて単体テスト及び統合テストを導入 - 既存プロジェクトのclass設計を見直しリファクタリングを担当 - 新規プロジェクトにおいてDockerfile等を作成 - 新規メンバーに対する技術指導及び、コードレビューを担当 【担当業務詳細】 ## 営業・企画チームとの要件のすり合わせ 開発を進めるにあたって、プロジェクトが立ち上がった初期の頃から営業・企画チームと密にコミュニケーションをとり要件のすり合わせをおこなった。 本プロジェクトは仕様変更が度々発生したが、本サービスのソースコードの全体像を把握していたため、仕様変更に対しても柔軟に対応することができた。 また、実装を進める際にも、仕様変更が生じる可能性が低い部分から優先的に実装を行い、仕様変更が生じる可能性が高い部分は実装の優先度を下げるなどして、開発を行なった。 加えて、今後の仕様変更にも柔軟に対応するために、適宜リファクタリングを行いながら実装を進めた。 ## APIを用いたWebサービスの開発 RESTful APIを基本としてlaravelでのAPI構築を基本設計~リリースまで担当 jQueryを使用して、SPA構成のWebアプリを基本設計~リリースまで担当 ## 新規機能開発を担当 実装機能は以下の通りである。 ・温湿度データグラフ表示機能 ・温湿度データCSV出力機能 ・温湿度データPDF帳票出力機能 ・工場設備の使用電力量及び稼働データを可視化するためのグラフ表示機能 ・工場設備の使用電力量及び稼働データのCSV出力機能 ・PDF形式のレポート出力Webアプリケーションの新規開発 ブラウザにて「使用電力量のデータに関するCSVファイル」をアップロードし、アップロードされたデータをもとに、データを分析したり、グラフを生成したり、元データから算出されたデータ等をレポートに出力するという仕様であった。 ## 使用ライブラリの選定 「データグラフ表示機能」ではChart.jsというライブラリを選定し開発を行なった。 https://github.com/chartjs 「PDF帳票出力機能」ではTCPDFというPDF生成ライブラリを選定し開発を行なった。 https://github.com/tecnickcom/TCPDF 「PDF形式のレポート出力Webアプリケーションの新規開発」ではjpgraphというグラフ画像生成ライブラリを選定し開発を行った。 https://packagist.org/packages/amenadiel/jpgraph JpGraphというライブラリはネット上に公式ドキュメント以外のサンプルコードや参考文献が少なかったため、ライブラリ本体のソースコードを自分で読み解くなどをしてライブラリの挙動を適宜確認するなども行なった。 ## バッチ処理プログラムの作成 各機能にて必要となるデータを算出するためのバッチプログラムを作成した。 cronにて実行できるように設定。 ## プライベートクラウドを用いたインフラ構築 CentOS7をベースとして、プライベートクラウドにてサーバーの構築を担当 Webサーバー、バッチサーバー、DBサーバー、CICD専用サーバー等、Webアプリケーション開発を行う上で必要なサーバー構築を担当 また、IoTサービスでの使用事例がいくつか存在する、Pub/Sub形式でmessageのやりとりを行うためのMQTTサーバーの構築も担当した。 ## Webサーバーの設定 Webサービスを外部公開するための以下の諸設定を担当。 ``` Nginxの設定 DNSの設定 SSL/TLS証明書の取得及びWebサーバーへの設置 NAT及びファイアウォールの設定 serviceファイルの設定 ``` ## DB設計(NoSQL) mongoDBにてデータベースの設計を担当。 ビッグデータを扱うwebアプリケーションのため、コレクションに複合インデックスを貼りドキュメントの検索速度向上を実現した。 ## CI/CDパイプラインの構築& 運用改善 「gitlab runner」というgitlab専用のCICDツールを使用して、CICDパイプラインの導入から運用までを担当(静的解析及び、formatter実行、デバッグログ検知、自動リリースを実現) ## 静的解析ツール、及びフォーマッターの導入 git のpre-commitスクリプトを「bash scripts」で作成し、チームで共通して静的解析ツールとフォーマッターを使用できるようにした。 以下、使用したLInter 及びFormatterの一覧である。 PHP : PHPMD, PHP-CS-Fixer JaveScript : ESLint, Prettier ## PHPUnit を用いて単体テスト及び統合テストを導入 CIにて自動テスト実行環境を構築 全てのAPIに対して統合テストを導入し、既存ソースコードの改修及び、新規APIの追加がスムーズに行えるようになった。 # 開発時に遭遇した課題 ## APIの開発について 当プロジェクトで作成したAPIは大量のデータを返す仕様ということもあり、 APIを作成する際には、運用時に問題となりやすい以下の点を防ぐことを意識した。 * サーバーへの負荷 APIの設計によってはOS上のメモリに過剰な負荷がかかり、OOMを発生させる原因となる。 * APIのレスポンス速度の低下を防ぐ APIの設計によっては、レスポンス速度が大幅に低下してしまうことがある。 上記の問題点を防ぐために、以下の点を意識して設計・開発を行なった。 ・DBに投げるクエリ ・for文のネストを浅くする ・処理速度が遅いPHPの関数を使用しない ・バッチ処理を適宜利用する ・サーバー側でswap領域を利用する ・REST API のJSONデータのサイズを極力軽量なものにする 当プロジェクトは、社内の既存のソースコードを参考にして約1週間程度の工数でリリースを行なったものである。 リリース優先で実装を進めたが故に、非常に保守性が低い設計になっていたので、リファクタリングを行なった。 既存のAPIでは親クラスでグローバル変数を定義し、クラス内のあちらこちらのメソッド内で値を代入するようなソースコードになっており、グローバル変数がどのような使われ方をしているのか、 また、グローバル変数の中にどのような値が入っているのかを把握することが困難であった。 既存のソースコードの課題を踏まえて、グローバル変数を極力使わないように実装を行った。 クラス内の各メソッドについてもできる限りシンプルに保ち、後からソースコードを読んだ際に、それぞれの関数の挙動が理解しやすいような設計を行った。 #### 当プロジェクトで学んだこと 当プロジェクトのwebサービスを設計する上で、意識した点をこちらのqittaの記事にもまとめています。 https://qiita.com/takuyanagai0213/items/f05f701edd9011dbebe2 ## webアプリの設計について プロジェクト立ち上げ当初から、リリース優先で全体的な設計面がきちんとなされないまま、開発が進められていた。 保守性の向上を目的としてクラス設計面でのリファクタリングを担当した。 laravelのディレクトリ構成を見直し、設計思想についてはクリーンアーキテクチャーを参考にした上で行なった。 クリーンアーキテクチャのUseCasesの考え方を取り入れて、既存のMVCモデルに含めることが難しいデータの整形部分のロジックをUseCasesに所属させることで見通しの良い設計を実現した。 また、Webアプリ全体において、保守性を意識したディレクトリの再設計を行なった。 以下、Controller, UseCases, Models, Viewの当プロジェクトでの位置づけを箇条書きでまとめる。 ``` * Controller : APIの入口および出口の役割としての位置づけ * UseCases : Modelから受け取ったデータをリクエストに応じて整形する役割としての位置づけ * Models : DBからデータを取得することだけに特化させた役割としての位置づけ * View : html部分 ``` ## テストコードについて テストコードの実装が不十分であったため、既存のソースコードに対して改修を行う際にデグレを発生させてしまうことがチーム内でも時々発生した。リリース前の段階でデグレが発生していることを発見できるように全てのAPIに対して自ら統合テストを積極的に導入した。 CIにて自動テストの実行環境を構築することで開発チームのメンバーがリリース前に既存ソースコードのデグレに気づくことができるようになった。 ## CI/CDパイプラインの構築について 以前、デバッグログを含んだソースコードが本番環境にリリースされる事象が別プロジェクトにて発生したので、 その反省を活かして、マージリクエストでのレビュー時にデバッグログをCIにて未然に発見する仕組みを構築。 別プロジェクトにて本番環境へのリリース作業プロセスを社内の特定の人物しか知らないということがあった。 その反省を生かして、リリースプロセスの属人化を防ぐために、自動リリースの仕組み(CD)を導入した。 ※ プロジェクト内で導入したCI / CD パイプラインについてはこちらの記事にもまとめています。 https://qiita.com/takuyanagai0213/items/ce4169c72e10986eb16d ## 静的解析ツール、及びフォーマッターの導入 → PHPでは静的解析ツール「phpmd」とフォーマッター「php-cs-fixer」を用いた。 社内の別プロジェクトにて、静的解析ツールおよび、フォーマッターが一切使用されていないプロジェクトがあり、以下の点で非常に開発のやりづらさを感じた。 ・未使用変数及び、未使用関数の残存 ・クラス名や変数にて共通の命名規則が定められていない。 ・共通のフォーマットが使用されていないことによる可読性の低下 ・インデントやスペースのズレによるソースコードの読みづらさ プロジェクトの立ち上げ初期から、静的解析及び、フォーマッターを恒常的に実行することで、 後の改修や、機能追加の際の開発の進めやすさを担保するように意識した。 # キャッチアップした技術 結果的に本番環境での導入には至りませんでしたが、技術選定を行う過程で以下の技術をキャッチアップし、本番運用を想定してプロトタイプを作成した経験があります。 ## Golang (API開発) ⇨当プロジェクトのPHPで作成したAPIは大量のデータを送る仕様ということもあり、 APIのレスポンスが非常に遅いという課題があったため、課題解決のためにGolangに目をつけて、APIの実装を行なった。 ## Vue.js (SPA開発) 現状、jQueryを用いてSPA構成のフロントエンド開発を行なっており、Vue.jsやReact.js等を用いた開発が本格的に行えていなかったため、Vue.jsを用いてSPA構成のソースへのリプレイス作業を行なった。 本番運用への導入は実現しなかった。