【Java】DIコンテナ使用時の「K&Rスタイル VS Allmanスタイル」+ パラメータのインデントスタイルについて

徒然草2.0
Document Management System (DMS) being setup by IT consultant working on laptop computer in office. Software for archiving, searching and managing corporate files and information. Business processes

まずはじめに、K&RスタイルとAllmanスタイルの違いに触れる前に、少しだけ実感ベースの話をさせてください。

Javaで依存性注入を用いたメソッドを書いていると、インデントが揃っていないように見えて非常に気持ちが悪く感じることがあります。

K&Rスタイルは、C言語の生みの親であるカーニハンとリッチーのスタイルで、AllmanスタイルはUNIXやsendmailの開発に携わったエリック・オールマンというプログラマの書き方に由来します。両者の違いはたった一つ、関数(やメソッド)の中括弧 {} を改行するかどうかです。

  • K&Rスタイル:中括弧を改行せずに関数宣言の行の末尾に書く

  • Allmanスタイル:中括弧を次の行に改行して書く

このわずかな違いですが、見た目の印象は意外と大きく変わります。

K&Rスタイルの利点は、行数を節約できる点にあります。関数が比較的短く、数が多い場合や、縦に長くない端末でコードを表示する場合にはスッキリして見やすいでしょう。一方、Allmanスタイルは行数は多くなりますが、中括弧が縦方向に揃うため、ネストが深いコードでも構造が把握しやすく、見間違いを防げるというメリットがあります。

個人的には、コードの複雑さに応じてスタイルを使い分けるのが理想だと考えています。単純な処理が並ぶコードならK&Rスタイルで情報密度を高め、複雑で注意深く読まなければならないコードにはAllmanスタイルを適用する。そうすることで、見やすさと実用性のバランスが取れると思うのです。

しかし現実には、多くのプロジェクトではスタイルの使い分けを好まず、コーディング規約によって統一することが一般的ではないでしょうか。

特にJavaのプロジェクトでは、K&Rスタイルに従うのがほぼ既定路線であり、おそらく9割以上がこのスタイルを採用しているのではないでしょうか。

私自身はJavaの世界に深く精通しているわけではありませんが、少なくともJavaの書籍でAllmanスタイルを使って書かれたコードは見たことがありません。Allmanスタイルを使うプログラマは特にJavaプログラマにとっては、かなり少数派と言っていいでしょう。

C系やその他の言語では見かけることもありますが、Javaにおいては極めて珍しいはず。組み込み系など、少人数で開発している現場であれば、逆にAllmanスタイルが根付いているケースもあるのかもしれません。

というわけで具体的にSpling boot 3にありそうなJavaのソースコードを見てみましょう。

 

【K&Rスタイル】Java(Spring boot3)のコード例

UserService.CreateUser Methodに、

Repository、Validator、EventPublisherをDIしている、

よくある感じのソースコード↓

@Service
public class UserService {

    private final UserRepository userRepository;
    private final EmailValidator emailValidator;
    private final ApplicationEventPublisher eventPublisher;

    public UserService(UserRepository userRepository,
                       EmailValidator emailValidator,
                       ApplicationEventPublisher eventPublisher) {
        this.userRepository = userRepository;
        this.emailValidator = emailValidator;
        this.eventPublisher = eventPublisher;
    }

    public User createUser(String name,
                           String email,
                           String password,
                           Optional<String> phoneNumber,
                           boolean subscribeToNewsletter) {
        if (!emailValidator.isValid(email)) {
            throw new IllegalArgumentException("Invalid email");
        }

        User user = new User(name, email, password, phoneNumber.orElse(null));
        userRepository.save(user);

        if (subscribeToNewsletter) {
            eventPublisher.publishEvent(new NewsletterSignupEvent(user));
        }

        return user;
    }
}

【Allmanスタイル】Java(Spring boot3)のソースコード

同じく、

UserService.CreateUser Methodに、

Repository、Validator、EventPublisherをDIしている、

よくある感じのソースコード↓

@Service
public class UserService
{

    private final UserRepository userRepository;
    private final EmailValidator emailValidator;
    private final ApplicationEventPublisher eventPublisher;

    public UserService(UserRepository userRepository,
                       EmailValidator emailValidator,
                       ApplicationEventPublisher eventPublisher)
    {
        this.userRepository = userRepository;
        this.emailValidator = emailValidator;
        this.eventPublisher = eventPublisher;
    }

    public User createUser(String name,
                           String email,
                           String password,
                           Optional<String> phoneNumber,
                           boolean subscribeToNewsletter)
    {
        if (!emailValidator.isValid(email))
        {
            throw new IllegalArgumentException("Invalid email");
        }

        User user = new User(name, email, password, phoneNumber.orElse(null));
        userRepository.save(user);

        if (subscribeToNewsletter)
        {
            eventPublisher.publishEvent(new NewsletterSignupEvent(user));
        }

        return user;
    }
}

まとめ + 引数(パラメータ)のスタイルについて

さて、どちらのほうが見やすかったですか?

自分の書き慣れたスタイルがいいという、スタイル愛着バイアスの影響を無視すれば、またモニタが大きめの人はAllmanの方が見やすいのではないでしょうか?まあそれはいいとして⋯、Spling boot 3に不慣れな私にとってはもう1つ気になるところがあります。

それは、引数が1つずつ改行されているところガタガタじゃね?問題です。コンストラクタのUserServiceメソッドの引数と、createUserメソッドの引数のインデントが左側を起点にするとガタガタなように個人的には感じて気持ちが悪いです。

しかし、これがJavaプログラマ界隈でもっとも使われる書き方のようで、記事の上に書いたソースコードはこの書き方をしています。

カッコの開始位置にそろえる「Aligh with opening parenthesis」

最初の引数の頭にあわせてインデントをいれることで見やすいそうです。たしかに上の引数を基準に並んでいる用に見えますがそもそも他のインデントはエディタの左側のラインを基準にするので、合っている感じがしないのですが⋯

と私のように考える人もいるのか、左側のラインに合わせる書き方もあるようです。

インデントレベルで改行をいれる

4スペース(または1タブ)か8スペース(2タブ)をいれて左側のラインに合わせる方法もあるそうです。とりあえず上のパラメータに合わせるか左側のラインにそってインデントを加えるか、2つのパターンがあるようです。

最後に

最終的にはなれるしかないのでしょうが、クラスを多層化して依存性をパラメータとして渡す昨今のアーキテクチャが主流になるならば、この変はプログラム言語の仕様を変えるなりしてももっと見やすく分かりやすくスッキリした感じにならないのかな?というのが個人的な感想になります。

言語仕様で書き方を縛るのはどうか?と思う一方、Pythonは「Aligh with opening parenthesis」という書き方ができないためPEP8ではカッコの直後で改行し4スペースでインデントをするスタイルです。(厳密には「Aligh with opening parenthesis」でも文法エラーにはならないようです)

徒然草2.0
スポンサーリンク
シェアする
gomiryoをフォローする
ごみぶろぐ

コメント

タイトルとURLをコピーしました