ぺい

大阪の専門学生の落書き。主にエンジニア寄りの話。

Golangのreflectの公式ドキュメント翻訳

reflectパッケージ

f:id:tikasan0804:20170719172956p:plain

※翻訳については、ざっくりこんな感じくらいのノリです。

reflect - The Go Programming Language

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.

Package reflectionは実行時reflectionを実装し、プログラムが任意の型のオブジェクトを操作できるようにします。 一般的な使用方法は、静的型interface{}で値をとり、Typeを返すことで動的型情報を抽出することです。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println("----typeof-----")
    typeof(1, "string", true)
    fmt.Println("----typeof2-----")
    typeof2(1)
}

// vが何の値かを出力する
func typeof(value ...interface{}) {
    for _, v := range value {
        fmt.Println(reflect.TypeOf(v))
    }
}

// vがint型と同じか比較する
func typeof2(v interface{}) {
    fmt.Println(reflect.TypeOf(v).Kind() == reflect.Int)
}
go run intro1/main.go
----typeof-----
int
string
bool
----typeof2-----
true

A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.

ValueOfを呼び出すと、実行時データを表すValueが返されます。 ZeroはTypeを取り、その型のゼロ値を表すValueを返します。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println("----valueof-----")
    valueof(1, "str", false)
    fmt.Println("----valueof2-----")
    valueof2(100)
    fmt.Println("----valueof3-----")
    valueof3()
}

// vからValueOfでポインタにアクセスして、Elemでポインタにある値を返す
func valueof(value ...interface{}) {
    for _, v := range value {
        fmt.Println(reflect.ValueOf(&v).Elem())
    }
}

// valueに格納されている値がint型と適合したら、その値をansに格納する
func valueof2(value interface{}) {
    var ans int
    v := reflect.ValueOf(&value).Elem()
    if intValue, ok := v.Interface().(int); ok {
        ans += intValue
        fmt.Println(ans)
    }
}

// int型のゼロ値を取得し表示する
func valueof3() {
    var value int
    fmt.Println(reflect.ValueOf(&value).Elem())
}
go run intro2/main.go
----valueof-----
1
str
false
----valueof2-----
100
----valueof3-----
0

See “The Laws of Reflection” for an introduction to reflection in Go: https://golang.org/doc/articles/laws_of_reflection.html

Goでのreflectionの概要については、「The Laws of Reflection」を参照してください。https://golang.org/doc/articles/laws_of_reflection.html

リフレクションの法則

The Laws of Reflection

Reflection in computing is the ability of a program to examine its own structure, particularly through types; it’s a form of metaprogramming. It’s also a great source of confusion.

コンピューティングにおけるリフレクションとは、プログラムが自分の構造、特に型を調べる能力です。 それはメタプログラミングの一種です。 それはまた混乱の大きな原因です。

In this article we attempt to clarify things by explaining how reflection works in Go. Each language’s reflection model is different (and many languages don’t support it at all), but this article is about Go, so for the rest of this article the word “reflection” should be taken to mean “reflection in Go”.

この記事では、Goでreflectionがどのように機能するかを説明して、物事を明確にしようとしています。 各言語のreflection modelは異なっていますが(そして多くの言語ではそれをサポートしていません)。これはGoについての記事なので、「reflection」という言葉は「Goのreflection」を意味すると解釈されるべきです

前書き

Introduction

Because reflection builds on the type system, let’s start with a refresher about types in Go.

reflectionはシステム上に構築されるため、Goのタイプについての再考から始めましょう。

Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: int, float32, *MyType, byte, and so on. If we declare

Goは静的に型付けされています。 すべての変数は静的型を持ちます。つまり、int、float32、* MyType、 byteなど、コンパイル時に既知で固定された1つの型だけです。
もし、変数宣言をしたら以下のようになります。

type MyInt int

var i int
var j MyInt

then i has type int and j has type MyInt. The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.

MyIntはint型を持ち、jはMyInt型を持っています。 変数iとjには別個の静的型があり、それらは同じ基底型を持ちますが、変換なしでは互いに割り当てることはできません。

i = j // 同じ基底クラスのintをもっていても代入出来ない。

One important category of type is interface types, which represent fixed sets of methods. An interface variable can store any concrete (non-interface) value as long as that value implements the interface’s methods. A well-known pair of examples is io.Reader and io.Writer, the types Reader and Writer from the io package:

typeの重要なカテゴリの1つは、固定されたメソッドセットを表すinterface typesです。 interface変数は、その値がinterfaceのメソッドを実装している限り、任意の具体的な(非interface)値を格納できます。
よく知られた例のペアは、io.Readerとio.Writerです。これは、ioパッケージのReaderとWriterタイプです。interfaceについては、Javaなどにあるものと同じような挙動をします。

// Readerは、基本的なReadメソッドをラップするinterfaceです。
type Reader interface {
    Read(p []byte) (n int, err error)
}

// Writerは、基本的なWriteメソッドをラップするinterfaceです。
type Writer interface {
    Write(p []byte) (n int, err error)
}

Any type that implements a Read (or Write) method with this signature is said to implement io.Reader (or io.Writer). For the purposes of this discussion, that means that a variable of type io.Reader can hold any value whose type has a Read method:

このシグネチャでRead(またはWrite)メソッドを実装するすべての型は、io.Reader(またはio.Writer)を実装すると言われています。 ここでは、io.Reader型の変数に、その型がReadメソッドを持つ値を保持できることを示します。

var r io.Reader
r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)
// and so on

It’s important to be clear that whatever concrete value r may hold, r’s type is always io.Reader: Go is statically typed and the static type of r is io.Reader.

どのような具体的な値rが保持されていても、rの型は常にio.Readerです:Goは静的に型指定され、静的型はio.Readerです。

An extremely important example of an interface type is the empty interface:

インターフェイスタイプの非常に重要な例は、空のインターフェイスです。

interface{}

It represents the empty set of methods and is satisfied by any value at all, since any value has zero or more methods.

これは、空のメソッドセットを表し、任意の値が0以上のメソッドを持つため、すべての値がすべて満たされます。

Some people say that Go’s interfaces are dynamically typed, but that is misleading. They are statically typed: a variable of interface type always has the same static type, and even though at run time the value stored in the interface variable may change type, that value will always satisfy the interface.

一部の人々は、Goのinterfaceは動的に型付けされていると言いますが、それは誤解を招くものです。 それらは静的に型付けされています:interface型の変数は常に同じ静的型を持ち、実行時にinterface変数に格納された値が型を変更しても、その値は常にinterfaceを満たします。

We need to be precise about all this because reflection and interfaces are closely related.

reflectionとinterfacesは密接に関連しているため、すべてのことについて正確にする必要があります。

インタフェースの表現

The representation of an interface

Russ Cox has written a detailed blog post about the representation of interface values in Go. It’s not necessary to repeat the full story here, but a simplified summary is in order.

Russ Coxは、Goにinterfaceの値を表現するための詳細なブログ記事を書いています。 ここでは話を繰り返す必要はないですが、簡略な要約が必要です。

A variable of interface type stores a pair: the concrete value assigned to the variable, and that value’s type descriptor. To be more precise, the value is the underlying concrete data item that implements the interface and the type describes the full type of that item. For instance, after

interface typeの変数は、変数に割り当てられた具体的な値と、その値のタイプ記述子のペアを格納します。 より正確に言えば、値はinterfaceを実装する基礎となる具体的なデータ項目であり、タイプはその項目のフルタイプを表します。

例えば

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

r contains, schematically, the (value, type) pair, (tty, os.File). Notice that the type os.File implements methods other than Read; even though the interface value provides access only to the Read method, the value inside carries all the type information about that value. That’s why we can do things like this:

rには (value, type) の対(tty, os.File)が概略的に含まれています。 os.File型はRead以外のメソッドを実装していることに注意してください。 interface値がReadメソッドへのアクセスのみを提供しても、内部の値はその値に関するすべての型情報を保持します。 だから私たちはこのようなことをすることができます。

var w io.Writer
w = r.(io.Writer)

The expression in this assignment is a type assertion; what it asserts is that the item inside r also implements io.Writer, and so we can assign it to w. After the assignment, w will contain the pair (tty, *os.File). That’s the same pair as was held in r. The static type of the interface determines what methods may be invoked with an interface variable, even though the concrete value inside may have a larger set of methods.

この代入の式は型アサーションです。 それが主張するのは、rの中のアイテムもio.Writerを実装しているので、wに割り当てることができるということです。 代入の後、wにはペア(tty, *os.File)が含まれます。 それはrと同じペアです。 インタフェースの静的型は、内部の具体的な値がより大きな一連のメソッドを持つ場合でも、インタフェース変数で呼び出されるメソッドを決定します。

Continuing, we can do this:

続けて、これを行うことが出来ます。

var empty interface{}
empty = w

and our empty interface value empty will again contain that same pair, (tty, *os.File). That’s handy: an empty interface can hold any value and contains all the information we could ever need about that value.

空のinterfaceの空の値には、同じペア (tty, *os.File)が再び含まれます。 それは便利です:空のinterfaceは、任意の値を保持することができ、我々がその値について必要とする可能性のあるすべての情報を含みます。

(We don’t need a type assertion here because it’s known statically that w satisfies the empty interface. In the example where we moved a value from a Reader to a Writer, we needed to be explicit and use a type assertion because Writer’s methods are not a subset of Reader’s.)

ここでは、wが空のinterfaceを満たしていることが静的にわかっているため、タイプアサーションは必要ありません。ReaderからWriterに値を移動した例では、明示的に型アサーションを使用する必要がありました。 Readerのサブセットではありません)。

One important detail is that the pair inside an interface always has the form (value, concrete type) and cannot have the form (value, interface type). Interfaces do not hold interface values.

1つの重要な詳細は、interface内のペアは常にフォーム(値、具体的なタイプ)を持ち、フォーム(値、interface型)を持つことができないということです。interfaceはinterface値を保持しません。

Now we’re ready to reflect.

今我々は反映する準備が整いました。

reflectionの第1の法則

The first law of reflection

1.Reflectionは、interface値からreflection objectに向かう

  1. Reflection goes from interface value to reflection object.

At the basic level, reflection is just a mechanism to examine the type and value pair stored inside an interface variable. To get started, there are two types we need to know about in package reflect: Type and Value. Those two types give access to the contents of an interface variable, and two simple functions, called reflect.TypeOf and reflect.ValueOf, retrieve reflect.Type and reflect.Value pieces out of an interface value. (Also, from the reflect.Value it’s easy to get to the reflect.Type, but let’s keep the Value and Type concepts separate for now.)

基本レベルでは、reflectionはinterface変数の内部に格納されている型と値のペアを調べるメカニズムに過ぎません。 始めるには、パッケージreflectに反映させるためにTypeValueの2種類が必要です。 これらの2つの型は、interface変数の内容にアクセスできます。また、reflect.TypeOfおよびreflect.ValueOfという2つの単純な関数は、reflect.Typeとreflectを取得します。 (また、reflect.Valueからreflect.Typeに到達するのは簡単ですが、ValueとTypeのコンセプトを今のところ分けておきましょう。)

Let’s start with TypeOf:

TypeOfから始めましょう。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    fmt.Println("type:", reflect.TypeOf(x))
}

This program prints

このプログラムをプリントすると

type: float64

You might be wondering where the interface is here, since the program looks like it’s passing the float64 variable x, not an interface value, to reflect.TypeOf. But it’s there; as godoc reports, the signature of reflect.TypeOf includes an empty interface:

interfaceの値ではなくfloat64変数xを渡しているように見えるので、interfaceがどこにあるのか疑問に思うかもしれません。 しかしそれはreflect.TypeOfにあります。 godocレポートとして、reflect.TypeOfのシグネチャには空のinterfaceが含まれています。

// TypeOfは、インタフェース{}内の値のreflection Typeを返します。
func TypeOf(i interface{}) Type

When we call reflect.TypeOf(x), x is first stored in an empty interface, which is then passed as the argument; reflect.TypeOf unpacks that empty interface to recover the type information.

reflect.TypeOf(x)を呼び出すと、xはまず空のinterfaceに格納され、引数として渡されます。 型情報を復元するために空のinterfaceを展開します。

The reflect.ValueOf function, of course, recovers the value (from here on we’ll elide the boilerplate and focus just on the executable code):

もちろんreflect.ValueOf関数は値を復元します(ここからは、ボイラープレートを削除し、実行可能コードだけに焦点を当てます)。

var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x).String())

prints

value: <float64 Value>

(We call the String method explicitly because by default the fmt package digs into a reflect.Value to show the concrete value inside. The String method does not.)

(デフォルトでは、fmtパッケージはreflect.Valueを掘り下げて具体的な値を内部に表示するため、Stringメソッドは明示的に呼び出します。Stringメソッドはそうではありません)。 ちなみに、これをStringなしで実行すると

var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x))
value: 3.4

Both reflect.Type and reflect.Value have lots of methods to let us examine and manipulate them. One important example is that Value has a Type method that returns the Type of a reflect.Value. Another is that both Type and Value have a Kind method that returns a constant indicating what sort of item is stored: Uint, Float64, Slice, and so on. Also methods on Value with names like Int and Float let us grab values (as int64 and float64) stored inside:

どちらも反映されます。 reflect.Typeとreflect.Valueには、それらを調べて操作するための方法がたくさんあります。 1つの重要な例として、ValueはTypeはreflect.ValueのTypeを返すメソッド があります。 もう一つは、TypeとValueの両方に、どの種類のアイテムが格納されているかを示す定数(Uint、Float64、Sliceなど)を返すKindメソッドがあることです。 また、IntやFloatのような名前を持つValueのメソッドでは、内部に格納されている値(int64とfloat64など)を取得できます。

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())

prints

type: float64
kind is float64: true
value: 3.4

There are also methods like SetInt and SetFloat but to use them we need to understand settability, the subject of the third law of reflection, discussed below.

SetIntやSetFloatのようなメソッドもありますが、それらを使用するには、後述する第3回reflectionの主題である設定可能性を理解する必要があります。

The reflection library has a couple of properties worth singling out. First, to keep the API simple, the “getter” and “setter” methods of Value operate on the largest type that can hold the value: int64 for all the signed integers, for instance. That is, the Int method of Value returns an int64 and the SetInt value takes an int64; it may be necessary to convert to the actual type involved:

reflectionライブラリには、注目に値するいくつかのプロパティがあります。 まず、APIを単純なものにするために、Valueのgetterメソッドとsetterメソッドは、値を保持できる最大の型、たとえば、すべての符号付き整数に対してint64で動作します。 つまり、ValueのIntメソッドはint64を返し、SetInt値はint64を返します。 関係する実際のタイプに変換する必要があるかもしれません:

var x uint8 = 'x'
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())                            // uint8.
fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
x = uint8(v.Uint())                                       // v.Uint returns a uint64.

The second property is that the Kind of a reflection object describes the underlying type, not the static type. If a reflection object contains a value of a user-defined integer type, as in

2番目のプロパティは、reflection objectの種類が静的型ではなく基底型を記述していることです。 reflection objectにユーザ定義の整数型の値が含まれている場合

type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)

the Kind of v is still reflect.Int, even though the static type of x is MyInt, not int. In other words, the Kind cannot discriminate an int from a MyInt even though the Type can.

静的な型のxはintではなくMyIntであるにもかかわらず、vの種類はまだ reflect.Intです。 言い換えれば、種類はできますが、KindはMyIntからintを区別できません。

reflectionの第2の法則

The second law of reflection

Reflectionはreflection objectからinterfaceの値に向かう

  1. Reflection goes from reflection object to interface value.

Like physical reflection, reflection in Go generates its own inverse.

物理的な反射のように、Goでのreflectionはそれ自身の逆を生成します。

Given a reflect.Value we can recover an interface value using the Interface method; in effect the method packs the type and value information back into an interface representation and returns the result:

与えられたreflect.Valueは、Interfaceメソッドを使用してInterface値を復元できます。 実際にはこのメソッドは型と値の情報をInterface表現にパックして返します。

// Interfaceはvの値をinterface{}として返します。
func (v Value) Interface() interface{}

As a consequence we can say

結果として、我々は言うことができる

y := v.Interface().(float64) // y will have type float64.
fmt.Println(y)

to print the float64 value represented by the reflection object v.

reflection object vによって表されるfloat64値を出力する。

We can do even better, though. The arguments to fmt.Println, fmt.Printf and so on are all passed as empty interface values, which are then unpacked by the fmt package internally just as we have been doing in the previous examples. Therefore all it takes to print the contents of a reflect.Value correctly is to pass the result of the Interface method to the formatted print routine:

しかし、私たちはもっと良くすることができます。 fmt.Println、fmt.Printfなどの引数は、すべて空のinterface値として渡され、前の例で行ったように内部的にfmtパッケージによってアンパックされます。 したがって、reflect.Valueの内容を出力するには、Interfaceメソッドの結果を書式付きprintルーチンに渡すだけです。

fmt.Println(v.Interface())

(Why not fmt.Println(v)? Because v is a reflect.Value; we want the concrete value it holds.) Since our value is a float64, we can even use a floating-point format if we want:

(なぜfmt.Println(v)なのか?vはreflect.Valueなので、具体的な値が必要です。)値がfloat64なので、必要ならば浮動小数点フォーマットを使用することもできます:

fmt.Printf("value is %7.1e\n", v.Interface())

and get in this case

この場合

3.4e+00

Again, there’s no need to type-assert the result of v.Interface() to float64; the empty interface value has the concrete value’s type information inside and Printf will recover it.

ここでも、v.Interface()の結果をfloat64にタイプアサートする必要はありません。 空のinterfaceの値は具体的な値の型情報を内部に持ち、Printfはそれを復元します。

In short, the Interface method is the inverse of the ValueOf function, except that its result is always of static type interface{}.

要するに、InterfaceメソッドはValueOf関数の逆ですが、その結果は常に静的型interface{}である点が異なります。

Reiterating: Reflection goes from interface values to reflection objects and back again.

繰り返します:Reflectionはinterface値からreflection objectsに戻り、再び戻る。

reflectionの第3の法則

The third law of reflection

3.反射オブジェクトを変更するには、その値を設定可能にする必要があります。

  1. To modify a reflection object, the value must be settable.

The third law is the most subtle and confusing, but it’s easy enough to understand if we start from first principles.

第3の法則は最も微妙で混乱しますが、しかし、最初の原則から始めたら理解することは簡単です。

Here is some code that does not work, but is worth studying.

ここで動作しないコードがありますが、勉強する価値があります。

var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.

If you run this code, it will panic with the cryptic message

このコードを実行すると、謎のメッセージでパニックに陥ります

panic: reflect.Value.SetFloat using unaddressable value
reflect.Value.Setfloatをアドレス指定が不可能な値を使用した

The problem is not that the value 7.1 is not addressable; it’s that v is not settable. Settability is a property of a reflection Value, and not all reflection Values have it.

問題は、値7.1がアドレスが指定可能ではないということではありません。 vは設定できません。 設定可能性は、reflection Valueの特性であり、すべてのreflection Valuesがそれを有するわけではない。

The CanSet method of Value reports the settability of a Value; in our case,

ValueのCanSetメソッドは、Valueの設定可能性を報告します。 私達の場合。

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())

prints

settability of v: false

It is an error to call a Set method on an non-settable Value. But what is settability?

設定できない値に対してSetメソッドを呼び出すのはエラーです。 では、設定可能性とは何ですか?

Settability is a bit like addressability, but stricter. It’s the property that a reflection object can modify the actual storage that was used to create the reflection object. Settability is determined by whether the reflection object holds the original item. When we say

設定可能性は、アドレス可能性のようなものですが、より厳しいものです。 reflection objectは作成に使用された実際のストレージを変更することができるプロパティです。 設定可能性は、reflection objectが元のアイテムを保持するかどうかによって決まります。 私たちが言うとき

var x float64 = 3.4
v := reflect.ValueOf(x)

we pass a copy of x to reflect.ValueOf, so the interface value created as the argument to reflect.ValueOf is a copy of x, not x itself. Thus, if the statement

xのコピーを渡します reflect.ValueOf、したがって、reflect.ValueOfへの引数として作成されたinterfaceの値は、x自身ではなくxのコピーです。 したがって

v.SetFloat(7.1)

were allowed to succeed, it would not update x, even though v looks like it was created from x. Instead, it would update the copy of x stored inside the reflection value and x itself would be unaffected. That would be confusing and useless, so it is illegal, and settability is the property used to avoid this issue.

たとえそれがxから作成されたように見えるとしても、xは更新されないでしょう。 代わりに、それは反射値の内部に格納されたxのコピーを更新し、x自体は影響を受けません。 このような操作は、混乱を生むだけで役に立ちません。設定可能性はこの問題を回避するために使用されるプロパティです。

If this seems bizarre, it’s not. It’s actually a familiar situation in unusual garb. Think of passing x to a function:

これが奇妙に思われるかもしれませんが、そうではありません。 実際には普通ではない服装ではおなじみの状況です。では、 xを関数に渡すことを考えてみましょう:

f(x)

We would not expect f to be able to modify x because we passed a copy of x’s value, not x itself. If we want f to modify x directly we must pass our function the address of x (that is, a pointer to x):

私たちは、x自身の値ではなく、xの値のコピーを渡したので、fでxを変更できるとは思わないでしょう。fでxを直接変更したい場合は、関数xのアドレス(xのポインタ)を渡す必要があります。

f(&x)

This is straightforward and familiar, and reflection works the same way. If we want to modify x by reflection, we must give the reflection library a pointer to the value we want to modify.

こういったことは、簡単でよく知られていることで、reflectionも同じように機能します。 reflectionでxを変更する場合は、reflectionライブラリに変更したい値へのポインタを与える必要があります。

Let’s do that. First we initialize x as usual and then create a reflection value that points to it, called p.

やってみましょう。 最初にxを通常どおりに初期化し、それを指すreflection 値のpを作成します。

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

The output so far is

これまでの出力は

type of p: *float64
settability of p: false

The reflection object p isn’t settable, but it’s not p we want to set, it’s (in effect) *p. To get to what p points to, we call the Elem method of Value, which indirects through the pointer, and save the result in a reflection Value called v:

reflection objectのpは設定できませんが、設定したいpではありません。実際には*pです。 pが何を指しているかを知るために、ポインタを介して間接的に行われるValueのElemメソッドを呼び出して、その結果をvと呼ばれるreflection Valueに保存する。

v := p.Elem()
fmt.Println("settability of v:", v.CanSet())

Now v is a settable reflection object, as the output demonstrates,

出力が示す通り、vは設定可能なreflection objectです。

settability of v: true

and since it represents x, we are finally able to use v.SetFloat to modify the value of x:

vはxを表すので、最終的にv.SetFloatを使ってxの値を変更することができます:

v.SetFloat(7.1)
fmt.Println(v.Interface())
fmt.Println(x)

The output, as expected, is

出力は、期待どおりです。

7.1
7.1

Reflection can be hard to understand but it’s doing exactly what the language does, albeit through reflection Types and Values that can disguise what’s going on. Just keep in mind that reflection Values need the address of something in order to modify what they represent.

反射は理解するのが難しいかもしれませんが、何が起こっているのかを隠すことができる反射のタイプと値にもかかわらず、言葉の意味を正確にしています。 リフレクションには、表現するものを変更するために、何かのアドレスが必要です。

構造体

Structs

In our previous example v wasn’t a pointer itself, it was just derived from one. A common way for this situation to arise is when using reflection to modify the fields of a structure. As long as we have the address of the structure, we can modify its fields.

前の例では、vはポインタそのものではなく、単にポインタから導出されたものです。 この状況が発生する一般的な方法は、reflectionを使用して構造のフィールドを変更する場合です。 構造体のアドレスがあれば、そのフィールドを変更することができます。

Here’s a simple example that analyzes a struct value, t. We create the reflection object with the address of the struct because we’ll want to modify it later. Then we set typeOfT to its type and iterate over the fields using straightforward method calls (see package reflect for details). Note that we extract the names of the fields from the struct type, but the fields themselves are regular reflect.Value objects.

構造体の値tを解析する簡単な例を次に示します。 構造体のアドレスを使ってリフレクションオブジェクトを作成します。後で変更する必要があるからです。 次に、typeOfTをその型に設定し、簡単なメソッド呼び出しを使用してフィールドを反復処理します(詳細はパッケージを参照)。 struct型からフィールドの名前を抽出しますが、フィールド自体は通常のreflect.Valueオブジェクトです。

type T struct {
    A int
    B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    fmt.Printf("%d: %s %s = %v\n", i,
        typeOfT.Field(i).Name, f.Type(), f.Interface())
}

The output of this program is

このプログラムの出力は

0: A int = 23
1: B string = skidoo

There’s one more point about settability introduced in passing here: the field names of T are upper case (exported) because only exported fields of a struct are settable.

ここではsettabilityについてもう一度説明します。Tのフィールド名は、構造体のエクスポートされたフィールドのみが設定可能であるため、Tのフィールド名は大文字(エクスポートされます)です。

Because s contains a settable reflection object, we can modify the fields of the structure.

sには設定可能なreflection objectが含まれているため、構造のフィールドを変更できます。

s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)

And here’s the result:

そして結果は次のとおりです。

t is now {77 Sunset Strip}

If we modified the program so that s was created from t, not &t, the calls to SetInt and SetString would fail as the fields of t would not be settable.

&tではなくtからsを作成するようにプログラムを修正した場合、SetIntとSetStringの呼び出しは失敗し、tのフィールドは設定できません。

結論

Conclusion

Here again are the laws of reflection:

反射の法則もここにあります。

  • Reflection goes from interface value to reflection object.
  • Reflection goes from reflection object to interface value.
  • To modify a reflection object, the value must be settable.
  • Once you understand these laws reflection in Go becomes much easier to use, although it remains subtle. It’s a –
  • powerful tool that should be used with care and avoided unless strictly necessary.
  • Reflectionは、interface値から反射オブジェクトに向かう。
  • Reflectionは、reflection objectからinterface値に向かいます。
  • reflection objectを変更するには、その値を設定可能にする必要があります。
  • これらの法律を理解すれば、Goでの反映はずっと使いやすくなりますが、微妙なままです。 どうしても必要な場合を除いて使用し、出来れば避けるべき強力なツールです。

感想

勉強のために翻訳しましたが、思ったより分量多くて辛かった。

Cloud Datastoreをざっくり理解する

スケーラビリティの高い NoSQL データベース

f:id:tikasan0804:20170715202352p:plain

いま友人と開発しているプロダクトで、本格的にDatastoreを使った開発をすることになったので、概念を理解するためのメモ記事です。

cloud.google.com

RDBから理解するDatastore概念

概念 Datastore RDB
オブジェクトのカテゴリ Kind Table
1つのオブジェクト Entity Row
1つのブジェクとの各データ Property Field
オブジェクトに対するユニークなID Key Primary Key

これらを分かりやすい説明をしてくれていたものがあったので、引用させて頂きます。

Kindと呼ばれるテーブルみたいなものに
Entityと呼ばれるオブジェクトを格納できます。
Entityには一意のKeyが割り当てられています。
EntityのフィールドはPropertyといいます。

つまり、Kind -> Entity -> Propertyという親子関係のようです。

GAE/GO Cloud Datastoreを使ってみる | teppeeeのブログ

次に実行されるメソッドの種類について

動作 Datastore RDB
取得 Get, GetAll SELECT
追加 Put INSERT
更新 Put UPDATE
削除 Delete DELETE

基本的なCRUDは当然出来ます。ただ、Readに関しては読み取るだけなら問題はないですが、複雑な検索はRDBに比べると非力なので、Search APIを使って検索したりすることが一般的なようです。

Datastoreのデータ整理

cloudplatform-jp.googleblog.com

上記の記事が非常に分かりやすかったので、引用しながら理解していこうと思います。

Google Cloud Datastore のような非リレーショナル データベースにおけるデータのモデリングや保存には、固有の難しさがあります。結合や正規化など、リレーショナル データベースの有益な機能の多くは、非リレーショナル データについては、スケーラビリティに欠けるという理由で適用されません。リレーショナル データベースを「オブジェクトと関係」としてとらえるという一般的なアプローチも、非リレーショナル データベースに当てはめるのは困難です。

DatastoreはRDBの代わりにはならない。同じ考えでやることは困難のようです。

具体例:マルチユーザーブログ

RDBでのモデリング

User

Id username name
1 tonystark Tony Stark
2 dianaprince Diana Prince

Post

Id user_id content
1 1 Hello, world!
2 2 Another post

特定ユーザーの検索クエリ
user_idが1のユーザーの投稿で検索する
SELECT * FROM Post WHERE user_id = 1

Datastoreのモデリング

Key Data
(Post, 1) {“user”: Key(User, tonystark), “content”: “Hello, World!”}
(Post, 2) {“user”: Key(User, dianaprince), “content”: “Another post”}
(User, tonystark) {“name”: “Tony Stark”}
(User, dianaprince) {“name”: “Diana Prince”}

Entityが特定のKindを持っている構造になります。今回の例だと、(Post, 1) PostがKindに当たります。RDBでいうところの、Rowがそれぞれ特定のTableを持っているという構造になります。

では、Post Kindでusernameをフィルタリングすると以下のようなクエリになります。
tonystarkでフィルダリングする例
datastore.Query(kind='Post', filters=[('user', '=', Key('User', tonystark))])

上記のようなグローバルクエリをDatastoreで実行すると、結果整合性を持つことになります。

結果整合性とは

NoSQLでよく登場する性質で、「データの何らかの変更は最終的には全体に適用される」というものです。変更の定義は、追加や削除、更新を総称しているものとします。これはどういうことかと言うと、様々なユーザーがリソースに対して操作を行ったりします。場合によっては、作業が衝突して問題が起きそうですが、これは最後に行った更新を適用するようにしていて、結果的には問題ないとするものです。
つまり、様々なCRUDの操作があったとして、

時間 操作
12:10 ☆更新
12:12 ◯更新
12:09 △更新

上記のような操作のログデータが集約された時に、最終的に適用されるのは、最終更新時間である「◯更新」が正しいとします。なので、基本的にひたすらInsertをしていくということになります。(帳簿的な感じ?)
RDBにおいては厳密な一貫性を重視しているということから、性質上全く違うということがここから分かります。

ちなみに、Datastoreでは、データ整理方法に応じて強整合性と結果整合性のどちらかを選択出来ます。

強い整合性

強い整合性は、先程の結果整合性と処理の流れそのものは同じですが、データに対してアクセス出来るタイミングが全く異なります。分散させたストアにそれぞれ適用が完了してから、ロックを解除します。これらのバランスや性質については公式ドキュメントが非常に分かりやすくまとめてくれているので、参照してみてください。

cloud.google.com

KindやKeyの性質を理解する

先程紹介した記事には以下のように書かれています。

カインドをテーブルと、キー名をプライマリ キーと考えたくなるかもしれません。しかし、キーは祖先を持つことができ、そのためにキーパスが存在します。非リレーショナル データをテーブルやキーの観点からとらえるのではなく、ファイル システムとして考えてみましょう。

ファイルシステムとして考える???

対象

Key Data
(Post, 1) {“user”: Key(User, tonystark), “content”: “Hello, World!”}
(Post, 2) {“user”: Key(User, dianaprince), “content”: “Another post”}
(User, tonystark) {“name”: “Tony Stark”}
(User, dianaprince) {“name”: “Diana Prince”}

ファイルシステムに置き換える

/1.post
/2.post
/tonystark.user
/dianaprince.user

ユーザー別にグループ化する

/tonystark.user
  /1.post
/dianaprince.user
  /2.post

最初の投稿パスは、/tonystark.user/1.postとなります。つまり、以下のように整理されています。

Key(ファイルパス) Data(ファイル)
(User, tonystark) {“name”: “Tony Stark”}
(User, tonystark, Post, 1) {“content”: “Hello, World!”}
(User, dianaprince) {“name”: “Diana Prince”}
(User, dianaprince, Post, 2) {“content”: “Another post”}

投稿をユーザー別に整理すると、エンティティ グループが作成されます。その中にはユーザーのプロフィールとすべての投稿が含まれます。Cloud Datastore では、1つのエンティティ グループに対するクエリは強い整合性を持ちます。このため、ユーザーは投稿を作成すると、すぐに見ることができます。祖先をキーに指定してクエリを行うことも可能です。

datastore.Query(kind='Post', ancestor=Key('User', username))

このようなパターンの場合、強い整合性を持つとあります。つまり、その分のトレードオフが発生することになります。Datastoreでは、各エンティティグループには、約1秒間に1回しか更新できません。その代わり、全ての読み取りが強い整合性を持ちます。ここでの更新はCRUD全般を指します。 ※1秒間に1回というのは、各エンティティグループにのみ適用されるルールで、別エンティティグループなら同時操作を可能としています。

この設計の場合、全てのユーザがアップロードした投稿を返すクエリは結果整合性を持つようになります。

datastore.Query(kind='Post')

つまり、以下のようになります。

クエリ 性質
全ての投稿を取得 結果整合性
自分の投稿を取得 強い整合性

自分の投稿だけを見る分にはすぐ確認できますが、投稿が全体に公開されるフィードなどにはすぐ更新されませんということだと思います。ここまでの説明で分かる通り、結果整合性と強い整合性は全く違う性質を持っているので、使い所をしっかり判断することが大事だと考えられます。

具体例:Wiki

ファイル パスのメタファーを使って、シンプルな Wikiモデリングすることもできます。Wiki では、ページを保存するたびに新しいリビジョンが作成されます。ユーザーは任意のリビジョンからページをリストアできます。 このデータをファイル システムとして表現すると、次のようになります。
この構造は、各ページのすべてのリビジョンを別々のエンティティ グループに保存します。

/home.page
  / current.revision
  / 05-29-2015-10-30-27.revision
  / 05-20-2015-06-33-11.revision

/another.page
  / current.revision
  / 04-10-2015-11-23-10.revision

データの操作の流れは以下の通りです。

現在のページデータ(current.revision)を新しいリビジョンにコピーし、current.revisionを新しいコンテンツで上書きします。Datastoreにあるトランザクションを利用するとこういった複数回の処理を、整合性を保つことが出来ます。つまり、成功すれば適用し、失敗すればロールバックしてくれるということです(すごい)

このトランザクション処理は、25のエンティティグループにまたがって実行することが出来ます。ですが、このトランザクションは範囲が多ければ多いほど、失敗の確率が上がるので注意が必要そうです。

これら関連するリビジョンをリストで取得することが、祖先キーを指定することで可能となっています。

datastore.Query(kind='revision', ancestor=Key('page', home))

リビジョンの更新はほとんど同じで、新しく投稿されたコンテンツを使うのではなく、current.revisionを更新することで実現出来ます。

まとめ

記事には以下のようにまとめられていました。

  • ページは 1 秒間に 1 回まで更新できる。
  • ページ上のクエリとそのリビジョンは強い整合性を持つ。
  • 保存操作では、強い整合性を持つクエリが使用されるため、ページの保存やリビジョンのリストアは、トランザクションとして実行できる。
  • ページ数が膨大でも、ページの読み書きは高速。

これは理解するためには、まずは使ってみて、経験を積むことが大事な気がしますね。なんか作ったらまとめてみようと思います。

goaのデザインコードを分割する

肥大化しがちなDSLコードを分割する

f:id:tikasan0804:20170505212036p:plain

goaの開発フローは、以下のような感じです。

  1. DSLを作成する
  2. コントローラー作成
  3. 追加仕様または修正でDSLをごにょる

上記のようなことをしていたら、結構DSLが肥大化します。そこで、DSLを少し工夫することで分割することが可能です。これをすると以下のような構成に出来るので、困ってる人は実践してみてください。

├── Makefile
├── README.md
├── app
├── client
├── controllers
│   ├── hello.go
│   └── sample.go
├── design
│   ├── api_definition.go
│   ├── media
│   │   ├── hello.go
│   │   └── sample.go
│   └── resources
│       ├── hello.go
│       └── sample.go
└── main.go

ソース

github.com

まだ、PR出している最中ですが、上記のコードがその具体例になります。

goaのGoglandスニペットを活用しよう

DSLを楽ちんにするスニペットを活用する

f:id:tikasan0804:20170505212036p:plain

goaのDSL書くの面倒ですよね!? Gogland用のgoaのDSLを書くためのスニペット作成しました。

github.com

この発想はkawakenさんの以下の記事の影響されて作ったものです。(goa studyにて)

kawaken.hateblo.jp

イデア求む

Goglandでスニペットをコードベースで管理したいんですけど、何かいい方法ないですかね。

exampleがないOSSでexampleを探す方法

OSS使うとよく起きるアレ

f:id:tikasan0804:20170704205846p:plain

流行っている言語やフレームワークを使っていれば、そこまで深刻な問題ではありませんが、僕とかは普段Goをメインに書いているので、利用者が少ないOSSを使うことがよくあります。
そんな時に起きる問題が、
「良いOSS見つかったけど、使い方わからん」

せっかく良いの見つけたのに、正直よくわかんねーーーーってなって、使うのを諦めるのは勿体ないですよね。(ドキュメントとかテスト読めば分かりますが)そんな時にほしいのがexampleです。一切無いものは珍しいですが、あったとしても非常に端的なものしかないことが多いので、そこからはドキュメントなどを読んで、自分のケースに当てはめたりするフローは必須ですが、少しでも多くの利用例があるに越したことはありませんよね?

そこで、他のexampleを探す方法を紹介します。

コードを探すならGithub

github.com

今回はGoのOSSでexampleを探してみましょう。まだ、スター数は300前後で、少なくはありませんが採用例をググって探すのは難しいぐらいの微妙なラインのものです。

f:id:tikasan0804:20170704211049p:plain

使うのは、Githubの検索窓です。検索には先程のOSSを実行する時に必ず使うソースの一部を貼り付けます。

dockertest.NewPool(

以下が検索結果です。 github.com

f:id:tikasan0804:20170704210354p:plain 51コードがヒットしました。これで、用意されたexample以外のパターンを見ることが出来ます!!!これでまあまあ幸せになれるかもしれません。 他にも、importしているパッケージ名とかでも検索が出来たりするので、探してみてください。

学生の間に勉強するべき技術とかの話

学生という貴重な時間で何するべきか

f:id:tikasan0804:20170623112305j:plain

私を含めた学生のエンジニアの多くが悩む課題であろう「結局なにを勉強したらいんだろう」という内容について、私なりに出た結論が出たので紹介します。

先に断っておくと、これは私の完全なる主観です。

筆者の行く業界も重要な要素かもしれないので、簡単な紹介をしておくと、私はVOYAGE GROUPという渋谷にあるITベンチャーの会社に内定を頂いており、2018年より新卒入社する予定です。

とことん好きなことをやればいい

就職まで時間あるけど、入社まで何を勉強したらいいんだろう。または、就活まで何を勉強したらいいんだろうという話です。私の中で出たひとつの結論は、「誰にも負けないくらい、とことん好きなことをやればいい」です。
何故好きなことやっとけという話なったかと言うと、例えば、いまのWeb業界で流行っている技術の◯◯やったとしても、ITの世界は非常に技術革新の流れが早いので、入社の頃には役に立たなくなってる可能生もあります。たとえそれを勉強したところで、業務レベルで通用するかは結構怪しいです。何より仕方なくやってるというのが良くないです。

学生で自由に学ぶ権利がある今だからこそ、好きなことをとことん極めてしまった方が有意義ではないかと考えたわけです。業務に関する勉強は業務で学んで、学生だからこそ出来る勉強を今やるというスタイルで、最近はやりたいことやってます。(個人的には遊びまくるのも大事だと思ってます)

あと、私の場合、住んでいる場所が大阪で、就職先が東京っていうのもあって、内定先とかで働きたくても無理だったので、自分でどうにかする方に振り切るしかなかったという環境的要因も大きいかもしれません。

実際にいまやっていること

f:id:tikasan0804:20170505212036p:plain

私がいま実際に取り組んでいることは、バックエンドの特にAPI周りの勉強です。あとは、GoのOSSのgoaです。流行ってるからやってるというよりは、好きだからやってるという、リスペクト駆動開発でやっています。(goaいいよ本当に)

業務で使えない好きをやる意味

私がいま力を入れて取り組んでるOSSのgoaなどは正直まだまだ発展途上で、流行ってるとはとても言えない状況です。そもそもGoがまだまだ使える人が少ないですし・・・。そこで出て来る不安が、業務で使わないような技術やってる時間無駄じゃない?問題です。
これに関しては、私なりの持論があって、どんなことでも極めようと思うと様々な勉強が必要だったり、課題にぶつかることがあります。それらの解決策を考える際に、他のOSSではどうなってんだろう?とかやってると自然に体系的な技術力がつくので大丈夫だと思ってます。良くないのはなんとなく使い続けていることだと思います。色々なものを触った上で、これが好きだ!というのは大事だと思っています。なので、色々触って不満を感じれるレベルまで、まずは色々やってみようという最低ラインはあるかもしれません。

技術が好きじゃないとだめ?問題

勘違いしてほしくないので補足しておくと、「技術が最初から好きだから出来るんじゃないの?(天性的なやつ)」という誤解です。実は就活をし始めた3年生の5月時点では、エンジニア志望度はあまり高くなく、正直モノづくりに関われたら何でもいいというスタンスで、手段としてプログラムがあるくらいの認識の人間でした。なので、元々は全然技術には興味がなく、むしろやりたくない側でした。

好きになったきっかけとしては、夏のインターンなどを通して、ある程度のラインまでやって、学生レベルですが、理解出来て楽しくなってきたという感じです。何が言いたいかというと、食わず嫌いで無理だと思わず、自然と楽しくなってくることもあるので、トライしてみましょうって感じです。

好きをやってると良いことがある?(Go関連事例)

結局そんなことして何がいいの?って話ですが、私は少なくとも恩恵を得ました。以下にGoに関連したものだけを挙げますが、実際には他にもたくさん良いことがあります。

f:id:tikasan0804:20170623113200j:plain

人との繋がりが増える

当然ながら共通の好きなどの繋がりで、人との交流が増えます。楽しいです。

tikasan.hatenablog.com

OSSへコミット出来たりする

正直こんな僕でもリスペクト駆動でどうにかなってます。

tikasan.hatenablog.com

イベントで登壇したりして、刺激もらえる

場合によってはイベントでトーク出来たりして、アウトプットに対するフィードバックもらえたりします。

tikasan.hatenablog.com

会社によっては支援があったりする

これに関しては会社によりけりですが、私の内定先のVOYAGE GROUPでは、勉強に関する費用を負担頂ける制度があり、カンファレンスへの参加や技術書の購入など、様々な支援が頂けます。そこらへんの詳しい話はまた別で紹介しようと考えています。

支援で行ったイベント tikasan.hatenablog.com tikasan.hatenablog.com tikasan.hatenablog.com

まとめ

もし、好きなんだけど流行る気しねーみたいな技術があるなら、それはガッツリ取り組んだ方がいいです。そういう好きなことがあるということを無駄にするのは勿体ないです。
人によっては何もない人もいるかもしれませんが、焦らず自分の興味に対して注意を払って見つけると良いと思います。

でも就活心配だぞ!という人へ

でも、実際やっておいた方がいいことあるでしょ?という就活生向けの記事は過去に書きました。私の就活経験から感じた。よかったことなどまとめているので、心配な人は参考にしてみてください。

qiita.com qiita.com

Goの静的コード解析を一括でいい感じにする(Wercker)

静的コード解析(lint)でコード品質を保つ

f:id:tikasan0804:20170622161758j:plain

Goには静的解析のツールがたくさんあります。結局何使えばいいんだろうとか、いい感じの設定ファイルが欲しいなど、結構何かと困る点があったので、記事にしてまとめて紹介します。

alecthomas/gometalinter

github.com

今回の静的コード解析にはalecthomas/gometalinterを使います。このOSSはgoに存在する様々な静的コード解析ツールを一括で使うことが出来る優れものを使って、CI回していきます。 まずは、go getします。

これ以降、静的コード解析ツールをlintとします。

$ go get -u github.com/alecthomas/gometalinter
$ gometalinter --install --update
Installing:
  unconvert
  gas
  gosimple
  ineffassign
  safesql
  varcheck
  dupl
  goimports
  golint
  misspell
  structcheck
  unparam
  unused
  errcheck
  gocyclo
  lll
  gotype
  interfacer
  staticcheck
  aligncheck
  deadcode
  goconst

このパッケージをインストールすると、こんなにlintツールあんのか!wって感じなんですけど、今回はこの中にあるいくつかのパッケージに絞って実践してみたいと思います。 それぞれのlintについては別記事でそれぞれが何かを紹介します。
いい記事が既にあったので紹介しておきます。

tech.sideci.com

ソースくれ

github.com

lintの準備

Makefileを以下のように作成します

Makefile

# 開発者のためのインストールコマンド
install:
    @which gometalinter || go get -u github.com/alecthomas/gometalinter
    @gometalinter --install --update

# Werckerのための依存関係解決コマンド
deps:
    @which gometalinter || go get -v github.com/alecthomas/gometalinter
    @gometalinter --install --update

# lintの実行
lint:
    @if [ "`gometalinter ./... --config=lint_config.json | tee /dev/stderr`" ]; then \
        echo "^ - lint err" && echo && exit 1; \
    fi

設定ファイルを以下のように作成します

lint_config.json

{
  "DisableAll": true,
  "Enable": [
    "vet",
    "gofmt",
    "staticcheck",
    "goconst",
    "golint",
    "goimports",
    "errcheck"
  ],
  "Exclude": [
    "ignore"
  ],
  "Vendor": true
}

軽く意味を解説すると以下のような感じです。(細かいニュアンスは若干違います。)

キー 説明
DisableAll 全てのlinterを使わない設定にする
Enable 使用するlinterを指定する
Exclude lintしたくないファイルやフォルダを指定する
Vendor vendorフォルダを無視する

他にもたくさんオプションがあるので、気になる方は、gometalinter --helpで調べてみてください。

lint対象コード作成

次に実際に解析するコードを適当に作成します。

フォルダ構成

.
├── Makefile
├── check
│   └── main.go
├── ignore
│   └── main.go
├── lint_config.json
└── main.go

./main.go

package main

import (
    "github.com/tikasan/golint/check"
    "github.com/tikasan/golint/ignore"
)

func main() {
    check.Hoge()
    ignore.Foo()
}

./check/main.go

package check

import "fmt"

// Hoge print hoge <--- GoDocを書かないとエラーになる
func Hoge() {
    fmt.Println("hoge")
    err := returnErr() // errチェックを行わないとエラーになる
    if err != nil {
        fmt.Println(err)
    }
}

// nolint <--- これを書くとlintが無視される
// https://github.com/alecthomas/gometalinter#comment-directives
func NoLint() {
    fmt.Println("noLint")
}

// returnErr
func returnErr() error {
    return fmt.Errorf("return %s", "err")
}

./ignore/main.go
フォルダごと無視される

package ignore

import "fmt"

func Foo() {
    fmt.Println("foo")
}

では、lintを実行してみましょう。正しく終わったら、わざと間違えてみたりしてください。今回の例では、他にgoimportsされてない。gofmtされていないコードもエラーとなったりします。

$ make lint

Werckerと連携させる

せっかくlintが動くようになったので、CIで常にコードをチェックする仕組みほしいですよね。ということでさくっと実装してみたいと思います。

www.wercker.com

wercker.yml

box: golang
build:

    steps:
        - setup-go-workspace

        - script:
            name: dependencies
            code: make deps

        - script:
            name: lint
            code: make lint

管理したいアプリケーションを追加します f:id:tikasan0804:20170622160525p:plain

今回はGithubのrepoなので、Githubを選択します f:id:tikasan0804:20170622160527p:plain

対象のrepoを選択する f:id:tikasan0804:20170622161624p:plain

Ownerを選びます f:id:tikasan0804:20170622160533p:plain

何で設定ファイルにアクセスするか選択します f:id:tikasan0804:20170622160546p:plain

このアプリケーションはpublicです的な f:id:tikasan0804:20170622160550p:plain

設定が完了したら、コミットしてみてください。lintが走ってコードがチェックされるようになります。 f:id:tikasan0804:20170622160552p:plain

CollaborationにWerckerbotを追加しましょう f:id:tikasan0804:20170718213354p:plain

lintを入れるだけでもコードの品質は結構上がる

私は何か規模大きめ、またはリリース目的のコードには基本的にlintを必ず入れています。理由としては、コードの品質が保たれるのはもちろんですが、チームでやっていた場合に少なくともlintでチェックしている部分はレビューしなくてよかったりもするので、コスト削減にもなったりするので、絶対入れたほうが幸せになれますw