ASP.NET MVC 6 でデータベースに接続(データベースファースト編)

前回の続きで、今度はデータベースから構築するパターン。基本的なところは、ASP.NET5 MVC6 Entity Framework 7 を使って Database First する と同じで、あらかじめ SQL Server で作ったテーブルをもとに ASP.NET MVC の Model クラスを作る。

ASP.NET MVC 6 の Web Application テンプレートを使う

こちらも、Web Application のテンプレートを使う。無駄なページができるのは仕方がないのだが、project.json などの設定がそのまま使えるので活用する。

SSMS(SQL Server Mangement Studio)でテーブルを作成する

ここではローカルPCに SQL Server を入れて testdb に「Movie」というテーブルを作っている。前回のとテーブル名を合わせると比較しやすい、ってのとどうやらテーブルに主キーとIDENTITYが設定していないと Model クラスの作成に失敗するので、元の Movie クラスから引っこ抜いている。

テーブル作成時にスクリプトはこんな感じ。

USE [testdb]
GO

/****** Object:  Table [dbo].[Movie]    Script Date: 2016/02/04 0:31:47 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Movie](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[Genre] [nvarchar](max) NULL,
	[Price] [decimal](18, 2) NOT NULL,
	[ReleaseDate] [datetime2](7) NOT NULL,
	[Title] [nvarchar](max) NULL,
 CONSTRAINT [PK_Movie] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

ちなみに、最近の SSMSは後から列名の変更をしたり、IDENTITYの設定をし直したりできない。昔はできたような気がするのだが、最近の SSMSを使うとエラーになる。SQL Server のスクリプトで直接「alter table …」を使うと変更ができるので SQL Server 側の制限ではないらしい。MySQL の Workbench では自由にできるのでかなり残念。

…と思い続けていたのだけど、SSMSのオプションで [デザイナー] 部の [テーブルの再作成を必要とする変更を保存できないようにする] とできるようになる。これはハッピー。

project.json に EntityFramework.MicrosoftSqlServer.Design を追加する

SQL Server から Model クラスを作るときは「EntityFramework.MicrosoftSqlServer.Design」が必要なので、NuGet から取得しておく。
取得しないまま、「dnx ef …」をすると、きちんとエラーを返してくれるので、それに従ってもよい。

Unable to find design-time provider assembly. Please install the EntityFramework.MicrosoftSqlServer.Design NuGet package and ensure that the package is referenced by the project.

dnx ef で Model クラスを作る

ちょっとややこしいけど、次のように書くと Models フォルダに対象データベース内にあるテーブルの EF を作ってくれる。

dnx ef dbcontext scaffold "Server=.;Database=testdb;Trusted_Connection=True" EntityFramework.MicrosoftSqlServer --outputDir Models

Azure とかにつなぐ場合は(たぶん)接続文字列を変えればよい。出力先は、–outputDir で指定して今回は Models フォルダ内にしてある。

これを動かすと、Visual Studio のほうに EF クラスと接続のための testdbContext クラスを作ってくれる。接続用のクラスは、「データベース名」+「Context」になるようだ。

スキャフォールディングで、Controller と View を作る

Model クラスができたので Controller と View を自動生成させる。
「追加」→「コントローラー」を選択して、「Entity Framework を使用したビューがある~」のほうを選ぶ。

モデルクラスで「Movie」を選んで、データコンテキストクラスでは「testdbContext」のほうを選ぶ。

ちなみに、testdbContext クラスは、元のテンプレートにある ApplicationDbContext と同等の機能を持つデータコンテキストクラス。接続先のデータベースがハードコーディングされているので、デフォルトでここに直結という感じになっている。きちんと手を加えれば、ApplicationDbContext と同じように applications.json から読み込めるようにできるだろう。

public partial class testdbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlServer(@"Server=.;Database=testdb;Trusted_Connection=True");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Movie>(entity =>
        {
            entity.Property(e => e.Price).HasColumnType(&quot;decimal&quot;);
        });

        modelBuilder.Entity<person>(entity =>
        {
            entity.Property(e => e.name)
                .IsRequired()
                .HasMaxLength(50)
                .HasColumnType(&quot;varbinary&quot;);
        });
    }

    public virtual DbSet<Movie> Movie { get; set; }
}

データベース接続のために Setup.cs を書き換える

データベースコンテキストを使って接続するので、Setup.cs に AddDbContext なところを書き加える。

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration[&quot;Data:DefaultConnection:ConnectionString&quot;]));

	// ここを追加する
    services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<testdbContext>();

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

実行してみる

動かしてみた結果がこれ。コードファーストのときと同じように CRUD を動かすことができる。

SSMS を使って select してデータ確認もできる。

カテゴリー: ASP.NET | 2件のコメント

ASP.NET MVC 6 でデータベースに接続(コードファースト編)

コードファースト自体は結構前に話題になったハズなのですが、ASP.NET MVC 6 でデータベースに接続する場合にはなんだかよくわからなかったので再調査。いやいや、データベースから POCO を作ることはあまり重要ではなくて、ASP.NET MVC 6 自体なんだけど…まあ、EF(Entity Framework)が扱えたほうがいいので、ちょっときちんと手順を追ってみる。

チュートリアル的にはいろいろあって、

を使って手早く済ますのもよいし、Getting started with ASP.NET MVC 6 ? ASP.NET MVC documentation にチュートリアルがあるので、それに沿って進めてみる。急がば廻れというスタイルです。github のほうは、ちまちま作っている途中らしいので抜けもあるけど、Building your first MVC 6 application からの一連の操作はひと通りできているようです。英語だけど、画面キャプチャが貼ってあるので分かりやすいはずです。

本来やりたいことは

本来やりたいことは、テンプレートを使わないシンプルな ASP.NET MVC を作りたいのだけど、実はなにやら設定がややこしい。一度、Empty のテンプレートから作ってみたもののうまく DB に接続できなかったので、これは後で調べてみる。ポイントとしては、

  • project.json に必要な dependencies を追加する。
  • ApplicationDbContext クラスを用意する。
  • POJO な Model クラスから dnx ef を使ってデータベースを作成する。

するらしい。後で手順を追いなおしてみる。

ASP.NET MVC 6 の Web Application テンプレートを使う

project.json の設定と ApplicationDbContext クラスがややこしいので、Getting started with ASP.NET MVC 6 に従って、テンプレートをそのまま使う。

image

あれこれ無駄なページができるのだけど仕方がない。最終的には Empty から作れるようにする。

image

POJO な Model クラスを作る

Adding a controllerAdding a view はチュートリアル的に流せば ok。ここで必要なのは、Adding a model になる。

手順通り Models/Movie クラスを作る。このあとスキャフォールディングを使って、Movie クラスに対応するコントローラとビューを自動作成する。

「追加」→「コントローラ」を選択して「Entity Frameworkを利用したビューがある…」を選択する。

image

対象となるモデルクラス(Movieクラス)を選択して、データコンテキストでは「ApplicationDbContext」を選ぶ

image

ApplicationDbContext はローカルPCにデータベースを作る方式で、もともと ASP.NET MVC 6 の Web Application に入っているものでユーザー認証とかに使っている。だから、自前で Empty プロジェクトから作るときは、ApplicationDbContext クラスと ApplicationDbContext クラスあたりを自前で作る必要がある(と思う)。

データベースの設定自体は、Startup.cs の ConfigureServices メソッド内に書かれていて、

// Add framework services.
services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration[&quot;Data:DefaultConnection:ConnectionString&quot;]));

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

なところで DI 化されている。配布を考えると project.json にあったほうがいいのだが、試験的に使うのであれば直書きしてもいいと思う。

dnx コマンドで Entity Framework を作る

EF を使ったほうが LINQ が使えるようになる(そのためにわざわざコードファーストしている)ので、EF に対応させるのだがデザインでやるのではなくコマンドラインから実行する。ここの部分、最終的に DB から各テーブルを読み込んでという形になるのかコマンドラインのままなのかはわからないけども、Linux 上で ASP.NET MVC + EF + MySQL という組み合わせを考えたときにはコマンドラインでできたほうがよい。この手順は Use data migrations to create the database あたりから書いてある。マイグレーション(migrations)というスタイルで、EF クラスと DB のテーブルとを相互に反映させる仕組みになる。あれこれ書いてあるけど、コマンドラインで project.json のあるフォルダを開けばよい。

dnu restore
dnx ef migrations add Initial
dnx ef database update

dnu や dnx と打ったときにコマンドが見つからないと言われたときには、パスなどを設定するために

dnvm upgrade

するのだが、そもそも dnvm 自体がないといわれるときには、c:¥users¥ユーザ名¥.dnx¥bin にある。このあたりの手順は Installing ASP.NET 5 On Windows にある。Mac 版、Linux 版もあるのでインストール時に一度やっておけばいいだろう。

image

dnvm use 1.0.0-rc1-update1 -p を実行していないのは、dnvm upgrade したときのバージョンをそのまま使うからだ。

そんな訳で、うまく DB が作成されるとデバッグ実行ができるようになる。Create New でデータ登録をしてリストを表示させることも可能。

image

ローカルデータベースは何処にあるのか

できあがった ASP.NET MVC のサンプルを動かすとデータが保持されているようなので、どこかにデータベースがあるはずだ。MVC 5 の場合は、App_Data の中にローカルデータベースがあってそれを参照していたのだが、MVC 6 の場合にはそれがない。

何処にあるのだろうかと調べると Setup.cs の

services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration[&quot;Data:DefaultConnection:ConnectionString&quot;]));

から、設定の Data:DefaultConnection:ConnectionString から接続文字列を読み取っているらしいことが分かる。

そこで applications.json という設定ファイルらしくものを覗くと

"Data": {
  "DefaultConnection": {
    "ConnectionString": "Server=(localdb)mssqllocaldb;Database=aspnet5-CodeFirst2-848a6bc9-9651-4b68-a5db-8b56f15a8be0;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
},

と書いてある。なんか接続文字列っぽくて、スキーマ名が 「mssqllocaldb」になっている。Working with SQL Server LocalDB にも書いてある。試しに SSMS(Sql Server Management Studio)を使って (localdb)mssqllocaldb を開いてみると、うまく接続できた上にそれらしいデータベースができていることが分かる。

image

データベースのプロパティを見れば、保存場所のわかる。

image

どうやら、c:usersmasuda の直下に置かれている。ああ、確かに豪快に Cドライブに置かれていることが分かります。まあ、これだとユーザー領域とか Cドライブを圧迫しちゃうよねという感じなので、これは別途データベース接続文字列を書き換えて元の SQL Server などに移せばよいでしょう。

image

これがコードファーストなので、コードからデータベースを生成する方法。だが、普通は既存のデータベースを使って EF なクラスを作るような CakePHP の Bake のような方法をとると思うので、これも後で試してみる。

ノーム・チョムスキーとコードファーストな余談

ふと Noam Chomsky: Bernie Sanders has the best policies な記事にあたって、チョムスキーが87歳で健在なことを知る。チョムスキーといえば言語学者で人工知能絡みで対話型の形態素解析とかで出てくるんだけど(最近では人工知能というと自動運転とか深層学習とかになっているので「言語」から離れているが)「哲学者」というよりもレッキとした科学者だ。言語の発生から扱い方はウンベルト・エーコの「ウンベルト・エーコの文体練習」を合わせて読むといい。いちだいブームになった「薔薇の名前」や「フーコーの振り子」も読んでもいいかもしれない。「薔薇の名前」がマスコミ的にもブームになったのは、そういう余裕があった時代ではなかったのかなと思ったり。

で、言語学的に言えばプログラミング言語も「言語」のうちだろう。非常に限られた文法しか持たない(最終的には厳密なアセンブリに変換するという束縛があるので)し、限定的な使われ方しかしないから、普通の自然言語とは違った見方がされる。狭いプログラム言語の中で、C# という言語があって、SQLという言語がある。コードファーストってのは、C# のコードの言語を、SQL という言語(正確にはデータベースの世界)に変換することだ。それを「テクスト」と言い直せば、C# が持つテクストと SQL が持つテクストを結び合わせて同じコンテクストで語ろうという話だ。翻訳の世界と同じになる。当然、日本語と英語のように、というよりも日本国内でも東北弁と鹿児島弁の違いのように単純な変換だけでは済まない。片方のテクスト上で語られるものは、片方のテクストの一語としては対応するものがない。しかし、とあるテクストが全体を網羅を持つという前提条件を付ければ、別のテクストはもうひとつのテクストに対して語数の違いはあるかもしれないが正確に変換できることになる。2つのテクストが存在する空間が、完全に重なりあっていないのであれば変換しえないものが出てくる。これがコードファーストとデータベースファーストとO/Rマッピングのインピーダンスミスマッチだったり、それぞれの違和感だったりする。ただし、「完全に一致する」ことを捨て去ってしまい、ある程度の共有領域を多くするという方針にすれば言語同士の変換は比較的楽になる。

このあたり、Scratch をはじめとする教育用言語も同じだよなーと。「教育用」という縛りを設けるのか、プログラミングをする思考に対する完全性を重視するのか(いわゆる道具立て)というところで、そこに「子どもだから」というプログラム言語的な欠損を最初に認めて作ってしまうと、そもそもが「教育」→「プログラミングができる」の達成すら危うくなってしまうのではないかなーと思ったりもする。だら、あくまで「プログラミング的な思考を養う」のほうがよいのかなと。

教育はさておき、現実的なところで言語で伝えることの限界と、その厳密性を突き詰めていくと、修辞法やら過去の習慣やら小学校での教育やらを含めて、相手とのずれとそれを許容する現実がある。それと同時に、許容できない現実もあることを認める…というか許容しなくても良いというのがある。なんというか、自分だけを中心にして世界が廻っているような人が権力を持つと(どういう経緯なのかよく知らんけど)あれこれ変なところに逝ってしまうんだなーと呆れたりする。まあ、現実的に呆れてもどうしようもないところに落ち着く前に、チョムスキーのように「いい加減にしろよ」ぐらいの釘は刺したほうがいいかもね。半藤一利によれば下り坂の30年間だったりするのだから。

カテゴリー: ASP.NET | 2件のコメント

Xamarin.Froms を使ってパズドラのように駒を動かす

Xamrin.Forms のドラッグシリーズの続き
ひと駒だけドラッグができたので、今度は複数の駒を移動させてみます。いわゆるパズドラのように隣の駒を入れ替えながら動かすというやつですね。

やっていることは前の BoxView のドラッグと同じで移動時のイベントを ManipulationDelta に変換して PCL にコールバックします。

AbsoluteLayoutに配置する

位置がわかりやすくなるように、AbsoluteLayout を使っています。UWP の Canvas に似た動きをしますね。iOS/Android/UWP の3種類でどういう作り方をしているかは知らなくても大丈夫です。Xamarin.Froms の AbsoluteLayout タグに則って配置させます。

/// <summary>
/// 初期化ボタン
/// </summary>
/// <param name=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
private void clickInit(object sender, EventArgs e)
{
    var cols = new List<Color>()
    {
        Color.Red,
        Color.Navy,
        Color.Yellow,
        Color.Pink,
        Color.Purple,
    };
    var rnd = new Random();

    // キャンバスに Box を25個並べる
    boxes = new List<BoxViewEx>();
    for (int i = 0; i < 25; i++) {
        var box = new BoxViewEx();
        boxes.Add(box);
        canvas.Children.Add(box);
        int w = 60;
        int h = 60;

        int x = (i % 5) * (w + 10) + 30;
        int y = (i / 5) * (h + 10) + 30;

        var rect = new Rectangle(new Point(x, y), new Size(w, h));
        box.LayoutTo(rect);
        box.BackgroundColor = cols[ rnd.Next(cols.Count)];
        box.ManipulationDelta += Box_ManipulationDelta;
        box.ManipulationCompleted += Box_ManipulationCompleted;
        box.ManipulationStarted += Box_ManipulationStarted;
    }
}

BoxView のタップイベントは、BoxView 自身につけています。自前の ManipulationDelta のコールバックでは移動している BoxView のオブジェクトそのものを sender として渡すので、このコールバックを AbsoluteLayout に集約してしまっても大丈夫なはずです。

タップ操作イベント

BoxView を移動させて隣の駒の中心付近になったときに駒の入れ替えをします。このあたりは感覚的なものがあるので実地で調節するのと、素早く動かしたときに SingleOrDefault なところでエラーになるので注意が必要です。これは LayoutTo メソッドを使ってアニメーションで駒を移動させているからです。Layout を使ってパッと移動させても良いのですが、ひとまずゲームっぽい感じで。

/// <summary>
/// ボックスの移動開始
/// </summary>
/// <param name=&quot;arg1&quot;></param>
/// <param name=&quot;arg2&quot;></param>
private void Box_ManipulationStarted(object sender , EventArgs arg2)
{
    var box = sender as BoxViewEx;
    /// 移動開始位置を覚えておく
    boxBlank = box.Bounds;
}
private bool _flag = false;
/// <summary>
/// box の移動中
/// </summary>
/// <param name=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
private void Box_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    // box の中心が他のboxに入ったときに入れ替える
    var box1 = sender as BoxViewEx;
    double x1 = box1.Bounds.Left + box1.Bounds.Width / 2;
    double y1 = box1.Bounds.Top + box1.Bounds.Height / 2;

    // 1.中心が他のboxに入っていないか調べる
    try {
        var box2 = boxes
            .Where(x => x != box1)
            .SingleOrDefault<BoxViewEx>(x => x.Bounds.Contains(x1, y1));
        if (box2 == null) return;

        if (_flag == true) return;
        _flag = true;
        // 2.中心に入っていれば、空位置へ移動する
        var b = boxBlank;
        boxBlank = box2.Bounds;
        box2.LayoutTo(b).ContinueWith((_) => { _flag = false; });
    }catch
    {
        return;
    }

}
/// <summary>
/// タップを離したとき
/// </summary>
/// <param name=&quot;arg1&quot;></param>
/// <param name=&quot;arg2&quot;></param>
private void Box_ManipulationCompleted(object sender, EventArgs arg2)
{
    // 移動中の box は空きに収まるように移動させる
    var box = sender as BoxViewEx;
    box.LayoutTo(boxBlank);
    boxBlank = new Rectangle(); // 空にしておく
}

そんな訳で次は、カードゲームでよくある強化カードを選ぶ、みたいなドラッグサンプルを。

サンプルコード

moonmile/PazzleDrag
https://github.com/moonmile/PazzleDrag

カテゴリー: C#, Xamarin | Xamarin.Froms を使ってパズドラのように駒を動かす はコメントを受け付けていません

追悼 デスマーチ

「デスマーチ」の著者 エドワード・ヨードン氏が亡くなったそうなので、追悼記念に書き下しておく。ちなみに、ツイッターでも書いたけど「デスマーチ」は「終わりなき行軍」を意味するので、現在の短納期(半年ぐらい)のプロジェクトは当てはまらないと思う。そういう場合は、すでに精神が「デス」か「Dead」してしまう場合が多いので別なラベリングが必要だろう。「お前は既に死んでいる」…でもいいけど、意味が違うから別なのを考えよう。

「デスマーチ」を手に取った頃

私が「デスマーチ」を知ったのは、まだ阿佐ヶ谷に住んでいたころだから一人暮らしで寝て起きて渋谷だったか新宿だったかに通っていたころだ。20年前になると思う。DoCoMo のプロジェクトで i-mode の前身を作っていたころだ。いまでこそ i モードを知っている人は少なくないけど(つーか、終わっているから知らない人のほうが多いかも)当時、なんだかわからない2,3年目の新人が、なんだかわからないプロジェクトのまま、なんだかわからない新宿の地下で毎日仕事をしているのは、いま考えればちょっと精神が病みそうな感じだったのだと思う。だが、会社員としてのプログラマをやりつつ、流行りだしたインターネット&ホームページ作りをやりつつということで、仕事と自分の将来を折り合いが付くか付かないかのぎりぎりのところだったと思う。

そういう頃に、プログラミング(当時は VB や C++ が主流)の技術のあれこれとともに、いつ果てるともない仕事の流れに漂っている感じ、朝会社に行く昼を食べる夕方に夜食を少し食べる10時頃に新宿を出る、という毎日を続けていた。合間にプログラミング&テスト&不具合直しを繰り返して、自分の担当の仕様をあれこれ考えてやっていても、多少プログラミングの腕に自信があるぐらいではどうしようもない量の仕事(プロジェクト自体にかかわっているのは、自社で30名弱、他社も入れれば200名ぐらいだろうか)があって、徒労感がひどい状態だった。でも、まあ、こういうのが「仕事」かもしれないと思ってやっていたころだ。

ふと、阿佐ヶ谷の本屋でいつもの技術書コーナーじゃなくて(当時はコンピューターの本はたくさん棚に並んでいたのだ)、なにかちょっと読みものっぽいコーナーを見た。「人月の神話」を買った前後だったか覚えていないのだが、「デスマーチ」という薄い本(日経BPのは分厚いけども、当時はもっと薄かった)があった。日経BPのほうでは挿絵を削られてしまっている(と思う)のだが、当時の本には、行軍のイラストが書いてあった。

ある意味、それだけで私は「デスマーチ」という本は十分だったのである。

見えない現象に名前を付けるということ

タイトルを失念したが、細野不二彦の漫画に「子供に見えない恐怖に名前を付けて克服できるように教える」というシーンがある。もともと現象なり恐怖なりはそこにあるものだけど、それを認識するためにはなんらかの「認識する」行為そのものが必要となる。それが「名前付け」であり、認知学の基本だったりする。現象学を紐解けば、シニフェ/シニフィアンという対応がとられているのがわかる。

いつ終わるともわからないプロジェクト、完成がいつかわからないプロジェクト、毎日忙しいけれどそれがいつ忙しくなくなるのかがわからないプロジェクトが2,3年続けば、それは「デスマーチ」プロジェクトと言ってよい。当時は、プロジェクトの成功率が 30%程度(日本の成功率が高いのは、「失敗したと認めない」からだ)だった。もっと厳密に「成功率」を考えれば、

  • 当初、計画した期間でプロジェクトを終わらせる
  • 当初、計画した予算(人員)でプロジェクトを終わらせる
  • 完成時に、当初の要望を満足できる形で製品が完成される

のが「成功」と言えるだろう。もちろん、もっとゆるゆるにして「ほぼ成功」とか「一部成功」なんてことも言えるけど、きちんと計画駆動(ウォーターフォール)するのだったら、成功の定義ぐらいきちんとして欲しいところだ。まあ、カウボーイプロセスも似た感じではあるけれど。

そういうものを曖昧にしたまま、「仕事」だからというスタイルでずるずるとソフトウェア開発をしていると、それは「デスマーチ」だ。目標もゴールも予算もなにもない。ただ「行軍」だけが目的化してしまった状態だ。

その渦中にいると、なにでこうなっているか分からないのだが、一度「デスマーチ」という名前付けをしてしまうと、一方で「デスマーチではない状態とは何か?」がわかってくる。いくつか「デスマーチではない状態」を列挙してみれば、

  • 納期が決まっている(それが不可能であっても、動かない納期がある)
  • 予算が決まっている。予算がなくなれば、プロジェクト自体が死ぬので、デスマーチも止まる。
  • タスクが決まっている。クリアすべきタスク/機能がわかっていれば、それさえ作ってしまえば、いつでもプロジェクトを終わらせられる。

という状態がある。なので、2000年頃からスタートした Web 開発の場合、短納期であることが多いので「デスマーチ」にならない。その代り「デス」=「即死」してしまうことはある。

ヨードンとデマルコ

実は、エドワード・ヨードン氏は数学者で(だったよね?)数学的なアプローチでソフトウェア開発プロセスを組み直そうとしている。構造化分析とかシステムダイナミクスとかそれだ。一方で、がちがちの管理主義者だったデマルコ氏だが一変して「ピープルウェア」を提唱している。このあたりは(今思えば)両者ともコンサルタントの立場から離れないという感じで、あまりプログラミングそのものには介在しないような感じなのではあるが、「ソフトウェア開発」というもの自体が「営利活動」である間は、経営/雇用/被雇用/外注などの普通の会社と変わらないものが出てくる。そこのあたりはドラッカー言うところの、何処に「顧客を創る」かだ。

おそらく、そのあたりで SAP などの BI(ビジネス・インテリジェンス)ブームに乗ってしまったと思うのだが、この二人がプロジェクト・ナビゲーターを作っていた頃の講演を聞きにいったことがある。

当時の私は、会場で手を挙げて質問をするのが趣味だったので、数学者としてのヨードン氏に質問をした。「TOC(制約理論)を応用した CCPM をどう思われるでしょうか?」。私のほうは TOC にハマっていた頃で、CCPM を自分の会社に応用できればいいかと思っていろいろ考えて、同時に XP をはじめとするアジャイル開発界隈にも顔を出していた頃だった。彼の答えの雰囲気としては、「TOC は非常に素晴らしい/興味ある理論だけども…」という感じだった。まあ、そりゃそうだ。一方で「プロジェクト・ナビゲーター」を売り出していこうとしたところで、TOC/CCPM の話をされたらあまり良い気はしなかったのだろう。

プロジェクト・ナビゲーターの最大の欠点は?

その講演があったのは10年前ぐらいだろうか。アジャイル開発が盛り上がっていた頃でもあって、管理側と開発側の対立が顕著になっていた頃だ。むろん、アジャイル開発をする場合には、スクラムプロセスのように管理と開発が一体にならないとダメなのだが、もともと管理側の人間からすれば「人を管理する」に徹するほうが分かりやすかったりする。少なくtも、管理側の人間からすれば、管理するのが楽なのだ。あたりまえだけどそういう視点がある。このあたりはワインバーグの「ライト、ついてますか」にもあって、「管理者になれ、被管理者になるな」ってのがある。

私が、BI が胡散臭いと思っているのは(今の BI はわからないが、当時の BI は非常に胡散臭かった)、現状だけを眺める、いわば工場のラインを上から眺めるだけの仕事になっているからだ。そのラインで働いている人のことを全然考えていない。というか、そのラインで働いている人を「バカ」だと思っているか、そういう制限された能力しかない(少なくとも、管理者を超える能力や、管理者が想像もできないような能力は思いもよらない)というのが前提になっている。だから、ラインで働いている人は、飛び抜けて出来ても困るし、もちろん飛び抜けてできなくても困る。そういう「ソフトウェア・ファクトリ」(昔の Microsoft のスローガンだ)の視点でしか見ない現象である。以前は、こういう会社を憎んでいた私でははあるが、いやいや今だだと旧態依然でやってくれたほうが相対的に自分に利益になることが分かったので放置である。だって「仲間」じゃないんだもん。

でもって、「ナビゲーター」の話に戻ると、それは株のデイトレーダーと同じように開発プロセスを見ることを目的としている(ヨードンは「デイトレード」という名称を使わなかったけど、絵柄はそっくりだ)。確かに、経営的な視点とかマクロ的な視点とかであればいいのだが、どうもそういう尻馬に乗っているスタイルは私は好きではない。いや、もっと積極的に言えば、尻馬に乗るぐらいだったら、馬自体の能力をもっと引き出したらどうだろうか?ってな具合だ。

「ナビゲーター」は現状を数値化して不都合のありそうなところをフォローするように働きかけることができる。いわば、マイナス部分を削っていけば、プラスだけが残る。少しずつ平均を上回るということだ。私も「マイナス削除」の方法をとることはあるけど、それはミクロ的なレベルだ。けれど、マクロ的にマイナスの削除をするということは、人を部品として切り捨てるということになる。あるいは、人を標準化するということになる。

もちろん、CCPM も含めて「部分最適化」よりも「全体最適化」のほうが効果が大きいことがわかっている。CCPM もプロジェクトナビゲーターも全体を俯瞰するというツールという点では同じだ。進捗状況を、Excel で管理したり、MS Project であれこれとやったり、バーンダウンチャートを作ったりするのも同じだ。全体の俯瞰するためのツールである。が、全体を俯瞰して弱点を見つけたあとに何をするかというのが「プロジェクトナビゲーター」にはない。いや、なかった。弱点を補強するのか、差し替えるのか、または全体をシミュレーションし直すのかという視点がナビゲーターにはない。それは、あくまでも俯瞰するための「図」でしかなくて、ナビゲーションしていない。そうそう、弱点を補強するという形では、ツェッペリが鉄球で馬の癖を大きくする、という方法もあるのだ。

そういう意味でもピープルウェアから外れている感じがするのだが、当時は CMMI ブームでもあったので仕方がないといったところだろう。

再びデスマーチへ?

過去のものが「経験」であるならば、未来に進むためには「予測」や「予知」が必要となる。私たちはソフトウェア界隈の多くの屍(主に大手企業の屍)を乗り越えここに至っている…ような気がするけど、実はそうでもない。豆蔵のボランティアのアレもどうかと思うけど、どちらかといえば、屍になっちゃった人は屍のままで、その臭いを避けて通った人が生き残っている気がする。

かつてデスマーチ撲滅メーリングリスト(でしたっけ、プロセス改善 ML だったっけ?)ってのがあったのだが、廃れてしまった。その第一の理由が、「デスマーチになるような会社を辞めて、転職/独立しちゃった」ので、デスマーチに巻き込まれなくなったんですよね。そうすると、自分のことではなくなってしまうので、あまり興味がなくなっちゃうわけですよ。緊急性が低くなる感じ。

という訳で、某銀行プロジェクトのような大規模デスマーチ予備軍に配属されない限り、あまりデスマーチに出会うことはない。むしろ、冒頭で書いたのだが「デス」の場合が多い。配属 → 即死フラグってのがあまりにもアレなんだけど、そこは要領良く無駄な作業を省くということだろう。超概算見積もりとか、三面図型 CCPM とか、まあ色々避ける手段はある。

[amazonjs asin=”B00F4QOMUO” locale=”JP” title=”デスマーチ 第2版 ソフトウエア開発プロジェクトはなぜ混乱するのか”]

[amazonjs asin=”B00I96CJWO” locale=”JP” title=”ピープルウエア 第3版”]

[amazonjs asin=”4320023684″ locale=”JP” title=”ライト、ついてますか―問題発見の人間学”]

 

カテゴリー: プロジェクト管理 | 追悼 デスマーチ はコメントを受け付けていません

Is TDD Dead ? のその後

今更 TDD なのか?それとも今から TDD なのか…という疑問が出たのは既に2年前なのですが、状況はあまり変わっていないような気がします。

TDD is dead. Long live testing. (DHH)
http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html
テスト駆動開発(TDD)はもう終わっているのか? Part 1 | 開発手法・プロジェクト管理 | POSTD
http://postd.cc/is-tdd-dead-part1/
テスト駆動開発(TDD)はもう終わっているのか? Part 2 | 開発手法・プロジェクト管理 | POSTD
http://postd.cc/is-tdd-dead-part-2/
Is TDD dead? – YouTube
https://www.youtube.com/watch?v=z9quxZsLcfo

以前、マーチン・ファウラーが Japan XP User Group のために 2002年頃に来日して話した中に

  • TDD はプログラマに安心を与える。
  • MDA はプログラマを殺さないし、今後も大丈夫だ。

というのがありました。折しも「MDA(Model-Driven Architecture)」が発表されたころで、設計者 Model を作って UML のように繋げ、プログラミングの工数を大幅に減らす。そう、ソフトウェア開発の自動化によって大量にプログラマはいらなくなる(昨今の「ロボットに仕事が奪われる」ブームと同じ状態)がありました。当時から、大手ITのゼネコン体制が問題になっていたし、今でも問題な訳ですが(それは社員も含めて「社蓄」と言われているわけですが)そのあたりも含めての「今後も大丈夫だ」の発言です。ただし、ワタクシ的に言えばマクロ的には後退しているような気がしています(個人的には問題ないんですけどね、それは私の年齢的なものもあるので一般化できません)。

それから XP/TDD と言われて「アジャイル開発」という名前のブームも去りつつあり、そもそもソフトウェアプロセスについてのブームが去ってしまい、VRや人工知能、ロボット等の技術的な側面が全面に出てきています。これはスマートフォンやウェブサイトが一般に広まって零細/個人レベルでの売り出し(技術そのものを売る)ことができるようになったからでしょう。だから、内情がアジャイルであれ、ウォーターフォール式の委託であれ、カウボーイプロセスであれ、できあがった「製品」に対しての評価比がプロセス自体よりも高くなったということです。

そういうところで、Webサイトやスマートフォンのアプリを創るときに「TDD」だけにこだわるのはナンセンスです。

が、一方で業務アプリケーションのように十数年レベルで使われているもの(十数年使われていたもの)やインフラ開発のように障害発生時の損失が非常に大きい場合と、数年で消え去ってしまう Web サイトというか数か月でリリースしないと機会損失が発生してしまう Web サイトやスマートフォンのアプリとは別のアプローチが必要になってきます。それだけ TDD 自体の適用範囲が異なるということでしょう。

ただし、TDD にどのような価値があるかといえば「プログラマに安心を与える」のが最初になります。綿密な設計をし組み合わせを考え障害や例外を考慮したフローチャートを書いた後に、慎重なコーディングをした後に、このコードが期待通り動くかどうかを確認するには「ユーザーと同じような操作を画面から行う必要がある」というのは、心理的な負担が大きいのです。設計による試行錯誤、コードの書き換えによってどんな「変化」がおこってしまうかを、ずっと後の工程となる「テスト工程」ではなくて、その場でロジックとして即座に確認できる、というのが TDD の良いところです。この試行錯誤を手軽に扱える道具が TDD の UnitTest になります。逆に言えば、プログラマの安心のためにプログラマ中心の考え方が TDD にあります。

品質を向上するための手段はいろいろある

逆に言えば、プログラマを中心に据えないスタイルで、品質を向上する手段もあります。

  • プログラムコードを書かない設計書からの自動生成(富士通のアレ)
  • スクラム、CCPM をはじめとする、ソフトウェア開発プロセス/マネージメントからのアプローチ
  • 要求定義/開発というスタイルでの、要求の絞り込み (豆蔵のアレ)
  • ワインバーグの提唱する、要求定義工程からの品質の作りこみ
  • カバレッジやプロファイルツールを使い、テストの網羅率や複雑度からのアプローチ (富士通のアレ)
  • テスト工程での QA、不具合混入原因の調査、標準的な不具合発生率の導入
  • 関数型言語などの数学/証明的アプローチの活用
  • フレームワークを活用して、手動で作成する部分を減らす方法 (EJB, EF, Cake等)
  • UMLによるパターンやオブジェクト粒度などの経験的な手法の導入

TDD も含めて、品質を向上する(いわゆる製品の不具合率を下げる)方法はたくさんあります。どれを使ってもよいし、どのような組み合わせをしてもよいのです。ですが、残念ながら人はそれぞれの立場があり、その立場から得る利得のゆえに偏った「手段」を選ぶことがあります。それは TDD/UnitTest も同じ立場ではあるのですが、どこかに偏ってしまったときには、たいていの場合うまくいかない可能性が高まります。

逆に言えば、うまくいかない可能性を低めるのがこれらの品質マネージメントの目標になります。

品質を悪化させるものを削る

スマートフォンのアプリであれ、業務システムであれ、宇宙開発であれ、ロボット開発のためのソフトウェアであれ、要は「要求通り正しく動けばよい」という基準があります(品質工学の考え方で、管理図からはみ出さなければ良い、匠のように中央値に集約させなくてもよい、という考え方です)。特に素晴らしい品質/性能ではなくても、そこそこの品質を保てば平均以上になるということです(Intel プロセスのアレです)。

悪いものを削っていけば、だんだん良いものだけ残るだろうという発想のもとから、品質を悪化させるものを削っていくスタイルを取ってみます。そうすると、先の品質を向上するものが行き過ぎてしまったときに悪さを減らすことが可能です。

  • コーディングの手間がかかる部分で一定の法則があれば、コードを自動生成してしまう。
  • 要求の変更が少ない場合はウォーターフォールで、試行錯誤が必要であればスパイラルで、要求自体が時間軸で変わる可能性があればアジャイルプロセスを適用する。
  • 実装できない/実現の難しい要求を排除する。
  • 過去に実現できた要求を組み合わせて実現する。
  • TDD とカバレッジを組み合わせてテスト網羅率をほどよく観察する。観察した後は、TDD や設計にフィードバックする。
  • 似たプロジェクトあるいは以前のプロジェクトでの不具合混入率や原因をあらかじめ知っておく。
  • 部分的に強固なライブラリとして関数型言語を利用する。複数のプログラム言語を混在させる。
  • 部品が買えるのであれば、購入する。
  • 似たパターンを探し、パターンに沿って作成/ルール化する。ただし、20% の例外がある。

のように、悪化させる要因を減らしていきます。理論的なアプローチのほうが「美しい」と思われるでしょうが、そういう実現可能なものが「工学的なアプローチ」的に美しいものです。

Is Dead TDD のその後

その後、どうなったかといえば「Is Dead TDD」と検索してもさほど有用なデータは出てきません。使う人は使うし、使わない人は使わないという二極状態のような気がします。

おまけ、構造行列を使う方法

鴨澤さんの https://twitter.com/kamosawa/status/688208924764311557 順列組み合わせ絡みとコンポーネント化のところは、デザイン・ルールの「構造行列」という実例があります。この本はコンピュータのハードウェア設計を例にとって、設計時の情報伝達と手戻りのコストを行列として合わらわしたものです。訳本が 2004年で、原著は 2000年出版ですね。

以前、これをもとにして 30 コンポーネント/機能程度の構造行列を出して開発コスト&手戻りコストを計算したことがあります。あるコンポーネントが他のコンポーネントにどれだけ影響があるかを遷移表として調べて、関連を数え上げるだけです。この関連部分を少なくするように設計/UMLを書けば、各コンポーネントの独立度が高くなるため変更に強い(変更に相互影響が少ない)コンポーネント/モジュールが作れるという訳です。

image

[amazonjs asin=”4492521453″ locale=”JP” title=”デザイン・ルール―モジュール化パワー”]

カテゴリー: 開発, TDD | Is TDD Dead ? のその後 はコメントを受け付けていません

TDD はロストテクノロジー化しているか?

何故か、英語で CppUnit の解説を小一時間することになってしまったので、その後の展開的に残しておく。

使っている人は使っているらしいが

github のコードを見ると大抵のフレームワーク系のライブラリは、 test フォルダがあってテストプロジェクトがある。まあ、実際に自分でやってみると適当な xUnit を書かないと立ち行かない場合が多い(スタート時点の複雑さに追いつかない&後で混乱して修正コストが高くなる)のとで残しておくのと、ライブラリのマニュアル的なものとして残しておくと便利なのでちらっと書いておくとよい。

が、どこでどう間違ってしまったのか、様々な原因で身の回りに実務で TDD をやっている人は少ない…というかいない。これは主に業務アプリを作っている私だからなのか、最近はあまりであることが少なくなったのか分からないが、テストコードを書いている人は少ない。変わりに、従来通りの UI の打鍵テストをやったり、Excel で管理された単体テストや結合テストを繰り返している。

おそらく、XP のプラクティスと業務アプリ開発に取り入れるには「ペアプログラミングはコストが高い」、「UnitTest を継続的に使うにはコストが掛かる」があり、もうひとつ「単体テストをやると、単体テストのバグ票が出ない」かつ「単体テストの項目数が数えられない」というものがある。これは、2000年頃に XP/TDD を導入したときから言われてきたものだ。契約時に工数見積もりをするとき、「単体試験工程」を含ませてる必要があって、単体テストの項目数やバグ数という指標に引きずられてしまうというパターンである。まあ、そういう場合は

  • 単体テスト込みの製造工程/ガントチャートとする。
  • 単体テストの不具合票は出さない。

で押し切るのがベター。なんらかの QA 絡みで押し切られる場合には、不具合票自体をでっち上げるという手段をとる。

そんな訳で TDD は実質あまり広がらずに廃れてしまったものの、本質的に便利なところは便利だとわかっている人が使っている、という状態なのだろう。ちなみに言えば、UnitTest のフレームワークを使うか使わないかで、私的には工数的には倍以上異なる。MVVM パターンの解説のときにもよく言うのだが、

  • 内部ロジック(M-VM)部分をできるだけ多くして、UnitTest を使う。
  • UnitTest が適用しやすいクラス構造に徹する(できるだけモックを使わない)。
  • 適用外の場合は、通常の UI 打鍵で行う。

というスタイルが良い。TDD を適用しようとしたとき失敗するパターンが多いのが、すべての TDD を適用しようとするパターンである。どんな方法でも「適用可能な範囲」があるので、TDD で苦手な部分は多い。特に、ユーザーがいろいろなタイミングで打鍵するパターンは、TDD だけではうまくいかない場合がある(とはいえ、解析的に UnitTest を使うとうまくいくパターンも多い)。そのあたりを含めて、部分的に XP/TDD を取り入れればよいのである。

ちょっと変わった UnitTest フレームワーク

.NET Framework の場合は、Visual Studio で MS 謹製の UnitTest を使ったり、由緒正しい NUnit を使ったりする。Java の場合は JUnit だし、探せばたいていのプログラム言語に UnitTest フレームワークが用意されている。

UnitTest の基本は簡単で、

  1. テストコードを(できるだけ同じ言語で)プログラミングする。
  2. テストコードを何等かの形で実行する。
  3. テストの結果を自動判別する。

の 3 点があれば十分である。以前、Visual Test という GUI のテストを VB を使ってテストするフレームワークがあったがあまりはやらなかった。中身が C++/MFC で書かれていても、VB でテストしない駄目だったからだ。まあ、GUI の自動テストってのが難しいというのあるんだけど。

テストの実行環境は、できるだけ実環境と同じにあわせる。例えば、ガラケーの開発をしていたときには CPU の種類が異なるので、PC のテストとガラケー内のテストではずれが生じる可能性がある。ので、ガラケー内でテストが実行されるようにするのがベター、だがロジック的には PC でも十分だったりする。

結果を自動判別するのは、1,2,3 のサイクルを自動的に回すために必須である。昔 TDD 出る前に Excel で単体試験項目を書いて自動で動かす VBA を組んだことがあったが、結果は目検で行っていた。いま考えれば、結果を VBA で取り込んで Countif あたりで集計すればよかったのである。

そんなわけで、通常の PC あるいはサーバーで動く UnitTest はプログラム言語対応をそのまま使い、PC 以外の場合はちょっとした工夫が必要になる。

CppUnit

CppUnit – C++ port of JUnit – Browse /cppunit/1.12.1 at SourceForge.net
http://sourceforge.net/projects/cppunit/files/cppunit/1.12.1/

2008年で更新が止まっているが、これで十分。Visual C++, g++ で動くのでこれを使い続けている。一時期は更新結果が Green/Red になることが重要だったりしたが、実はそれは些末なところでしかない。本質は、All Success なのか Any Failure なのかにある。失敗したことが確認できて、どこでエラーになったか判別できればそれで十分である。

image

これは内部で FEM を計算するときの歪み関数をテストしているところだ。こういう科学計算の結果チェックに使える。

FsUnit

What is FsUnit?
http://fsprojects.github.io/FsUnit/

内部的には NUnit のラッパーなのだが、テストの書き方がちょっと異なる。たいていの xUnit テストは assertEqulas( 期待値, 実行値 ) という形でテストを書き連ねるのだが、FsUnit の場合は 実行値 |> should 期待値 というテストの書き方になる。期待値と実行値の語順が逆なのは関数型言語特融のカリー化/パイプを使っているため。この語順が便利かというと、実は結構混乱をしていて私の場合、CppUnit や NUnit の語順に慣れているのでよく間違う。

とはいえ、パイプを使うことで通常の assertEqulas 関数とは違った使い方ができる。特にパイプの間にログのフィルタを挟み込めるのは便利だ。バグ解析をするときに

実行値 |> dprint |> should be …

のように、適切な dprint を用意して挟み込めるようにするスタイルができる。

ArduinoUnit

先に書いた通り、組み込みシステムを作っているときは実機で動くような UnitTest を書くのがベストだ。Arduino の場合には Sketch と呼ばれるプログラム(実質、プログラムだ)を書いて動作させる。言語は C++ 風になっているので、ほぼ CppUnit が使える。ただし、 Arduino の sketch 自体が完全に C++ 準拠なのかどうかはわからないので、できれば Arduino 専用の UnitTest を使って、実行は Arduino 上でやったほうがいい。特に、GPIO をリアルタイムで制御するとか、センサーからの値を取得するとかは実機でしかできない(勿論、センサーからの値は毎回異なるので、assertEquals の対象としては使えない。センサーから読み込める/読み込めない、とか BLE 通信をするとか、そういう扱いになる)。

mmurdoch/arduinounit: ArduinoUnit is a unit testing framework for Arduino libraries
https://github.com/mmurdoch/arduinounit

まだ使ってみたことはないが、ひと通り AssertEquals が使えて結果がシリアル通信で送られてくるらしい。BLEやWiFi モジュールの通信系とかを作るときに便利そう。

Xamarin の UI Test App

Xamarin.UITest – Xamarin
https://developer.xamarin.com/guides/testcloud/uitest/
Xamarin.UITests クイック スタート | Xamarin : XLsoft エクセルソフト
http://www.xlsoft.com/jp/products/xamarin/uitest-quickstarts.html

Xamarin Test Cloud が必須っぽいのだが(テスト自体はローカルで実行できる?)、Android/iOS 上でテストをするツールである。これも試したことがないので記事を読む限り、昔の Visual Test に近いスタイルを取っている。UI コントロールに直接代入をする形になる。ただし、テストコード自体が C# であるのと、Xamarin 自体が C# で組む(F#/VB でも可能だけど)ので、テストフレームワークとして同じ言語を使える。スマートフォンのテストに特化しているので、ユーザーからの入力と画面キャプチャができるのがメリットだろう。

内部的には NUnit で動いているようなので、Xamarin.UITest.IApp と ITestServer を実装すればローカルで動かす限り Xamarin Test Cloud は必要ないのではないか?という作りになっている。勿論、Xamarin Test Cloud  自体は Android のいろいろな機種で動くというメリットがあるので、手元にある機種限定になるだろうけど。

Android Studio で UnitTest

AndroidStudioでUnitTestを行う | Anysense Blog
http://blog.anysense.co.jp/app/androidunittest/

こちらのほうは、由緒正しい JUnit を使った Android のテスト。こっちの UnitTest は Android Studio 上で動かすパターンなので UI を介在しない。ロジックなどをテストときに使う。

これも本来ならば、Android 実機上で動かしてログなどの形で結果が通知されるとよい。たぶん、テスト用の画面を作って「テスト実行」のボタンを押すと TestMain が起動されるという形にすればよいと思う。

Swift で UnitTest

Swift 2 + Xcode 7: Unit Testing Access Made Easy!!!!
https://www.natashatherobot.com/swift-2-xcode-7-unit-testing-access/

以前から、Xcode には test プロジェクトを作るか否かのスイッチはあるものの使ったことがない。まあ仕事がら執筆用のサンプルを作ることが多いので単体テストをやること自体が少ないのだが。

これも Android Studio と同じように Xcode 上でテストを実行するパターン。@testable というキーワードを使ってテストクラスを指定する(NUnit は属性を使ってテストクラスを指定する)。これも、実機の iPhone 上で動くことが望ましい。

参考文献

そんな訳で、実行環境が変わるとそれに追随して UnitTest のフレームワークも再作成される。が、もともと UnitTest のパターンは同じなので他言語で作ったテストパターン/知識は流用できる。つまり知識の蓄積ができる分野なのだ。

という訳で、ロスとテクノロジー化していると思われたら再入門し、知らなかったら「損」だよという形でお薦めする。

[amazonjs asin=”4894717115″ locale=”JP” title=”テスト駆動開発入門”]

ちなみに、私が最初に読んだ TDD の本はこれです。

[amazonjs asin=”4756136877″ locale=”JP” title=”Rubyを256倍使うための本 極道編”]

カテゴリー: 開発, TDD | TDD はロストテクノロジー化しているか? はコメントを受け付けていません

Xamarin.Forms でドラッグを実装しよう(UWP編)

Xamarin.Forms でドラッグを実装しよう(のうりん編)
http://www.moonmile.net/blog/archives/7653
Xamarin.Forms でドラッグを実装しよう(Android編)
http://www.moonmile.net/blog/archives/7667
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on Android編)
http://www.moonmile.net/blog/archives/7670
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on iOS編)
http://www.moonmile.net/blog/archives/7723
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on WinPhone編)
http://www.moonmile.net/blog/archives/7728

の続きです。

Xamarin.Forms は 2.0 からユニバーサルアプリ(UWP)を扱えるようになったハズなので、これを作ってみます。

Adding a Universal Windows Platform (UWP) App – Xamarin
https://developer.xamarin.com/guides/xamarin-forms/windows/getting-started/universal/

を参考にして、

– App.xaml.cs に Xamarin.Forms.Forms.Init(e); を追加
– MainPage.xaml に using:Xamarin.Forms.Platform.UWP を追加
– MainPage.xaml.cs に LoadApplication(new BoxDragXF.App()); を追加

すると動きます。

Android や iOS と同じようにドラッグさせたいので、Windows Phone 8.1 と同じように BoxExRenderer クラスを作ります。

[assembly: ExportRenderer(typeof(BoxViewEx), typeof(BoxExRenderer))]
namespace BoxDragXF.UWP
{
    class BoxExRenderer : Xamarin.Forms.Platform.UWP.BoxViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
        {
            base.OnElementChanged(e);
            this.ManipulationDelta += BoxExRenderer_ManipulationDelta1;
            this.ManipulationMode = Windows.UI.Xaml.Input.ManipulationModes.All;
        }

        private void BoxExRenderer_ManipulationDelta1(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            var el = this.Element as BoxViewEx;
            el.OnManipulationDelta(el, new BoxDragXF.ManipulationDeltaRoutedEventArgs(el, e.Delta.Translation.X, e.Delta.Translation.Y));
        }
    }
}

ほとんど、WinPhone 版と同じですね。
これが動くと、Windows IoT Core の UWP も同じように動くので、自作タブレットを作ったり、Surface を使った場合でも共通化できます。Android/iPhone/Surface の UI が Xamarin.Forms で一括で作ることができます。

動かしたときの動画はこちらです。

サンプルコード

https://github.com/moonmile/BoxDrag

にあります。

カテゴリー: 開発 | Xamarin.Forms でドラッグを実装しよう(UWP編) はコメントを受け付けていません

Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on WinPhone編)

Xamarin.Forms でドラッグを実装しよう(のうりん編)
http://www.moonmile.net/blog/archives/7653
Xamarin.Forms でドラッグを実装しよう(Android編)
http://www.moonmile.net/blog/archives/7667
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on Android編)
http://www.moonmile.net/blog/archives/7670
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on iOS編)
http://www.moonmile.net/blog/archives/7723

の続きです。

最後は Windows Phone で動かします。
もともとの Xamarin.Forms のテンプレートを使っているので、Windows Phone 8.1 版になっていますが、おそらく Windows 10 用の UWP プロジェクトでも動くはずです。

Windows Phone のレンダラーを作る

BoxDragXF.WinPhone プロジェクトに BoxExRenderer クラスを追加します。Windows Phone/Mobile が一番簡単で(簡単なようにしたので)、そのまま ManipulationDelta メソッドを渡せば ok です。渡すときの引数は、疑似的なほうの ManipulationDeltaRoutedEventArgs オブジェクトなので、そこだけコンバートします。

 [assembly: ExportRenderer(typeof(BoxViewEx), typeof(BoxExRenderer))]
namespace BoxDragXF.WinPhone
{
    class BoxExRenderer : Xamarin.Forms.Platform.WinPhone.BoxViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
        {
            base.OnElementChanged(e);
            this.ManipulationDelta += BoxExRenderer_ManipulationDelta;
        }
        
        private void BoxExRenderer_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            var el = this.Element as BoxViewEx;
            el.OnManipulationDelta(el, new BoxDragXF.ManipulationDeltaRoutedEventArgs(el, e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y));
        }
    }
}

実行してみる

Hyper-V のエミュレーターで動かしてみます。これで、同じ Xamarin.Forms を使って、三機種(Android/iPhone/Windows Phone)で同じようにコントロールをドラッグできることがわかります。

カテゴリー: 開発 | Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on WinPhone編) はコメントを受け付けていません

Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on iOS編)

Xamarin.Forms でドラッグを実装しよう(のうりん編)
http://www.moonmile.net/blog/archives/7653
Xamarin.Forms でドラッグを実装しよう(Android編)
http://www.moonmile.net/blog/archives/7667
Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on Android編)
http://www.moonmile.net/blog/archives/7670

の続きです。iOS 版は比較的簡単にできたので、Xamarin.iOS 版と Xamarin.Forms 版をいっぺんに作っていしまいます。

サンプルコード

https://github.com/moonmile/BoxDrag にあります。

Xamarin.iOS でドラッグを実装する

iOS のみで動くバージョンは、BoxDragApple.iOS というプロジェクトのほうです。以前は、ViewController にタップイベント(TouchesBegan等)を送っていたのですが、今回は Android と動きを合わせるために自前のコントロール BoxViewEx を作ります。

partial class BoxViewEx : UIView
{
    public BoxViewEx (IntPtr handle) : base (handle)
    {
    }
    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);
        UITouch touch = touches.AnyObject as UITouch;
    }
    public override void TouchesMoved(NSSet touches, UIEvent evt)
    {
        base.TouchesMoved(touches, evt);
        UITouch touch = touches.AnyObject as UITouch;
        var newPoint = touch.LocationInView(this);
        var previousPoint = touch.PreviousLocationInView(this);
        nfloat offsetX = previousPoint.X - newPoint.X;
        nfloat offsetY = previousPoint.Y - newPoint.Y;
        this.Frame = new CoreGraphics.CGRect(
            this.Frame.X - offsetX,
            this.Frame.Y - offsetY,
            this.Frame.Width,
            this.Frame.Height);
    }
    public override void TouchesEnded(NSSet touches, UIEvent evt)
    {
        base.TouchesEnded(touches, evt);
    }
}

ちょっとはまりどころがあって、Xamarin.iOS でユーザーコントロールを作るときは、

  1. Storyboard で、BoxViewEx を記述してコントロールを作る。
  2. コードのほうで、partial 付きの BoxViewEx クラスが作られる。
  3. 生成された BoxViewEx.cs を使う

という手順が必要です。先に BoxViewEx クラスを作ったり、partial 無しで作ったのですがうまく動きません。おそらく Storyboard のデザイナで自前コントロールを作ったときに、何らかの ID が割り振られるのでしょう。

BoxViewEx クラスは、UIView を継承しただけなので普通に Storyboard で扱えます。

タッチイベントによるドラッグは、TouchesMoved メソッドをオーバーライドすれば ok です。移動したときの差分を取って Frame プロパティに位置を設定します。

Xamarin.Forms on iOS でドラッグを実装する

iOS オンリー版ができたので、Xamarin.Forms で動くようにします。
Forms のある PCL プロジェクトは Android で作ったときのままにしておいて、BoxDragXF.iOS プロジェクトに、
BoxExRenderer クラスを追加します。

using BoxDragXF;
using BoxDragXF.iOS;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Foundation;
using UIKit;

 [assembly: ExportRenderer(typeof(BoxViewEx), typeof(BoxExRenderer))]
namespace BoxDragXF.iOS
{
    class BoxExRenderer : BoxRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
        {
            base.OnElementChanged(e);
        }
        public override void TouchesBegan(NSSet touches, UIEvent evt)
        {
            base.TouchesBegan(touches, evt);
            UITouch touch = touches.AnyObject as UITouch;
        }
        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            base.TouchesMoved(touches, evt);
            UITouch touch = touches.AnyObject as UITouch;
            var newPoint = touch.LocationInView(this);
            var previousPoint = touch.PreviousLocationInView(this);
            nfloat dx = newPoint.X - previousPoint.X;
            nfloat dy = newPoint.Y - previousPoint.Y;
            var el = this.Element as BoxViewEx;
            el.OnManipulationDelta(el, new ManipulationDeltaRoutedEventArgs(el, dx, dy));
        }
        public override void TouchesEnded(NSSet touches, UIEvent evt)
        {
            base.TouchesEnded(touches, evt);
        }
    }
}

書き方は、Android の時と同じですね。iOS の場合は、移動距離の差分がすでに計算されているので、そのまま OnManipulationDelta メソッドを呼び出せば ok です。

実行してみる

これを動かしてみたのが、この動画です。

Renderer を切り替えるだけで、Android と iOS が同じように Xamarin.Forms で動くことがわかります。似たような感じで、独自のコントロールを作って、PCL 側で共通で動かすということができる訳です。

カテゴリー: C#, Xamarin | Xamarin.Forms でドラッグを実装しよう(Xamarin.Forms on iOS編) はコメントを受け付けていません

ふと GoF のデザインパターンを再考しておく

懐かしの パタンランゲージ を眺めつつ、ふと 再考: GoF デザインパターン が気になったのでさらっと流しておこう。

[amazonjs asin=”4306041719″ locale=”JP” title=”パタン・ランゲージ―環境設計の手引”]

そもそもが GoF 発祥自体が 90年頃で、日本語の書籍は Java が発生した頃と前後してしまっているので、オブジェクト思考ブーム、UML, パターンのブームよりも随分前からある。C# や Java よりも前になので、今さら再考する意味もないのではないか?と思われるのだが(そもそも Qiita の「再考~」の記事自体が 2014 年だ)、歴史経緯から考えるのと、GoF の反省(あるいはドツボ?)からできあがった現在の C#, Java の言語拡張をみていくと、これらのパターンが言語仕様やライブラリに含まれてしまっていることが分かる。逆に言えば、.NET ライブラリを使うときに「?」とか「何でこんなややこしい使い方になっとるんやッ!!!」というときには、ここの GoF を踏まえたライブラリづくりがあって現在があるという経緯をを知ると、なんとなく納得がいくと思う。良くも悪くも、最適化(準かもしれないけど)されつつあるということだ。

それは、アルゴリズムのテクニックとして、双方向リストやらソートやらが流行っていた時期があって、今だと、List<> や Sort() で十分な訳で、実用的にはそれでよいし、でも知識として知っておくとその延長がわかるという仕掛けが含まれている。

というわけで、GoF を現在の C#, .NET クラスライブラリと合わせてさらっていこうと思う。

Abstract Factory

Factory パターンの汎用版で、C# だとストリームを作るときに使ってる。UWP の File.Open あたりがそれ。

20160111_03

Builder

なんとか Builder が好きな人が多くて StringBuilder とかに出てくる。

20160111_04

Factory Method

いわゆるファクトリーパターンで、Java だと結構頻発する。C# だと TaskFactory.StartNew にみられる。new するときにパラメータが多くなるのを嫌がったパターンと、DOM で Parent を Document にするときに作るときに使われる。

Abstract Factory と比べると、Factory/Creator クラスが二重化されていることがわかる。

20160111_31

Prototype

見かけたことがない…というか、普通にインターフェース。

20160111_06

Singleton

static で十分やろ、ってな感じで使われている。

20160111_32

Adapter

継承を使ってクラスを拡張する代わりに、あらかじめ拡張するメソッドをインターフェースにしておく手法。メッセージングのときに、後付けで必要なインターフェースを追加するときに使う。データ自体と操作するメソッドを分離するときによこう使われる。が、最初からわかっていれば、Interface で十分な気も。

20160111_08

Bridge

今だと普通に委譲を使うのだが、GoF の発祥自体が Java, C# よりも前なのだ。C++ と同時期だと思えば、そういうパターンがあっても仕方がない。継承地獄を避けるためにつくられる。今となっては常識になったパターン…だが、.NET クラスライブラリには歴史的にか継承地獄が頻発する。

20160111_10

Composit

今でいえば、DOM そのもの。ツリー構造を使いたいときは、このパターンを使うか、DOM を使う。

20160111_11

Decorator

元クラスがぴよぴよクラスのときに、継承して拡張するか、メンバにして拡張するか、のパターン。

20160111_12

Facade

残念ながら .NET クラスライブラリにはこの発想はない。既定クラスからばらばらとメソッド&プロパティが公開されている。Android の ViewGroup へのキャストがそれ。あるいは、ごちゃごちゃになったクラスをクライアントから見れば整理するパターン。ユーティリティクラスがそれ。

20160111_13

Flyweight

データベースのコネクションプーリングで使われている。

20160111_14

Proxy

いわゆる、アスペクト指向のパターンなのだが、C# の UI コントロールのメソッドが常に override と event を持っているのが proxy の役割になっている。あらかじめ仕込んでおかないといけないのがミソ。

20160111_15

Chain of Responsibility

複数のオブジェクトを連ねていくパターン。クリップボードのチェーンや、昔の常駐プログラムのキーチェーンで使われていた。いわゆる協調パターン。

20160111_16

Command

MVVM パターンにも出て来るおなじみの、ICommand インターフェースになる

20160111_17

Interpreter

いわゆる、式木だが、普通の人は使わない。動的にスクリプトを使うとか一部の関数型言語マニアが使う。F# だと簡単に作れる。

20160111_18

Iterator

いわゆる C++ のイテレーターだし、C# の IEnumerator だ。今だと、LINQ を使ったほうが楽。

20160111_20

Mediator

リモートメッセージで使われる SOAP とか JSON とかがそれにあたる。DCOM, CORBA を知っていればシリアライズという形で現れる。

20160111_23

Memento

いわゆる、Undo/Redo に使われるパターンなのだが、これを使った実装は見たことがない。そもそも Undo/Redo 自体が難しくて、今だとメモリのある限り丸ごと保存してしまう。例えば、Visual Studio をコンテナとして Undo/Redo メソッドとして利用する、ような感じ。

20160111_24

Observer

これも MVVM パターンで使われる ObservableCollection<T> の元ネタになる。

20160111_25

State

switch や if で実装しないために State パターンを使う。インターフェースを作っておくと、無限種類でオブジェクトを作れるので、State パターンは便利なのですよ。5 個程度ならば swtich、それ以上であれば State パターンを使えばよい。

20160111_26

Strategy

かつて openssl で使っていたパターンで、暗号コードの構造体を切り替える。ちなみに openssl は C言語だ。部分的に切り替えるのが State で、ごっそり切り替えるのが Strategy になる。ただし、.NET クラスライブラリに Strategy という単語はでてこなくて、Factory あたりでごっそりクラス名を切り替えたりする。ストリームクラスあたりがそれ。

20160111_27

Template Method

interface だったり、abstract だったりするが、言語仕様として Interface は内部フィールドを持たず、Abstract は内部データを持てる、という違いがあったりする。言語の都合なのと、IDE の補完機能を使って自動メソッドを使うときに便利なパターンだ。

20160111_28

Visitor

このあたりは、ほとんど delegate と一緒だったり、Action<>, Func<> で大丈夫だったりするが、異なるスレッドの場合はディスパッチが発生するため、このパターンが使われる?たぶん、C# だと Invoke になると思う。

20160111_29

 

 

改めて見直すと、コンテナとオブジェクトのパターンが多い。「パターン」自体が、頻出されるモデルという意味合いなので、かつてのオブジェクト指向以前であれこれと悩んだ末に出てきた定型パターンと考えられえる。定型だからこそ、現在の言語仕様やライブラリではそれらのパターンを取り入れてしまって、外側に出ないようにする。そういう意味では、GoF のパターンは形骸化しているといってよい。が、新しいプログラム環境で作ろうと思ったり、もっと大きい範囲でパターンを考える(ロボット制御の ROS とか、スマートフォンや PC などのメッシュ的な通信とか)ときには、これらのパターンが有効に働くので、知識として覚えておくとよいだろう。

おまけ

astah で作った GoF の図を置いてきます。

参考先

[amazonjs asin=”B000SEIBB8″ locale=”JP” title=”Design Patterns: Elements of Reusable Object-Oriented Software (Adobe Reader)”]

 

カテゴリー: 開発 | ふと GoF のデザインパターンを再考しておく はコメントを受け付けていません