お茶漬けびより

学んだことを整理する場所です。主に、C++, Unreal Engine 4 (UE4) を扱っていました。最近は、仕事方面で使っている言語やツールを紹介したいと思います。たまに趣味や雑記も。

超簡易な xUnit を Kotlin 入門しながら書く

f:id:pickles-ochazuke:20181202154024j:plain

Pixel 3 で写真撮るの楽しいです。久々の更新です(毎回言ってる気がする)。
Kotlin Advent Calendar 2018 5日目の記事です。

qiita.com

テスト駆動開発の本に書かれているプログラムを Kotlin で書いてみました。自分は Kotlin を触って日が浅いのですが、入門本を一冊読んでみたので何か書いてみようかと思ったのと、最近 「テスト駆動開発」という本を読んだので試しに xUnit 書いてみるかと。

クラスは、TestCaseTest, TestCase, WasRun, TestResult, TestSuite を作り、関数として getAttr 関数を作りました(機能的には getMethod という感じですが)。

Python では、オブジェクトの変数やメソッドを取り出す getAttr 関数があるのですが、Kotlin にはなさそうだったので、メソッドを取り出す関数を作りました。といってもただ Java のリフレクションを使っただけですが。以下のような感じです。

import java.lang.reflect.Method

fun getAttr(obj: Any, method_name: String): Method {
  return obj.javaClass.getMethod(method_name)
}

メソッドや関数の宣言の仕方はあとで書いてあるので飛ばしますが、上記のようにインポートすれば、Java のライブラリを使うことが出来ます。もっと上手いやり方がある気がするのですが本題じゃないので今回は上記のようにしました。

まず、基本クラスになる TestCase ですが、以下のようになります。

open class TestCase(var name: String) {
  open fun setUp() {
  }
  open fun tearDown() {
  }
  
  fun run(result: TestResult) {
    result.testStarted()
    setUp()
    try {
      val method = getAttr(this, this.name)
      method.invoke(this)
    }
    catch(e: Exception) {
      result.testFailed()
    }
    tearDown()
  } 
}

open class ですが、Kotlin はデフォルトで継承が禁止されています。なので、継承させるために open を指定あげます。class は察しの通りクラスの定義を意味します。

次の TestCase(var name: String) は、TestCase がクラスの名前で、括弧内はクラスの持つ変数の宣言とプライマリコンストラクタの仮引数を表します。このように書くことで引数の値が宣言されている変数内に格納されます。ちなみに name は、テストしたいメソッド名を持ちます。

理解しやすいように書くと以下と同じ意味になります。

// open class TestCase constructor(name: String) でも同じ意味
open class TestCase(name: String) {
  var name: String

  init {
    this.name = name
  }
}

これでコンストラクタと変数の初期化の仕方が分かりました。次は、メソッドです。 open fun setUp(), open fun tearDown() ですが、open でオーバーライドを許可しているメソッドになります。

fun run() メソッドですが、仮引数の TestResultクラスは、テスト結果をカウントするクラスです。 run メソッドは、テストを実行するメソッドです。初めにテストの回数を増やし、テスト前に必要な初期化処理を行います(実際は継承先でオーバーライドされている処理が走ります)。その後、例外処理の try ブロック内でメソッドを実行します。失敗したときにプログラムが終了しないように catch 内で テストが失敗したことをカウントします。

Kotlin のアクセス修飾子ですが、デフォルトでは public です。Java とは異なるので要注意です。

こちらが参考になると思います。 qiita.com

次に WasRun クラスを見ていきます。

class WasRun(name: String): TestCase(name) {
  var log: String

  init {
    log = ""
  }

  override fun setUp(): Unit {
    log = "setUp"
  }
  fun testMethod(): Unit {
    log = "${log} testMethod"
  }
  override fun tearDown() {
    log = "${log} tearDown"
  }
  fun testBrokenMethod() {
    throw Exception()
  }
}

WasRun クラスは、テスト対象となるクラスです。ここでは、TestCase のテストを行いたいので、TestCase を継承しています。class WasRun(name: String): TestCase(name) で使われているコロン(:)は、それのあとに書かれているクラスを継承することを意味しています。そして、コンストラクタに渡す引数として、WasRunクラスの変数を渡しています。 残りのメソッドは、オーバーライドをしていたり、テストに必要なメソッドを追加しています。testBrokenMethod() 内の throw Exception() ですが、見ての通りエラーを発生させています。

また、"${log} testMethod" のように文字列テンプレートを書くことが出来ます。

最後に、TestSuite クラスを見ていきます。

class TestSuite(val tests: MutableList<TestCase> = arrayListOf<TestCase>()) {

  var result: TestResult
  
  init {
    result = TestResult()
  }

  fun add(test: TestCase) {
    tests.add(test)
  }

  fun run(result: TestResult) {
    tests.forEach{
      it.run(result)
    }
  }
}

TestSuite クラスは、テストをまとめて行うためのクラスです。class TestSuite(val tests: MutableList<TestCase> = arrayListOf<TestCase>()) は、変数 tests に引数がなければデフォルト引数として arrayListOf<TestCase>() を入れるようにしています。 Kotlin の List についてはまだ詳しくないのですが、 readOnly と mutable なリストの二種類があります。簡単に紹介すると readOnly なリストは、中身を変えることができないリストで、 mutable なリストは、中身を変えることができるリストです。ただし、readOnly は以下のように書くことで中身を変えることが出来ます。

var list = mutableListOf(10, 20, 30)
var list2: List<Int> = list
list[0] = 33

リストについては以下が参考になると思います。

qiita.com

qiita.com

TestSuite では、様々なテストを tests にまとめておきます。そして run メソッドによってリストの中身をすべて実行していきます。

fun run(result: TestResult) {
  tests.forEach{
    it.run(result)
  }
}

簡単ですが、以上で Kotlin で作った xUnit の紹介を終わります。

Kotlin を使ってみた感想

書いてて楽しい言語だなと思いましたね。セミコロン必要ないですし、デフォルトで public になっていたり、継承がコロンだけで済んだり、また、継承もデフォルトで禁止されているのは良いなと思いました。null を許容しないのもいいですね。

Kotlin は、短く書けるけど何でもかんでも短くはしないというか、書きやすいと読みやすいのバランスが良いという感じがしました。

ぜひ仕事で使ってみたいので、修得してサーバやスマフォ開発で使いたいですね。

参考

入門するために読んだ本です。これは何か言語を知っていれば短時間で Kotlin にどんな機能があるのか把握できるので、とてもよかったです(何か言語を使ったことある前提)。

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

テスト駆動開発の本です。改訂版ですが、とても翻訳のクオリティが高く、言語も今に合わせて翻訳者が書き直してくれています。しかも付録として歴史的な話も載っています。さらに値段も安いです。すごいです…。

テスト駆動開発

テスト駆動開発

以下もおすすめらしいです。

Kotlinイン・アクション

Kotlinイン・アクション

記事内のコード

github.com

おれ、今の仕事納めたら Kotlin 勉強するんだ……

NgModule について

今回は、ngModule について説明していきます。 といってもまだ理解しきれていないので、簡単な説明ですが……。

NgModule

ng コマンドでプロジェクトを作成すると、app フォルダの中に、app.module.ts というファイルが作られます。 例えば以下のような感じです。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

この app.module.ts は、AppModule と呼ばれ、ルートモジュールとも呼ばれます。アプリの起動時は、初めにこのモジュールが読まれることになります。また、NgModule は一つだけではなく、FeatureModule を利用して、このルートモジュールの子として含めることができるようです。

アプリを起動するときに必要な情報を @NgModule に記述していきます。@NgModule を使えるようにするには、import { NgModule } from '@angular/core' を記述する必要があります。

@NgModule 内には、メタデータを定義していきます。

  • declaratons は、アプリに必要なコンポーネント、ディレクティブ、パイプを登録します。ng generate [component | directive | pipe] で作成した場合、自動で追加されます。
  • imports は、使いたい他のモジュールをインポートします(よく利用するものはこちらです)。
  • providers は、シングルトンにしたいサービスを登録します。
  • bootstrap は、アプリのルートとなるコンポーネントを登録します。

Angular は、JavaScriptimport と Angular の imports を使って、一部のモジュールを扱えるようにしています。最初は紛らわしいのですが、使っているうちに慣れていきます(それでいいのか……)。

モジュールのイントロダクション

簡単になりましたが今回はこのへんで。公式のドキュメントは充実してるので、一度目を通すことをオススメします。

NgModule

Angular を始める

comic-girls.com

アニメのこみっくがーるずが好きです。

仕事で Angular を使っていて、その仕事が一息ついたので学んだことをまとめていこうと思います。 Angualr の簡単な紹介は公式に任せます。

一つだけ補足しておくと、過去にAngularJS というものがありました。バージョン的には 1 扱いですが、2 以降との後方互換性はありません。AngularJS については、知る必要がありません。また、Angular(2 以上) について調べるとき、AngularJS の記事がよく引っかかります。参考にならないので、-angularjs を検索ワードにつけることをオススメします。

環境

  • Windows 10
  • Node.js 10.8.0
  • npm 6.2.0
  • Angular CLI 6.2.3
  • TypeScript 2.9.2

ここですること

  • Node.js のインストール
  • Angular プロジェクトの作成
  • 簡単なコンポーネントの構成紹介

Node.js のインストール

Angular を使うためには、Node.js を入れないといけません。 Node.js は、こちらからダウンロードしてください。 推奨版と最新版どちらでも好きなほうをダウンロードしてください。

Node.js のインストール方法は特に設定を変更することはないので、省略します。

Angular プロジェクトの作成

作成する前に、Angular をインストールする必要があります。 まずは、ちゃんと Node.js がインストールされているか確認しましょう。

> npm -v
6.2.0
> node -v
v10.8.0

次に、Angular CLI をインストールします(プロキシ環境下だとうまくいかないかもしれません。プロキシの設定をしてください)。

> npm install -g @angular/cli

インストールが完了したら、バージョンを確認して、ちゃんと入っているか確認します。

> ng -v

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 6.2.3
Node: 10.8.0
OS: win32 x64
Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.8.3
@angular-devkit/core         0.8.3
@angular-devkit/schematics   0.8.3
@schematics/angular          0.8.3
@schematics/update           0.8.3
rxjs                         6.2.2
typescript                   2.9.2

以上のような感じで表示されると思います。 では、プロジェクトを作成するので、作成したい場所に移動してから下記のコマンドを入力してください。

ng new my-app

実行が完了すると、プロジェクト(my-app)が作成されます。 my-app > src > app この下に必要なソースや html, css を作成していきます。 作業を始める前に、サーバを立ち上げて、Webブラウザで動作確認をしましょう。

> cd my-app
> ng serve
...
i  「wdm」: Compiled successfully.

最後の一行が表示されたら、Webブラウザを開き、http://localhost:4200 にアクセスします。 Welcome to my-app! という文字と Angular の画像が出たページが表示されると思います。 次に、簡単な変更をしてみましょう。

app.component.ts を開き、AppComponent クラスの title の中身を書き換えます。 自分は、以下のように書き換えました。

export class AppComponent {
+  title = 'The World';
-  title = 'my-app';
}

Webブラウザを確認しましょう。先に開いたタブを見ると文字が変わっているのが分かると思います。 何が起きたのかというと、変更を加えて保存をしたときにサーバ側が勝手に再度ビルドし、画面の更新を行ってくれます。 つまり、サーバを立ち上げ直す必要がなく、リアルタイムに動作の確認が出来ます。

簡単なコンポーネントの説明

最後に、コンポーネントを軽く紹介しておきます。 Angular は、一つのコンポーネントにつき、3 つのファイルが必要です(厳密には1つでもいけますが)。 それは、

  • TypeScript ファイル(.component.ts)
  • HTML ファイル(.component.html)
  • CSS ファイル(.component.css

の 3 つです。HTML と CSS は、TypeScript のファイルの中に直接書くことができるので、ファイルが必ず必要というわけではありませんが、現実的ではないでしょう。HTML と CSS は、Pug や SCSS のようなものも使えます(自分は書けないので使ったことがありませんが)。

.component.spec.ts は、コンポーネント単体テストのファイルです。そのコンポーネントのテストはここに書くことになります。

Angular では、ルートコンポーネントがあり、そのコンポーネントの中に別のコンポーネントを埋め込んでいくように作ります。 ルートのコンポーネントは、app.component です。例えば、hero というコンポーネントがあり、それを app コンポーネントに埋め込むとします。この場合、app コンポーネントの HTML ファイル(app.component.html)に以下を追加したい場所に記載します。

<app-hero></app-hero>

するとこの <app-hero></app-hero> の場所に hero コンポーネントの内容が追加されるようになります。 ここらへんは、話を聞くより実際に動かしたほうが理解できると思うので、Angular のチュートリアルをすることをオススメします。

Angular 日本語ドキュメンテーション

Visual Studio Code で Java 8 に対応する

全く更新してなかったけど、小さいことでも更新しようと思います。 苺ましまろ面白いです。アナ・コッポラちゃん可愛いよ。

最近、Java 8 を勉強中です。VSCode でStreamAPIを書くためにラムダ式を練習しようとしたら以下のような赤い波線が……。

f:id:pickles-ochazuke:20180731215430p:plain

ちなみに拡張機能として、Java Extension Pack を入れています。プロジェクトは、Maven で作りました。 で、先の問題を調べると以下を見つけました。

github.com

どうやらMavenによって作成される .settings/org.eclipse.jdt.core.prefs の中身が問題のようです。 自分のファイルは以下のようになっていました。

eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.processAnnotations=disabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.7

1.7 を 1.8 に書き換えます。

eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.processAnnotations=disabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

VSCode を再起動すると、以下のように消えました。

f:id:pickles-ochazuke:20180731215527p:plain

Team Geek を読んだ。

2013年に出た本ですが、今さら買って読みました。 読み物として読んだのであまりしっかり読んでいないですが、大事な話は1章に集約されている感じだったので、そこだけまとめようと思います。

ミッションステートメント

本書の目的は、プログラマがソフトウェア開発を効果的かつ効率的にするために、他人の理解・コミュニケーション・コラボレーションの能力を向上させることである。

というのがこの本の内容です。はじめに が来る前に書かれてあるのでそれぐらい重要な内容です。ここを理解してから本書を読み進めたほうがいいです。

全部で 6 章ありますが、進み方としては初めに自身の振る舞い良くする方法を提示し、2章でチームの文化を良くする方法、3章でチームリーダー、4章では害悪の人をなくす方法(人を排除するわけではない)、組織操作の方法、最後にユーザの扱い方を説明しています。

1章で説明されている HRT を基本としているので、他の章を読む前に 1 章を読むほうがいいでしょう。

天才プログラマの神話

世の中には、スゴいエンジニアがいるけど、その人たちのスゴさはエンジニアリングスキルではなく(もちろんそれ自体もスゴい)、チームをリードする力がスゴいという話。ソフトウェア開発は一人でするものではなく、チームで行うもの。チームスポーツなのだという。

世の中には、一人で隠れて開発したい人が多い。その人たちは自分の書いたコードやアイデアを人に見せるのが恐い。コードを見てバカにされないか、誰かにマネされて自分より先にプロダクトを世に出さないかが恐い。でも、公開されないソフトウェアは失敗する。相談する相手がいないので、過ちを犯しているのに気づかずに開発を進めているから。

早期発見

早い段階で、高速に、何度も失敗せよ

コードを書くときに全て書いてからコンパイルするだろうか? 少し書いて、コンパイル。少し書いて、コンパイル。失敗を早く見つけることで早く修正できる。これをコードだけでなくプロジェクトでも行う。環境は唐突に変わる。それに合わせて設計、計画を変えないといけない。じゃあこの失敗を早く気づくにはどうすればいいか。チームで仕事をするといい(人の数だけ早く気づける!)。

バス係数を高める

バス係数とは、プロジェクト関係者がバスにひかれても、そのプロジェクトを続けられる係数のこと。値が高いほどプロジェクトを続けられる。

これは、チームの文化、人の採用を強化することで高めることが出来る。人の採用はただ闇雲に集めればいいわけではない。本書の 3 章を参照。

集中する時間

エンジニアが開発するには、集中する時間が必要。誰にも邪魔されずにコーディングに集中できる時間が必要。邪魔して欲しくないときのルールを作ると良い。ただし、それ以上にチームとの高速で高帯域な連携は重要(たぶん 2, 4 章あたりの話)。

HRT

  • Humility(謙虚)
  • Respect(尊敬)
  • Trust(信頼)

人間関係の衝突は、この HRT の欠如によって起こる 。コミュニケーションの中心に HRT を心がけることが重要。

例えば、個人のエゴをなくす。自分の意見を押しつけない。集団のエゴを考える。それは、チームの功績や誇りなど。

例えば、批判をするときの言葉を選ぶ。相手のコードが間違っていると判断しても、相手に間違っていると言ってはいけない。提案をする。採用されないくてもいいような風に言うと良い。また、性格に対する攻撃的な非難をしてはいけない。コードはその人自身ではない。逆に批判を受けたときに非難されたと思わないこと。自分が書いたコードは、自分自身ではない。これをお互いに理解しておくことが大事。相手を尊敬していれば、非難しようと思わないはず。

信頼については、リーダーやユーザの話を参照(3 章、6 章)。

失敗から学ぶ。反復学習

過ちを犯したら文書化(ポストモーテム)する。文書化するときは、謝罪や言い訳を書かない。何を学んだか、何を変更するかを書く。見えやすいところに置いて、変更を継続できるようにする。
以下のことを書くと良い。

  • 概要
  • イベントのタイムライン
  • イベントの根本原因
  • 影響と損害の評価
  • すぐに問題を解決するための行動一式
  • 再発を防止するための行動一式
  • 学習した教訓

文書化されることで、同じ過ちをする人をなくすことができる。歴史を繰り返してはいけない。

チームの文化

チームの文化を強化することで、外部からの悪い文化を排除することができる。その悪い文化は、主に新来者が持ってくる。文化はリーダーが作るのではなく、メンバーたちが作るもの。メンバーたちが持つことで、新来者へ継承できる(バス係数が高まる)。優れたチーム文化は、ソフトウェアを届けることに集中している。

効率的なエンジニアリング文化は、同期コミュニケーションを減らし、非同期コミュニケーションを増やす。会議(同期コミュニケーション)には、必要な人しか集めない。早く終わるように工夫する。決まったことは、メーリングリストで報告する。電話、ビデオ通話、チャット、メールなど(非同期コミュニケーション)を駆使する。あらゆるツール、あらゆる手法を使ってコミュニケーションを強化し、効率的に開発を行えるようにする。

ミッションステートメント

そのプロジェクトのミッションステートメントを決める。何をして、何をしないのか。これを決めないと永遠に肥大化する。また、ミッションステートメントは変化するときがある。会社の環境やプロダクトの方向転換があれば、ミッションステートメントもそれに合わせて変える必要がある。

おわり

この本、ページ数が少なく200ページにも満たないので軽い気持ちで読めました。何か役立てるために読むというより、読み物として読んでいましたが、楽しく、興味深い内容でした。ここにまとめたのは、1章、2章が主ですが、3~6章も大事なのでいつかまた読みたいです。とりあえず HRT を意識できるようにならないといけないかなと思ってここにまとめてみました。

とても上手に翻訳していただいた角 征典(かど まさのり)さんに感謝です。

今回からここに載せている元の文書を Github で管理するようにしてみました。 github.com