読者です 読者をやめる 読者になる 読者になる

struct に static method は必要か?

golang を触りたての頃、struct に static method を実装したいと思った。

なぜかというと、
1つの package に function をずらーっと定義すると、
なんだか冗長な命名になってしまうから。

util.UserXxx()
util.TeamXxx()
util.EventXxx()



package を切って、以下のようにしても良かったのだが、
package 名が重複して import の時にエイリアスを付けるのが面倒だった。

user.Xxx()
team.Xxx()
event.Xxx()


理想としては、以下のようにしたかった。

util.User.Xxx()
util.Team.Xxx()
util.Event.Xxx()



今思うと、
これは以下のようなクラス単位で static method を生やすイメージで、
クラス単位で管理する思想に引きづられているように思える。

<?php
class User {
    public static function Xxx() {

    }
    public static function Yyy() {

    }
}

class Team {
    public static function Xxx() {

    }
    public static function Yyy() {

    }
}


そして、それに近いことができることを知って、
このように static method を書いてた時期もあった。
http://qiita.com/Jxck_/items/547f1c16669f91cc9c29


ただ、最近はこういった書き方をしなくなった。


理由としては以下。

1.golang の言語仕様に沿った方が良いと思ったから

そもそも golang では struct に static method を持たせることができないので、
無理やり持たせるのってそもそもおかしいのでは? と思った。
golang の struct と他の言語のクラスを同じようなイメージで利用するのは正しくない気がする。

2.「package の中の package」のような妙な領域が発生するから

以下のコードを見ると、util package の中に User, Team, Event という領域が存在するように思える。
こうなると、1つの package が持てる責務が大きくなってしまう可能性がある。

util.User.Xxx()
util.Team.Xxx()
util.Event.Xxx()

3.method 内で method を呼ぶときの呼び方に違和感があるから。

以下のように util.User から yyy() を呼ぶこともできるし、

func (_ User) Xxx() {
    return util.User.yyy()
}

func (_ User) yyy() {

}

以下のように receiver からも呼ぶことができる。

func (u User) Xxx() {
    return u.yyy()
}

func (u User) yyy() {

}



実体は struct なので、こういった書き方ができてしまう。
自分はここに違和感を感じる。
利用する側が static method っぽい書き方になるだけで、
struct 本来の使い方を見失っているように思える。


今はどうしてるのか?

ということで、最初に以下が理想だと言ったが、

util.User.Xxx()
util.Team.Xxx()
util.Event.Xxx()

現在は結局以下のように package を分けて定義したり・・・

user.Xxx()
team.Xxx()
event.Xxx()



prefix, safix を付けるようにしている。

util.UserXxx()
util.TeamXxx()
util.EventXxx()



package を分ける場合、
user, team, event という package が import で重複したら、
エイリアスを付ける。
面倒だけど・・・。

このように function を定義していくと、
package 内に User, Team, Event という「package の中の package」のような妙な領域は発生しないので、
1つの package の責務が肥大化する可能性が低くなる。
その package に属するのが自然になるように function として定義するのが一番だと思う。

仮に package 内に function が増えてきてゴチャゴチャしてきたら、
それは package を分割した方がいいというサインかもしれない。

ちなみに、標準 package とDockerのコードをサラッと grep したけど、
struct に static method を持たせるような実装は見当たらなかった。
*存在したら教えてください

今まで自分が触ってきた「クラスベースの private が当たり前だった言語」と同じように考えると、
struct に static method を持たせたくなるが、
struct に static method を持たせることはできないし、
golang は package private が基本になる。
package ベースで考えることで、
本来あるべき golang のコードに近づくかもしれないですね。

ちなみに、今回は util という package を例にしましたが、
「そもそも何でも突っ込める感じのする util みたいな package を用意することのはどーなの?」
というのはありますね・・・。
ちょっといい例が思いつかなくて・・・。