“Preemptive interface Anti-Pattern in Go” とは？

# はじめに

`Go`には`Preemptive interface Anti-Pattern in Go`という考え方があります。

https://medium.com/@cep21/preemptive-interface-anti-pattern-in-go-54c18ac0668a

私はこちらの記事を読み初めて知りました。

ただ、原文を読んだだけでは理解が難しかったので自分なりに手を動かして自分の言葉で整理してみたのが本記事の内容となります。
英語力に自信がなく、自動翻訳の力を借りています。また、間違っている可能性もあるため真の情報としては原文のご確認をお願いします。
（本記事の内容が間違っていたらご指摘のほどお願いします。）

# TL;DR

- `Preemptive Interface`という実装パターンがあります。
- `Java`のような`interface`を明示的に継承させる必要がある言語では有効となります。
- `Go`では`interface`は暗黙的に継承されるのでそこまで有効ではありません。

# `Preemptive Interface`とは？

そもそも`Preemptive Interface`とはどのような実装パターンなのでしょうか？
強引な訳かもしれませんが、日本語では「先走ったインターフェイス」と言えるでしょうか。
実際に`interface`が必要かどうか判明する前にあらかじめ`interface`を実装するパターンとなります。
噛み砕いた表現をすると、「とりあえず`interface`用意しておいた方が無難だよね」という感じでしょうか。

以下のような実装が`Preemptive Interface`となります。

```go
type IUser interface {
  Hello() error
}

type User struct {}

func NewUser() IUser {
  return User{}
}

func (u User) Hello() error {
    return nil
}
```

これが`Go`においてはアンチパターンとなる場合があるのだということです。
どういうことなのでしょうか？

# なぜとりあえず`interface`を用意しておきたくなるのか

実際に`Java`と`Go`のコードを実装してとりあえず`interfae`を用意しておきたくなる理由を紐解いてみます。

以下のような機能を有した実装がすでにあったと仮定します。

- `bool`を返す`CanAction()`という`Auth`型があります。
- `Auth`型を引数に持つ`TakeAction(a Auth)`というメソッドがあります。

この`TakeAction(a Auth)`関数の引数を`interface`にして汎用性を高めたくなりました。
修正の目的としてはテストを実施する際にMockが使いたくなったとかになるでしょうか。

では実際の実装を用いて`Java`と`Go`を比較していきます。
なるべく比較しやすいように`Java`と`Go`が似たような実装になるようにしています。
原文とは異なる実装を用いていること、ご了承ください。

## `Java`

まずは`Java`から見ていきます。

### Sample実装(修正前)

Auth.java
```java
package auth;

public class Auth {
    public boolean canAction() {
        return true;
    }
}
```

Logic.java
```java
package logic;

import auth.Auth;

public class Logic {
    public void takeAction(Auth auth) {
        if (auth.canAction()) {
            System.out.println("take action");
        }
    }
}
```

Main.java
```java
import auth.Auth;
import logic.Logic;

public class Main {
    public static void main(String[] args) {
        final var auth = new Auth();

        final var logic = new Logic();

        logic.takeAction(auth);
    }
}
```

### Sample実装(修正後)

Auth.java
```java
package auth;

import iauth.IAuth;

public class Auth implements IAuth {
    public boolean canAction() {
        return true;
    }
}
```

IAuth.java
```java
package iauth;

public interface IAuth {
    public boolean canAction();
}
```

Logic.java
```java
package logic;

import iauth.IAuth;

public class Logic {
    public void takeAction(IAuth auth) {
        if (auth.canAction()) {
            System.out.println("take action");
        }
    }
}
```

Main.java
```java
import auth.Auth;
import logic.Logic;

public class Main {
    public static void main(String[] args) {
        final var auth = new Auth();

        final var logic = new Logic();

        logic.takeAction(auth);
    }
}
```

### 変更点

- `IAuth`を追加
- `takeAction`の引数を`Auth`から`IAuth`に変更
- `Auth`に`implement Auth`を追加

## `Go`

続いて`Go`の実装を見ていきます。

### Sample実装(修正前)

auth.go
```go
package auth

type Auth struct{}

func NewAuth() Auth {
	return Auth{}
}

func (a Auth) CanAction() bool {
	return true
}
```

logic.go
```go
package logic

import (
	"log"
	"preemptive-interface/auth"
)

type Logic struct{}

func NewLogic() Logic {
	return Logic{}
}

func (l Logic) TakeAction(auth auth.Auth) {
	if auth.CanAction() {
		log.Println("take action")
	}
}
```

main.go
```go
package main

import (
	"preemptive-interface/auth"
	"preemptive-interface/logic"
)

func main() {
	a := auth.NewAuth()

	l := logic.NewLogic()

	l.TakeAction(a)
}
```

### Sample実装(修正後)

auth.go
```go
package auth

type Auth struct{}

func NewAuth() Auth {
	return Auth{}
}

func (a Auth) CanAction() bool {
	return true
}
```

iauth.go
```go
package iauth

type IAuth interface {
	CanAction() bool
}
```

logic.go
```go
package logic

import (
	"log"
	"preemptive-interface/iauth"
)

type Logic struct{}

func NewLogic() Logic {
	return Logic{}
}

func (l Logic) TakeAction(auth iauth.IAuth) {
	if auth.CanAction() {
		log.Println("take action")
	}
}
```

main.go
```go
package main

import (
	"preemptive-interface/auth"
	"preemptive-interface/logic"
)

func main() {
	a := auth.NewAuth()

	l := logic.NewLogic()

	l.TakeAction(a)
}
```

### 変更点

- `IAuth`を追加
- `takeAction`の引数を`Auth`から`IAuth`に変更

# `Java`と`Go`を比較

一見すると言語仕様に応じて`Java`では`implements`を用いて明示的に継承しているが、`Go`では暗黙的に継承（ダックタイピング）であるかくらいの違いしかありません。
これだけだとそこまで修正に対してコストが変わらないように感じます。
しかし、ある状況下だと`Java`ではこの修正が簡単にはいかないことがあります。

**私(あなた)** が`Logic`の実装者で`Auth`を **別の方** が実装しているとします。（私(あなた)が簡単に`Auth`を修正できない状況です。）
このとき`Logic`を上記で実装したように修正した場合、`Auth`実装者に「`implements`を用いて継承するようにしてください」と連絡/同意をする必要があります。
でないとビルドが通らなくなります。（`Main.java`でビルドエラーが発生し破壊的変更となります。）
このような事態が`Java`では発生するため、あらかじめ`interface`を用意しておく`Preemptive Interface`が有効と言えます。

一方、`Go`の場合はというと暗黙的な継承（ダックタイピング）となるため`Logic`実装者が一方的に上記のような修正を行なうことができます。（`main.go`のビルドは落ちず、後方互換性を保つことができ破壊的変更にはなりません。）
そのため、`Go`では`Preemptive Interface`はアンチパターンですよ。ということになるのですね。
≒ そんなことをしておかなくてもあとで**簡単に変更ができます**。不要なものはなるべく作らない。YAGNI原則ですね。

# おわりに

原文の終盤では`Preemptive Interface`を用いるとメソッド数が増加する傾向にあると言及されています。
クリーンアーキテクチャにおける`Usecase`と`Repository`の関係性などを思い浮かべるとよいでしょうか。

一般的に`interface`はシンプルである(メソッドが少ない)方が有利な点が多いかと思います。
シンプルになったりDIがしやすくなったりといったメリットが挙げられるでしょうか。

`Go`の標準パッケージでも`interface`のメソッドは1つないし2つが一般的なコードとなっています。

https://go.dev/doc/effective_go#interfaces

こちらは`Go`での`Accept Interfaces, return structs`という考え方を整理することでもう少し理解しやすくなる内容かと思います。
（`Accept Interfaces, return structs`は日本語での記事も多数あるのでそちらを参照ください。機会があれば私も整理するつもりです。）

https://bryanftan.medium.com/accept-interfaces-return-structs-in-go-d4cab29a301b

実際に`Java`と`Go`を比較し`Preemptive Interface`を確認したことで`Go`らしさを確認できたと思います。

一方でプロダクトコード開発において今回のように`struct`が引数に与えられていてそこから修正するというシチュエーションに遭遇するのか？という疑問も持ちました。
比較的Mockを利用したテストを想定してコーディングするために最初から`Preemptive Interface`で実装することも多いかと思います。

`Go`らしさとプロダクトコード開発のバランスについてはまだまだ理解できていないので今後もいろいろと整理していきたいです。