[Java] どこで実装をするかで可読性が異なった話

はじめに

こんにちは、新卒1年目の岡崎です。エキサイトホールディングス Advent Calendar 2023の25日目を担当します。

最近、記事に対する画像URLの変換処理を実装しました。この実装をどこでするかで可読性が異なったので、備忘録として記事に残します。

環境

openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment Temurin-17.0.2+8 (build 17.0.2+8)
OpenJDK 64-Bit Server VM Temurin-17.0.2+8 (build 17.0.2+8, mixed mode)
.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.6)

前提

記事が持っている画像に対して、仕様変更で画像URLの変換処理が必要になったと仮定します。

改善前の実装

画像用の処理を集約したImageComponentクラスに、画像URLの変換を行う処理がありました。これをService層で呼び出して変換を行うと、以下のような実装になります。

@Service
@RequiredArgsConstructor
public class SampleService {
    private final SampleRepository sampleRepository;
    private final ImageComponent imageComponent;

    public ArticleModel getArticle(final String articleCode) {
        return this.convertImageUrl(sampleRepository.findArticle(articleCode));
    }

    /**
     * 画像URLの変換処理を行い、記事にセットする
     *
     * @param articleModel 記事
     * @return 画像URLの変換処理を行い、セットした記事
     */
    private ArticleModel convertImageUrl(ArticleModel articleModel) {
        final String imageUrl = imageComponent.convertImageUrl(
                articleModel.getImageUrl()
        );

        articleModel.setImageUrl(imageUrl);

        return articleModel;
    }
}
@Repository
@RequiredArgsConstructor
public class  SampleRepository {
    private final SampleMapper sampleMapper;
    private final ModelMapper modelMapper;

    public ArticleModel findArticle(String articleCode) {
        // DB等から記事をとってくる処理
        Article article = sampleMapper.findArticle(findArticle(articleCode));

        return modelMapper.map(article, ArticleModel.class);
    }
}
@Data
public class ArticleModel {
    private String articleCode;

    private String imageUrl;
}
public class ImageComponent {

    public String convertImageUrl(String imageUrl) {
        // ここで画像URLの変換処理を行う
    }

}

このコードには問題点があります。それは、Service層で画像URLの変換処理を行なってしまうことです。

この実装では、Modelの構造が複雑になるほど、Service層の可読性が低下します。
現在のModelは複雑ではありませんが、Modelの構造が複雑になるにつれて、Service層で行う変換処理が増えてしまいます。この結果、Service層の複雑性が高まってしまい、可読性の低下を招いてしまいます。

改善策

それでは、どうしたらいいのでしょうか。

改善策の一つは、Model内で実装をすることです。実装例を以下に示します。

@Data
public class ArticleModel {
    private String articleCode;

    private String imageUrl;

    public String getImageUrl() {
        return ImageComponent.convertImageUrl(this.imageUrl);
    }
}
@Service
@RequiredArgsConstructor
public class SampleService {
    private final SampleRepository sampleRepository;

    public ArticleModel getArticle(final String articleCode) {
        return sampleRepository.findArticle(articleCode);
    }
}

Model内で画像URLの変換処理を実装することで、Modelを作るタイミングで変換処理を実行できます。前述した実装のように、いちいちModelを分解して、セットし直す必要はなくなります。

まとめ

今回の場合、Modelに閉じ込めることができる処理を、わざわざService層でやろうとしたことが問題でした。同じような処理でも、どこに実装をするかで可読性は変わることがあります。実装をする時は愚直にやるのではなく、どこに実装をすれば最善なのかを考えて行う必要だと改めて感じました。

また、この記事は、先輩エンジニアのMさんが指摘して下さった内容で書いています。Mさん、今回もありがとうございました!精進します。

最後に

最後に、エキサイトではデザイナー、フロントエンジニア、バックエンドエンジニア、アプリエンジニアを絶賛募集しております!

興味があればぜひぜひ連絡ください!

www.wantedly.com