GeekFactory

int128.hatenablog.com

ITのビジネス価値を最大化するには

2016年になってもアジャイルはテストをしないとか、計画を立てないとか、1日10回デプロイするための技法といった誤解が広まっているのは残念すぎる。

まず、ITのビジネス価値を最大化するという視点が必要なはず。事業の売上や費用を改善するためにシステムを活用するのであって、システムを作ること自体は目的にならない。

事業を取り巻く環境は変化が速いので、ITもそれに合わせて変えていく必要がある。1年後にシステムが完成したら事業環境が変化していて役に立たないかもしれない。投資が無駄になるリスクを抑えるために、数週間で軌道修正を繰り返す。

だから、事業環境の変化にITを対応させるためにアジャイルが必要、という話の流れになるはず。システムを作るためにアジャイルが必要とはならない。事業上の必要性からアジャイルを選択する。

ここまできて初めて、ITのビジネス価値を最大化するためにスプリントや自動デプロイといったやり方が出てくる。やり方だけでは不十分で、事業と開発が一体になるための組織構造や開発スキルを評価するための人事制度も必要になる。そもそも、事業環境の変化に対応できる事業計画の立て方が必要なはず。

なので、適度に偉い人が「事業上の必要性」を言い出して「事業環境の変化が速い領域」で試行錯誤するのが王道なんじゃないかなぁ。これはEnterpriseでもServicerでも同じはず。クラウドもこんな感じで広まったはず。

もうアジャイルという言葉をやめた方が誤解が生じなくてよいのでは。マックスバリューデベロップメントあたりでいいと思う*1

*1:誰か突っ込んでくれるかな

TestKitによるGradleプロジェクトのテスト

最近のGradleで導入されているTestKitを使ってみたのでメモします。

TestKitでできること

TestKitを利用すると、Gradleプロジェクトに対するテストを実行できます。例えば、何かの設定ファイルを自動生成するタスクをGradleで定義している場合に、そのタスクに対するテストコードを記述できます。TestKitはSpockと併用できるので、BDDスタイルでテストコードを書くこともできます。

この仕組みを応用すると、Gradleプラグインを適用したプロジェクトに対するテストを実行できます。Gradleプラグインの受け入れテストとも言えますね。詳細は The Gradle TestKit - Gradle User Guide Version 2.14 を参照してください。

使い方

ここでは、テスト対象のプロジェクトがGradle 2.13と1.12の両方でちゃんと動作するかテストする例を考えます。

  • build.gradle - テストを実行するプロジェクト
  • src/test/groovy/ExampleSpec.groovy - テストコード
  • fixture/build.gradle - テスト対象のプロジェクト

まず、テスト対象のプロジェクトを作ります。単にGradleバージョンを表示する雑なビルドスクリプトにしておきます。

// fixture/build.gradle
task show << { println gradle.gradleVersion }

それから、TestKitを利用してテストを実行するプロジェクトを作ります。

// build.gradle
plugins {
    id 'groovy'
    id 'java-gradle-plugin'
}

repositories {
    jcenter()
}

dependencies {
    testCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
        exclude module: 'groovy-all'
    }
}
// src/test/groovy/ExampleSpec.groovy
import org.gradle.testkit.runner.GradleRunner
import spock.lang.Specification
import spock.lang.Unroll

class ExampleSpec extends Specification {

    @Unroll
    def "test should be success on Gradle #version"() {
        when:
        GradleRunner.create()
                .withProjectDir(new File('fixture'))
                .withArguments('show')
                .withGradleVersion(version)
                .forwardOutput()
                .build()

        then:
        noExceptionThrown()

        where:
        version << ['2.13', '1.12']
    }

}

テストを実行してみます。

./gradlew check

テストレポートを確認すると、テストケースが2つ実行されて、それぞれ2.13と1.12が表示されていることがわかると思います。

Gradle SSH Pluginへの適用

Gradle SSH PluginはGradle 1系も動作対象に含めているため、受け入れテストを2.13と1.12で実施しています。これまではGradle Wrapperのプロパティファイルを無理やり書き換えて複数のバージョンでテストを実行しましたが、TestKitを利用することで独立した環境でテストを実行できるようになりました。

以下の流れでビルドを実行しています。

  • プラグインプロジェクトをビルドする(test
  • プラグインプロジェクトの成果物をMaven Localにリリースする(publishToMavenLocal
  • 受け入れテストプロジェクトではMaven Localに存在するプラグインを適用する(buildScriptrepositoriesmavenLocal()を指定し、apply pluginを実行)
  • 受け入れテストプロジェクトを実行する

プラグインの受け渡しはGradle 2.8以降であれば withPluginClasspath() が使えるのですが、今回はGradle 1系でテストする必要があるのでMaven Localを採用しました。

TestKitはプラグイン開発者には便利かもですね。

VyOSでIP masqueradeの最小構成

VyOSで最小限のルータを設定する時のメモです。

前提

設定

GLOBAL側とINTERNAL側のインタフェースを設定します。

set interfaces ethernet eth0 description GLOBAL
set interfaces ethernet eth0 address x.x.x.x/x

set interfaces ethernet eth0 description INTERNAL
set interfaces ethernet eth0 address 192.168.0.1/24

デフォルトゲートウエイを設定します。

set protocols static route 0.0.0.0/0 next-hop x.x.x.x

INTERNAL側からGLOBAL側へのIP Masqueradeを設定します。

set nat source rule 100 outbound-interface eth0
set nat source rule 100 source address 192.168.0.0/24
set nat source rule 100 translation address masquerade

INTERNAL側のDHCPサーバを設定します。

set service dhcp-server disabled false 
set service dhcp-server shared-network-name INTERNAL subnet 192.168.0.0/24
set service dhcp-server shared-network-name INTERNAL subnet 192.168.0.0/24 default-router 192.168.0.1
set service dhcp-server shared-network-name INTERNAL subnet 192.168.0.0/24 start 192.168.0.100 stop 192.168.0.200
set service dhcp-server shared-network-name INTERNAL subnet 192.168.0.0/24 dns-server x.x.x.x

GLOBAL側からINTERNAL側へのPort Forwardingを設定します。

set nat destination rule 1 destination address x.x.x.x
set nat destination rule 1 destination port 3389
set nat destination rule 1 inbound-interface eth0
set nat destination rule 1 protocol tcp
set nat destination rule 1 translation address 192.168.0.100

参考資料