セキュリティ、保守性、そして同時性制御

今回の記事では、プロジェクトの品質を一段階高めるために進めたリファクタリング過程を共有します。データベース接続情報を安全に保護する暗号化作業から、フロントエンドコードの重複を除去するモジュール化、そして頻繁なデータ更新状況での同時性制御処理方法を紹介します。

1. Jasyptを活用した機密情報の暗号化

開発を進めていくと、データベースURL、ユーザー名、パスワードなどの機密情報がapplication.yamlファイルに平文で露出される場合が多くあります。これはセキュリティ上大きな脆弱性となり得るため、Jasypt (Java Simplified Encryption) ライブラリを導入して解決しました。

従来広く使われていたPBEWithMD5AndDESアルゴリズムは、現在の基準ではセキュリティ強度が十分ではありません。そこで私たちは PBEWITHHMACSHA512ANDAES_256 アルゴリズムを適用してセキュリティ性を大幅に強化しました。また、暗号化キー(Master Key)はソースコード内部に置かず、実行時点の環境変数やVMオプションで注入されるように設定し、コードが流出しても復号化が不可能な構成にしました。

テスト環境でもこの設定を同一に維持するためにReflectionTestUtilsを活用します。JasyptConfigの設定をテストコードで再利用することで、暗号化および復号化の整合性を保証できます。

2. Thymeleaf Fragmentを利用したビューのモジュール化

投稿リスト(index.html)と詳細ページ(viewer.html)を開発していると、投稿を表示するUIコードが必然的に重複します。このような重複は、デザイン変更時に複数のファイルを修正しなければならない煩雑さを生み、保守性を低下させます。これを解決するためにThymeleafのFragment機能を活用して共通部分をモジュール化しました。

  • postitem.html: リストで使用される投稿ボックスコンポーネント

  • postview.html: 詳細ページの本文領域コンポーネント

  • post/common.html: いいね、リツイート(枝刈り)、共有ボタンなど下部共通領域

UIだけでなく、handleLikeなどのJavaScript関数も別の外部JSファイルに分離しました。結果として、UIやロジックの修正が必要な時に1箇所だけ変更すればすべてのページに即座に反映される効率的な構造を整えました。

3. JPAを活用した同時性問題の解決とパフォーマンス最適化

3.1. アトミック(Atomic)更新による同時性制御

「いいね」数や「ブランチ」数のように頻繁に更新されるフィールドは、同時性問題が発生しやすい地点です。Javaアプリケーションレベルで値を照会して1を加えて保存する方式(entity.setCount(count + 1))は、同時に複数のリクエストが流入した場合、データ損失(Lost Update)につながります。

この問題を解決するため、JPAの@Modifyingアノテーションを使用してデータベースレベルで直接UPDATEクエリを実行するように変更しました。


UPDATE post SET like_count = like_count + 1 WHERE id = ?

この方式は、データベースのロック(Lock)メカニズムを自然に活用してデータの整合性を保証します。注意すべき点は、更新クエリ実行後にpostRepository.save(entity)を呼び出してはいけないということです。永続性コンテキストに残っていた変更前の値がDBの最新値を上書きする危険性があるためです。

3.2. メソッド名規則を活用した明確なクエリ生成

子投稿を照会するロジックでは、JPAのメソッド名規則の中でProperty Traversalを積極的に活用しました。

  • findAllByParentPost_Id: アンダースコア(_)は非常に重要な役割を果たします。Postエンティティ内部のparentPostオブジェクトを探索し、その中のidフィールドを条件として使用することをJPAに明確に伝えます。これにより、フィールド名が重複したり、複雑な関連関係でも曖昧性のないクエリを生成できます。

3.3. 必要なカラムのみ照会(Projection)

単純にいいね数(Long)1つが必要な状況でエンティティ全体を照会することは、不必要なリソースの無駄です。これを最適化するために@Queryを使用して必要なフィールドのみを照会するように変更しました。


@Query("SELECT p.likeCount FROM Post p WHERE p.id = :id")

Long findLikeCountById(Long id);

JPAの基本メソッドであるfindBy...はエンティティ全体照会を実行するため、特定のタイプの戻り値が必要な時は上記のように明示的なクエリ作成が必須です。


今回のリファクタリングによりアプリケーションのセキュリティ性を確保し、重複コードを除去して保守効率を高めました。何よりも同時性環境でもデータが正確に管理される堅固な基盤を整えました。

リンク:
リンク: » 韓国語で見る (한국어로 보기)
リンク: » 英語版を見る (Switch to English)
シェア: