Mein io.Reader und io.Writer Interface

Dieser Post beschäftigt sich mit einer Möglichkeit des Refactorings, wenn externe Interfaces als Input von Funktionen verwendet werden. In dem Beispiel verwende ich den io.Reader da dieser sehr einfach aufgebaut ist und außerdem dürfte dieser Reader bereits von jedem Gopher schon öfters verwendet worden sein.

Fangen wir mal ganz einfach mit einer Funktion an:

import (
	"io"
)

func leseWas(r io.Reader) {
    // ...
}

Die Funktion leseWas nimmt einen io.Reader als Input und macht etwas damit. Wenn ich diese Funktion definiere und wirklich nur den io.Reader verwende, dann muss trotzdem das komplette io Paket importiert werden. Da dieses Paket zur Go Library gehört und nicht groß ist, ist dies nicht weiter schlimm. Aber einfach mal angeommen, dass ich als Ziel habe alle nicht notwendigen Imports zu eliminieren, dann kann ich das auf einfache Weise umsetzen.

An der Stelle kann man Rob Pike mit seinen Go Proverbs zitieren:

A little copying is better than a little dependency.

Anstatt das io Paket zu importieren, definiere ich einfach meinen eigenen Reader, welcher exakt dem io.Reader entspricht. Wenn die beiden Definitionen gleich sind implementiert jeder io.Reader auch unseren eigenen Reader. D.h. der folgende Code entspricht eins zu eins dem oberen:

type Reader interface {
	Read(p []byte) (n int, err error)
}

func leseWas(r Reader) {
    // ...
}

So habe ich auf einfache Weise eine Abhängigkeit abgebaut. Mein Binary file wird dadurch kleiner und mein Code ist unabhängig bzgl. Änderungen des io Pakets. Das schöne an dieser einfachen Technik ist, dass ich dies für alle Interfaces anwenden kann. Denn es ist durchaus sinnvoll, dass ich keine externen Interfaces als Input für meine Funktionen verwende. Neben der Abhängigkeit leidet auch die lesbarkeit des Codes.

Bei io.Reader und io.Writer gilt dies natürlich nur bedingt. Da diese beiden Interfaces eigentlich schon zur Sprache gehören. Zusätzlich ist das io Paket auch sehr schlank. Lediglich 9 kB konnte ich durch die Optimierung einsparen.

Aber Grundsätzlich ist es keine schlechte Idee die Interfaces für die eigenen Funktionen immer auch im selben Paket zu definieren.

comments powered by Disqus