宮水の日記

宮水の日記

主に書評や資格取得について記事を書いています。

Typescript exercises やってみた 3問目

みなさんこんにちは。宮水です。
今日は、TypeScript エクササイズの3に取り組んでみました。
英語も苦手なので、翻訳も自分でしてみました。

こちらのリポジトリをforkして、cloneして取り組みます。
rootディレクトリで、yarn installしてから問題文にあるRun this exerciseのコマンドを叩くと、答え合わせができます。すごい!!
github.com

前回の問題

miyamizu.hatenadiary.jp

本日の問題

import chalk from 'chalk';

/*

Intro:

    As we introduced "type" to both User and Admin
    it's now easier to distinguish between them.
    Once object type checking logic was extracted
    into separate functions isUser and isAdmin -
    logPerson function got new type errors.

 UserとAdminの両方に「type」を導入したので、簡単にそれらを区別できるようになりました。
 オブジェクトのtypeをチェックするロジックがisUserとisAdminに分けられると、logPerson関数で新しいタイプのエラーが発生しました。

Exercise:

    Figure out how to help TypeScript understand types in
    this situation and apply necessary fixes.

 TypeScriptが型を理解するために、必要な修正を適用してください。

Run:

    npm run 3

    - OR -

    yarn -s 3

*/

interface User {
    type: 'user';
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    type: 'admin';
    name: string;
    age: number;
    role: string;
}

type Person = User | Admin;

const persons: Person[] = [
    { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
    { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
    { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
    { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }
];

function isAdmin(person: Person) {
    return person.type === 'admin';
}

function isUser(person: Person) {
    return person.type === 'user';
}

function logPerson(person: Person) {
    let additionalInformation: string = '';
    if (isAdmin(person)) {
        additionalInformation = person.role;
    }
    if (isUser(person)) {
        additionalInformation = person.occupation;
    }
    console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`);
}

console.log(chalk.yellow('Admins:'));
persons.filter(isAdmin).forEach(logPerson);

console.log();

console.log(chalk.yellow('Users:'));
persons.filter(isUser).forEach(logPerson);

// In case if you are stuck:
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates

答え

interface User {
    type: 'user';
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    type: 'admin';
    name: string;
    age: number;
    role: string;
}

type Person = User | Admin;

const persons: Person[] = [
    { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
    { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
    { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
    { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }
];

const isAdmin = (person: Person): person is Admin => person.type === 'admin';
const isUser = (person: Person): person is User => person.type === 'user';

function logPerson(person: Person) {
    let additionalInformation: string = '';
    if (isAdmin(person)) {
        additionalInformation = person.role;
    }
    if (isUser(person)) {
        additionalInformation = person.occupation;
    }
    console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`);
}

console.log(chalk.yellow('Admins:'));
persons.filter(isAdmin).forEach(logPerson);

console.log();

console.log(chalk.yellow('Users:'));
persons.filter(isUser).forEach(logPerson)

解説&感想

今回は、isの問題でした。
自分の経験では解けなくて、問題文一番下にある公式ドキュメントのヒントを見ました。
www.typescriptlang.org

TypeScriptが引数で受け取ったの型を推測できない場合、私たちがこうやって書いてTypeScriptを助けてあげる必要もあるんですね。

// このpersonはAdminだよ!
const isAdmin = (person: Person): person is Admin => person.type === 'admin';

公式ドキュメントの同じ項目にinというものもあって、これは逆に"swim"はFishかBirdのプロパティだよ!と教えてあげることができます。
isとはちょっと違うけど、型を限定できるというものです。

function move(pet: Fish | Bird) {
  if ("swim" in pet) {
    return pet.swim();
  }
  return pet.fly();
}

うーん、だんだん難しくなってきました。以上です!

Typescript exercises やってみた 2問目

みなさんこんにちは。宮水です。
今日は、TypeScript エクササイズの2に取り組んでみました。
英語も苦手なので、翻訳も自分でしてみました。

こちらのリポジトリをforkして、cloneして取り組みます。
rootディレクトリで、yarn installしてから問題文にあるRun this exerciseのコマンドを叩くと、答え合わせができます。
github.com

前回の問題

miyamizu.hatenadiary.jp


本日の問題

import chalk from 'chalk';

/*

Intro:

    Since we already have some of the additional
    information about our users, it's a good idea
    to output it in a nice way.

 私たちはすでにいくつか情報を追加されたユーザーを持っているので、適切な方法で出力しましょう。

Exercise:

    Fix type errors in logPerson function.

    logPerson function should accept both User and Admin
    and should output relevant information according to
    the input: occupation for User and role for Admin.

 logPerson関数の型エラーを修正してください。
 logPerson関数は、UserとAdminの両方を受け入れ、Userの職業とAdminの役割を出力する必要があります。

Run:

    npm run 2

    - OR -

    yarn -s 2

*/

interface User {
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    name: string;
    age: number;
    role: string;
}

type Person = User | Admin;

const persons: Person[] = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Jane Doe',
        age: 32,
        role: 'Administrator'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    },
    {
        name: 'Bruce Willis',
        age: 64,
        role: 'World saver'
    }
];

function logPerson(person: Person) {
    let additionalInformation: string;
    if (person.role) {
        additionalInformation = person.role;
    } else {
        additionalInformation = person.occupation;
    }
    console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`);
}

persons.forEach(logPerson);

// In case if you are stuck:
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-the-in-operator

答え

interface User {
    type: 'user';
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    type: 'admin';
    name: string;
    age: number;
    role: string;
}

type Person = User | Admin;

const persons: Person[] = [
    {
        type: 'user',
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        type: 'admin',
        name: 'Jane Doe',
        age: 32,
        role: 'Administrator'
    },
    {
        type: 'user',
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    },
    {
        type: 'admin',
        name: 'Bruce Willis',
        age: 64,
        role: 'World saver'
    }
];

function logPerson(person: Person) {
    let additionalInformation: string;
    if (person.type === 'admin') {
        additionalInformation = person.role;
    } else {
        additionalInformation = person.occupation;
    }
    console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`);
}

persons.forEach(logPerson);

んー、ちょっと微妙なコードだと思うけど、一応動きました。
f:id:kattyan53:20200724163641p:plain

感想

今回は、Type Guardの問題だと思います。

今回の問題では、User型にroleプロパティが、Admin型にoccupationプロパティがないという型エラーが出ていました。
(ちなみに、前回の問題では、roleもoccupationも参照していなかったので、エラーにはなりませんでした。)

そこで、型定義にuser か adminかわかる情報を追加してあげて、データにもtypeプロパティを追加し、
if文でtypeプロパティごとに出力する値を変えるような処理を入れました。
この問題はいろんな書き方ができると思います。

初めは、typeofやinstanceofをそれを使おうと思ったのですが、使えませんでした。

typeofは、stringやnumberやnullといった基本型に対して使えるものです。
instanceofは、interfaceで定義された型に対しては使うことができません。

interfaceのタイプガードをするとしたら、以下のように自分でタイプガードを定義しないといけないようです。(ユーザー定義タイプガードというそうです。)

interface Foo {
  foo: number
}

interface Bar {
  bar: number
}

// ユーザ定義タイプガード
function implementsFoo(arg: any): arg is Foo {
  return arg !== null &&
    typeof arg === "object" &&
    typeof arg.foo === "number"
}

function getNumber(arg: Foo | Bar): number {
  if (implementsFoo(arg)) { // implementsFooをタイプガードに使用
    return arg.foo
  } else {
    return arg.bar
  }
}

※ 参考のQiitaから引用しました

以上です!

参考:TypeScript: interfaceにはinstanceofが使えないので、ユーザ定義タイプガードで対応する - Qiita

「オブジェクト指向設計 実践ガイド」を読みました

今回は「オブジェクト指向設計 実践ガイド」を読みました。

この記事について

この記事では、本の具体的な内容は少なめにし、各章について抽象的にまとめています。
この本に興味のある人が、どんなことが学べるのか軽く理解できるきっかけになればと思います。

なぜ読んだのか

私は今までオブジェクト指向Javaで少し学んだきり、あんまり勉強してきませんでした。改めてRubyオブジェクト指向を学んで、Rubyらしいオブジェクト指向を身につけて実務に活かそうと思いました。
特に「変更に強いコード」が書けるようになりたいです。変更に強いコードとはどんなコードなのか、どういう風に書くのか学んでいこうと思います。

この本の対象者

この本で学べること

  • オブジェクト指向ソフトウェアの設計
  • 今日の生産性が翌月も翌年も持続するようなソフトウェアをいかに構成するか
  • 将来に適応できるコードの書き方

第1章 オブジェクト指向設計

1章では、手短にオブジェクト指向プログラミングの概要が説明されています。
設計原則やデザインパターンにも軽く触れ、設計が大切な理由や設計が失敗してしまう理由について解説されていました。

第2章 単一責任のクラスを設計する

この章では、自転車について様々な計算するアプリケーションを使って、単一責任のクラスの考え方を学びます。

自転車のギアの比を計算するだけのクラスが完成した。

ギアのインチも知りたくなったが、引数が変わってしまう。

attr_readerを使ってインスタンス変数を隠蔽し、データの参照を"振る舞い"へと変える。

計算の都合上、続いて直径が必要になるが、データ構造(配列の要素の順番)に依存してしまう。

Structを使って、クラスを定義することなく属性を一箇所に束ねる。

最後に自転車の車輪の円周を計算したいという要望がくる。Wheelクラスを作るときがきた!

今まで変更に強いクラスを作ってたから、変更も簡単だね!めでたしめでたし

という流れです。
クラスを"簡単に変更できる"とはどういう意味か?クラスにさせる振る舞いはどのように決めるべきか?などが理解できました。
本書では、コードを用いて解説されています。

第3章 依存関係を管理する

この章では、2章で取り扱ったGear(ギア)とWheel(ホイール)のコードを使って、依存関係の原因と分離の仕方について解説されます。

最初のコードは、Wheelクラスに変更があった場合、Gearも大きく影響してしまう状態

Gearクラスの中でWheelインスタンスを生成するのをやめ、Gearインスタンスを生成するときに生成したWheelインスタンスを引数として渡す。(と疎結合になる)

引数の順番への依存もよくないので、Hashを使用する。明示的にデフォルト値を設けるのもあり。

WheelがGearに依存しているコードではなく、GearがWheelに依存するコードも書ける。
するとWheel.newという具象的なコードに依存していたGearが、抽象的なものに依存するようになったよ。抽象的なものに依存することはいいこと。
静的型付け言語ではインターフェース、Rubyみたいな動的型付け言語ではダックタイピングって言うけど、使いすぎに注意してね。

まとめると、疎結合なオブジェクトは変更に対応しやすいし再利用しやすいし最高!

「このクラスを直したらあのクラスを直さないといけない」という状況を極力減らすことが大切です。

第4章 柔軟なインターフェースをつくる

4章では、オブジェクト間でどのように「柔軟なインターフェース」を作成するのか取り扱います。

自転車旅行会社のアプリケーションを題材に、シーケンス図の使い方とデメテルの法則について学べました。
デメテルの法則は、簡単にいうと「オブジェクトは自分のことを知るべきで、他のことは知りすぎないようにしよう」という法則です。
デメテルの法則は、ドットは1個までが望ましいという言い方もします。Rubyでは、delegate.rbとforwardable.rbがあります。

例えば、

customer.bicycle.wheel.rotate

のようなメッセージチェーンは、設計者の設計思想は既知のオブジェクトに影響を受けすぎています。
customerは自転車のホイールが回転することを知らなくても大丈夫です。customerは、自転車に乗ることができるとわかれば十分だということです。

customer.ride

第5章 ダックタイピングでコストを削減する

第5章では、4章に続き自転車旅行会社のコードでダックタイピングを扱う例が解説されています。

Tripクラスに定義された、旅の準備をする"prepareメソッド"は、準備をする人(クラス)ごとに準備の内容を異なるものにしたいです。

※ 日本語でコードを表しています

def prepare(preparers)
preparers.each { |preparer|
if preparer == Mechanic
自転車を用意する
elsif preparer == TripCoordinator
食料を買う
elsif preparer == Drivar
自転車の水のタンクを用意する
end
}
end

しかし、これだと各クラスへの依存が大きいです。そこで、ダックタイピングの出番です。
prepareメソッドが何をしたいかというと、ズバリ"旅の準備"。
コードを以下のように書き換えます。こうすると、新しく準備をする人(preparer)が増えてもTripのprepareメソッドに変更はありません。

def prepare(preparers)
preparers.each { |preparer|
preparer.prepare_trip(self)
}
end

Mechanicクラス
def prepare_trip(trip)
自転車を用意する
end

TripCoordinatorクラス
def prepare_trip(trip)
食料を買う
end

Drivarクラス
def prepare_trip(trip)
 自転車の水のタンクを用意する
end

このように、ダックタイピングを使えばオブジェクトが"何であるか"ではなく"何をするか"によって定義される、仮想の型を作ることができます。
ダックタイピングについてもう少し知りたくなったので、追加で ダック・タイピングがダメな理由 | GWT Center という記事も読みました。メリットデメリットが書かれていてとてもわかりやすかったです。

第6章 継承によって振る舞いを獲得する

この章では、クラスによる継承のテクニックを学びます。

自分が様々な自転車を扱う会社に勤めているという設定で、最初に自転車クラスを作るところから始めます。
マウンテンバイクとロードバイクというサブクラスを作ったり、リカンベント(首や腰に優しい自転車)自転車を追加したときに既存の自転車クラスが壊れることを体験しながら、どのように継承を扱っていくのか学びます。
superを使うより、親クラスのメソッドを子クラスでオーバーライドしたほうがいいということも学べました。(テンプレートメソッドパターンというそうです)
Rubyの親クラスと子クラスのメソッドが呼び出される順番について復習にもなりました。

第7章 モジュールでロールの振る舞いを共有する

6章では、継承を使って共通の処理を親クラスに移動させるやり方を学びました。一方で7章では、モジュールを使ってオブジェクトの役割を共有する方法を学びます。

本章では、整備士と自転車と自動車、そしてスケジュールクラスが登場します。
はじめに、整備士と自転車と自動車にはそれぞれ休みや、稼働可能かなどの"スケジュール"をスケジュールクラスに聞くようになっています。
しかし、スケジュールは"オブジェクト自身"が知っているべきなので、スケジュールをクラスではなくモジュール化して、整備士と自転車と自動車クラスでincludeしてオブジェクト自身にスケジュールを聞けるように改修していきます。
継承と違って、モジュールにするとどんなクラスにもメソッドを追加できるので便利ですね。

モジュールが追加された際のメソッド探索の順番にも少し触れられており、勉強になりました。

最後に、 モジュールを使うとRubyらしい便利なコードが書ける反面、継承を使った方がいいのか?モジュールを使った方がいいのか?迷うことがあります。そこで、7章の後半ではモジュールを使ったアンチパターンも紹介されていました。

第8章 コンポジションでオブジェクトを組み合わせる

8章の前半では、自転車をコンポーズしていき、コンポジションによってオブジェクトを組み立てるテクニックを説明されます。
コンポジションとは、組み合わされた全体が、単なる部品の集合以上となるように、個別の部品を複雑な全体へと組み合わせる(コンポーズする)行為です。
タイヤやサドル、ギアなど一つ一つは部品ですが、組み合わせることで一つの自転車となります。
今回も自転車を例にし、コンポジションについて理解します。

同じく8章の後半では、コンポジション、継承、ダックタイプによる役割の共有からいずれかを選ぶためのガイドラインが示されます。

継承について (整数は数字だ。浮動小数点数は数字だ)

例えばRubyのNumericクラスを継承するIntegerとFloatは二つとも、根本的には"数字"です。
「is-a」の関係のときには、継承を使う方が見通しがよく、合理的と言えます。
しかし、継承は間違ったケースに適用した場合に最悪です。簡単に振る舞いを追加できなくなってしまいます。

コンポジション(自転車はパーツを持っている)

コンポジションを使うと、小さなオブジェクトがたくさんできます。一つ一つが独立しているので、変更が容易にできます。
「has-a」の関係にはコンポジションを使うと良いでしょう。(Bicycle hava-a parts)
一方で、オブジェクト同士を組み合わせたときに、うまくいくかどうかは保証できません。書いた人の設計の腕次第になります。

ダックタイピング(準備は整備士のように振る舞う)

ダックタイピングは、「behaves-like-a」関係のときに使うのが好ましいです。
「〇〇は△△のように振る舞う」に当てはまる場合に使用します。
5章でやったコードを例にすると、準備は整備士のように振る舞う、準備は運転手のように振る舞う、などです。
ちょっと違和感ありますが、なんとなく意味は伝わります。

第9章 費用対効果の高いテストを設計する

最後は、テストについてです。意味のあるテストの書き方が学べます。
ここまで、オブジェクト指向を学ぶことにより"変更に強い"コードの書き方を学びました。ここで出てくるのが、リファクタリングです。

良いテストは、コードへの変更によってテストの書き直しが強制されないように書かれています。また、テストは唯一信用できる設計の仕様書となります。
privateメソッドのテストはしない、リスコフの置換原則、など知らないことがたくさん書いてあって、参考になりました。

まとめ

新しいオブジェクトを設計する際に変更に強いコードを書くための考え方を学ぶことができました。

今後は以下のような観点に気をつけながら設計していこうと思いました。

  • このオブジェクトの責任はなんだろう?
  • 依存関係はどうなっているだろう?
  • オブジェクトはどんな振る舞いをするべきか?
  • 振る舞いによっては、共有するべきか?(モジュールを使うべきか?)
  • 継承、ダック、コンポジションの使い分け
  • どんなテストを書くべきか(受信メッセージ/ 役割/ プライベートメソッド/ 送信メッセージ/ ダックタイプ/ 継承/ 振る舞い)

全体的に例が自転車で一貫していて、コードもわかりやすかったです。
翻訳にちょっと癖がありますが、読み進めていけば気にならなくなりました。

とてもおすすめなので、ぜひ読んでみてください。

Typescript exercises やってみた 1問目

みなさんこんにちは。宮水です。
今日は、TypeScript エクササイズの1に取り組んでみました。
英語も苦手なので、翻訳も自分でしてみました。

こちらのリポジトリをforkして、cloneして取り組みます。
rootディレクトリで、yarn installしてから問題文にあるRun this exerciseのコマンドを叩くと、答え合わせができます。すごい!!
github.com

前回の問題

miyamizu.hatenadiary.jp

本日の問題

import chalk from 'chalk';

/*

Intro:

    All 2 users liked the idea of the community. We should go
    forward and introduce some order. We are in Germany after all.
    Let's add a couple of admins.

    Initially we only had users in the in-memory database. After
    introducing Admins, we need to fix the types so that
    everything works well together.

 2人のユーザーが、コミュニティのアイデアを気に入りました。
 それでは、いくつかのを注文を取り込みます。(意訳めっちゃ下手www)
 私たちは所謂ドイツにいます。2人を"管理者"として追加しましょう。

 最初はインメモリデータベースには、Userしかいませんでした。
 "管理者(Admin)"型を追加し、全ての機能をうまく機能するために型を変更する必要があります。

Exercise:

    Type "Person" is missing, please define it and use
    it in persons array and logPerson function in order to fix
    all the TS errors.

 型「Person」を追加し、使用してください。
 persons arrayとlogPerson関数のTSエラーを修正してください。

Run this exercise:

    npm run 1

    - OR -

    yarn -s 1

*/

interface User {
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    name: string;
    age: number;
    role: string;
}

const persons: User[] /* <- Person[] */ = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Jane Doe',
        age: 32,
        role: 'Administrator'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    },
    {
        name: 'Bruce Willis',
        age: 64,
        role: 'World saver'
    }
];

function logPerson(user: User) {
    console.log(` - ${chalk.green(user.name)}, ${user.age}`);
}

persons.forEach(logPerson);

// In case if you are stuck:
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types

答え

interface User {
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    name: string;
    age: number;
    role: string;
}

type Person = User | Admin;

const persons: Person[] /* <- Person[] */ = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Jane Doe',
        age: 32,
        role: 'Administrator'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    },
    {
        name: 'Bruce Willis',
        age: 64,
        role: 'World saver'
    }
];

function logPerson(user: Person) {
    console.log(` - ${chalk.green(user.name)}, ${user.age}`);
}

persons.forEach(logPerson);

いい感じ😻
f:id:kattyan53:20200723233638p:plain

感想

ユニオン型

今回は、"Union Types"に関する問題でした。
ユニオン型とは、A | B と書かれ、Aの値でもBの値でも許されます。
今回は、UserとAdminにたいして使用しましたが、以下のような書き方も、ユニオン型です。

// UserIdは、文字列でも数値でもおっけー👌
type UserId = string | number;
interfaceとtype

interfaceとtypeの違いは、この記事を読むのが良さそうです👌
freelance-jak.com

qiita.com


ざっと調べた感じ、この場合にはどっちを使え!っていう決まりは無いようです。

今回のエクササイズの問題を見ると、UserやAdminはオブジェクトなのでinterfaceとして定義して、Personは型の組み合わせに別名をつけているのでtypeを使用しているのかなと思いました。

どっちも使い方が似ていますが、違いを理解して使い分けられるようになると良さそうです。

以上です!

Typescript exercises やってみた 0問目

みなさんこんにちは。宮水です。
今日は、TypeScript エクササイズの0に取り組んでみました。
英語も苦手なので、翻訳も自分でしてみました。

こちらのリポジトリをforkして、cloneして取り組みます。
rootディレクトリで、yarn installしてから問題文にあるRun this exerciseのコマンドを叩くと、答え合わせができます。すごい!!
github.com

本日の問題

import chalk from 'chalk';

/*
Intro:
    We are starting a small community of users. For performance
    reasons we have decided to store all users right in the code.
    This way we can provide our developers with more
    user-interaction opportunities. With user-related data, at least.
    All the GDPR-related issues we will solved some other day.
    This would be the base for our future experiments during
    this workshop.

 私たちは、ユーザーの小さなコミュニティを始めました。
 パフォーマンス上の理由から、全てのユーザー情報をコード上に直接格納することにしました。
 このようにして、少なくともユーザー関連のデータに関して、ユーザーインタラクションの機会を開発者に提供できます。
 全てのGDPR(一般データ保護規則)関連の問題は、別の問題で解決します。このコードは、このワークショップで今後のエクササイズのベースになります。
 
Exercise:
    Given the data, define the interface "User" and use it accordingly.

 「User」インターフェースを定義し、それを使用してください。

Run this exercise:
    npm run 0
    - OR -
    yarn -s 0
*/

const users: unknown[] = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    }
];

function logPerson(user: unknown) {
    console.log(` - ${chalk.green(user.name)}, ${user.age}`);
}

console.log(chalk.yellow('Users:'));
users.forEach(logPerson);

// In case if you are stuck:
// https://www.typescriptlang.org/docs/handbook/interfaces.html#introduction

答え

const users: User[] = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    }
];

interface User {
  name: string;
  age: number;
  occupation: string;
}

function logPerson(user: User) {
    console.log(` - ${chalk.green(user.name)}, ${user.age}`);
}

console.log(chalk.yellow('Users:'));
users.forEach(logPerson);

いえい👏
f:id:kattyan53:20200723224640p:plain


今日は、型定義のやり方と使い方に関する問題でした。
以上です!

普通に食事制限して普通に運動するダイエット2ヶ月目

皆さんこんにちは!宮水です。
エンジニアって在宅で仕事すると運動不足になりがちだけど、今月もダイエット頑張るぞ〜

今月の目標

身長 158cm 53kg
今月の目標は52.0〜52.9kg!

やったことまとめ

  • 朝: 3、昼: 5、夜:2の割合で食べる。
  • Youtubeにある10分くらいのトレーニングを毎日2回やる。
  • 睡眠の質を高めた。(具体的には寝る90分前に湯船に浸かる、寝る前は靴下を履かない、決まった時間に寝て起きるなど)
  • デスクトップを田中みな実さんにする(重要)

おすすめYoutube

この3つを、好きな時間にやりたいときだけやってました。
youtu.be
youtu.be
www.youtube.com

ダイエット記録

32日目(4/25)

体重:53.2kg

朝 0/300kcal

昼 850/600kcal
そば 200kcal
ネギトロ丼 500kcal
ごぼうの和え物 100kcal
豆乳入りコーヒー 50kcal

夜:400/300kcal
ご飯 200kcal
餃子 200kcal
筋トレ20分
エアロビ 15分

合計:1250/1500kcal

一言:今日から2ヶ月目!頑張るぞ〜

33日目(4/26)

体重:53.1kg

朝 0/300kcal

昼 492/600kcal
ご飯 150g 252kcal
ブリ大根 115kcal
納豆 100kcal
ヤクルト 25kcal

おやつ 200/200kcal
アイス 200kcal

夜:215/300kcal
ブリ大根 115kcal
野菜スープ 100kcal

合計:907/1500kcal
一言:今日運動しなかったな...反省

34日目(4/27)

体重:52.8kg

朝 230/300kcal
メープルシロップレモン水 30kcal
豆乳プロテイン 200kcal
筋トレ20分

昼 630/600kcal
ご飯 150g 250kcal
マグロ 200kcal
アボカド 180kcal
お散歩 10分

おやつ 170/200kcal
ぶどう 170kcal

夜:300/300kcal
うどん 300kcal
エアロビ 15分

合計:1430/1500kcal
一言:やったー52kg台!

35日目(4/28)
体重:52.7kg

朝 30/300kcal
メープルシロップレモン水 30kcal
筋トレ10分

昼 600/600kcal
カルボナーラ 500kcal
カフェラテ 100kcal
お散歩 10分

おやつ /200kcal
コーヒーゼリー 154kcal
プロテイン 200kcal
みかん二つ 160kcal
バニトレ 7分

夜:318/300kcal
ご飯少し 168kcal
マグロ 100kcal
野菜スープ 50kcal
筋トレ 20分
エアロビ 15分

合計:1462/1500kcal
一言:筋トレが楽しくて仕方ない

36日目(4/29)

体重:52.7kg

朝 0/300kcal

昼 938/600kcal
グランバーガー 428kcal
ポテト M 410kcal
コカコーラ0
カフェラテ 100kcal

お散歩 30分
おやつ 180/200kcal
プロテインバー 100kcal
みかん 80kcal

夜:700/300kcal
カレー 700kcal

合計:1818/1500kcal

一言:宮水家のマック率の高さよ

37日目(4/30)

体重:53.2kg

朝 320/300kcal
プロテインバー 200kcal
豆乳ラッシー 120kcal
筋トレ 10分

昼 620/600kcal
ご飯 200g 320kcal
鶏肉とキノコのクリーム煮 300kcal
お散歩 30分

おやつ 480/200kcal
カフェラテ 100kcal
杏仁豆腐 80kcal
みかん 6こ 300kcal
ランニング 20分

夜:200/300kcal
鶏肉とキノコのクリーム煮 200kcal
エアロビ 15分
合計:1620/1500kcal
一言:おやつ食べすぎたw

38日目(5/1)

体重:53.5kg

朝 200/300kcal
みかん 4つ 200kcal

昼 900/600kcal
親子丼 400kcal
タピオカ 500kcal
お散歩 40分

夜:200/300kcal
親子丼の残り 300kcal
筋トレ 10分

合計:1300/1500kcal
一言:冷静に食べ過ぎ。

39日目(5/2)

体重:53.4kg

朝 0/300kcal

昼 700/600kcal
チキン南蛮 700kcal
お散歩 20分

おやつ:
ぶどう 180kcal

夜:558/300kcal
マグロ 100g 108kcal
ご飯 150g 250kcal
アボカド 200kcal
筋トレ 10分
エアロビ 7分

合計:1438/1500kcal
一言:明日から食事制限きつくしよう…

40日目(5/3)

体重:53.8kg

朝 243/300kcal
ご飯 168kcal
ツナ 50kcal
ヤクルト 25kcal
筋トレ 8分

昼 360/600kcal
ご飯 80kcal
野菜炒め 200kcal
卵 80kcal
お散歩 20分

おやつ:
カフェラテ 105kcal
プロテインバー 200kcal
バニトレ 7分

夜:230/300kcal
野菜スープ 30kcal
そぼろと卵 200kcal
筋トレ 20分
エアロビ 15分

合計:1033/1500kcal
一言:寝つきが悪くて代謝が悪くなってる気がする...

41日目(5/4)

体重:53.3kg

朝 0/300kcal
筋トレ 10分

昼 700/600kcal
パスタ 700kcal
おやつ:
プロテインバー 200kcal
脚トレ 8分

夜:230/300kcal
野菜スープ 30kcal
豚の生姜焼き 200kcal
エアロビ 15分

合計:1130/1500kcal

42日目(5/5)

体重:53.5kg
朝 310/300kcal
豆乳コーヒー 50kcal
さつまいも 200g 260kcal
筋トレ 10分

昼 614/600kcal
マグロ 100g 108kcal
アボカド 186kcal
ご飯 200g 320kcal

おやつ:
チーズケーキ 234kcal
ウォーキング 20分

夜:130/300kcal
野菜スープ 30kcal
納豆キャベツ 100kcal
卵2個 160kcal
豚の角煮 200kcal
筋トレ 20分
エアロビ 15分
合計:1648/1500kcal

42日目(5/5)

体重:53.8kg

朝 180/300kcal
ぶどう 180kcal

昼 475/600kcal
麻婆豆腐 200kcal
ご飯 250kcal
ヤクルト 25kcal

おやつ 242/200kcal
カフェオレ 92kcal
コーヒーゼリー 150kcal
ウォーキング 20分

夜:500kcal/300kcal
きのことピーマンと鶏胸肉のバター醤油炒め 300kcal
麻婆豆腐 200kcal
エアロビ 15分

合計:1397/1500kcal

44日目(5/7)

体重:53.9kg

朝 300/300kcal
ご飯 250kcal
つな 50kcal
筋トレ 10分

昼 570/600kcal
ご飯 250kcal
ニラ玉 120kcal
プロテインバー 200kcal

おやつ 350/200kcal
豆乳 100kcal
ケーキ 250kcal
ウォーキング 20分

夜:100/300kcal
鶏肉 100g 100kcal
筋トレ 10分
合計:1320/1500kcal

45日目(5/8)

体重:53.1kg

朝 318/300kcal
ご飯 168kcal
つな 50kcal
鶏肉 100kcal

昼 550/600kcal
ご飯 250kcal
生姜焼き 300kcal

おやつ 584/200kcal
プロテインバー 200kcal
豆乳 100kcal
ケーキ 284kcal

夜:150/300kcal
納豆 100kcal
キムチ 50kcal
筋トレ 10分
エアロビ 15分

合計:1602/1500kcal

46日目(5/9)

体重:53.2kg

朝 0/300kcal

昼 1015/600kcal
テリヤキフィレオ 498kcal
ナゲット 270kcal
チェダーチーズソース 77kcal
キャラメルアイスラテ 170kcal

夜:550/300kcal
ご飯 250kcal
豚肉とキャベツの味噌炒め 300kcal
筋トレ 10分

合計:1565/1500kcal

47日目(5/10)

体重:53.3kg
朝 306/300kcal
ツナ(今日のオイル入ってた…)206kcal
ご飯 100kcal

昼 530/600kcal
マグロ 100kcal
アボカド 180kcal
ご飯 250kcal

夜:620/300kcal
生姜焼き 200kcal
キャベツ
納豆キムチ 120kcal
豆乳 100kcal
プロテインバー 200kcal

合計:1456/1400kcal

48日目(5/11)

体重:53.0kg

朝 300/300kcal
ツナ 50kcal
ご飯 250kcal

昼 450/600kcal
豚肉とキャベツの炒め物 200kcal
ご飯 250kcal
おやつ 200kcal
ぶどう 180kcal
ビーフジャーキー 128kcal

夜:0/300kcal
冷しゃぶ 200kcal
筋トレ 10分

合計:1258/1400kcal

49日目(5/12)

体重:52.9kg

朝 300/300kcal
ツナ 50kcal
ご飯 250kcal

昼 550/600kcal
豚肉と大根炒め 300kcal
ご飯 250kcal

おやつ 315kcal
カフェオレ 80kcal
チーズケーキ 235kcal

夜:55/300kcal
野菜スープ 30kcal
ヤクルト 25kcal
エアロビ 15分

合計:1220/1400kcal


50日目(5/13)
体重:53.1kg

朝 250/300kcal
豆乳 50kcal
プロテインバー 200kcal

昼 650/600kcal
ハンバーグ 400kcal
ご飯 250kcal
お散歩 20分

おやつ 359kcal
ほうじ茶ラテ 93kcal
ケーキ 266kcal
筋トレ20分

夜:30/300kcal
野菜スープ 30kcal
エアロビ 15分

合計:1289/1400kcal
一言: カロリーはクリアしてるけど、おやつを辞めねば。

51日目(5/14)

体重:52.7kg

朝 458/300kcal
ご飯100g 168kcal
ツナ 50kcal
プロテインバー 240kcal

昼 600/600kcal
豚キムチ 350kcal
ご飯 250kcal
筋トレ20分

夜:400/300kcal
野菜スープ
そば 一口
ネギトロ巻き 一口
ハマチ
ぶどう
エアロビ 15分

合計:1458/1400kcal

52日目(5/15)

体重:53.0kg

朝 0/300kcal

昼 600/600kcal
パスタ 600kcal
タピオカ 500kcal
お散歩20分

夜:400/300kcal
プロテインバー 200kcal
ピーマンとひき肉の炒め物 200kcal
筋トレ10分
エアロビ 15分

合計:1500/1400kcal

53日目(5/16)

体重:53.0kg
218/300kcal
ご飯 168kcal
ツナ 50kcal

昼 550/600kcal
餃子 300kcal
ご飯 250kcal

おやつ:
豆乳 100kcal
プロテインバー 200kcal

夜:30/300kcal
野菜スープ 30kcal
合計:1098/1400kcal

54日目(5/17)

体重:52.9kg

朝 0/300kcal

昼 892/600kcal
チキンタツタ明太チーズ 482kcal
ポテトM 410kcal

おやつ:

夜:280/300kcal
豚肉とキャベツの味噌炒め 100kcal
ぶどう 180kcal

合計:1172/1400kcal

55日目(5/18)

体重:53.1kg

朝 393/300kcal
Lちき 275kcal
ほうじ茶ラテ 118kcal

昼 368/600kcal
ご飯 168kcal
回鍋肉 200kcal

おやつ 300kcal:
ぶどう 180kcal
プロテインバー 120kcal

夜:100/300kcal
回鍋肉 100kcal
合計:1161/1400kcal

56日目(5/19)

体重:52.7kg

朝 350/300kcal
プロテインバー 200kcal
プロテインチョコ 100kcal
豆乳コーヒー 50kcal

昼 568/600kcal
ご飯 168kcal
春雨 400kcal
筋トレ10分
エアロビ15分

夜:200/300kcal
豚肉とキャベツともやしの炒め物 200kcal
合計:1118/1400kcal

57日目(5/20)

体重:52.9kg

朝 268/300kcal
ご飯 168kcal
ツナ 50kcal
豆乳 50kcal

昼 450/600kcal
ご飯 250kcal
大根と豚肉の煮物 200kcal

おやつ 417kcal
豆乳 137kcal
プリン 280kcal

夜:200/300kcal
大根と豚肉の煮物 200kcal
合計:1335/1400kcal

58日目(5/21)

体重:52.9kg

朝 0/300kcal

昼 990/600kcal
たこ焼き 640kcal
ご飯 250kcal
マグロ 100kcal

おやつ 180/200kcal
ぶどう 180kcal

夜:0/300kcal

59日目(5/22)

体重:52.9kg

朝 300/300kcal
プロテインバー 200kcal
プロテインチョコ 100kcal

昼 800/600kcal
チキンカツ 400kcal
コロッケ半分 150kcal
ご飯 250kcal

夜:0/300kcal

60日目(5/23)

体重:52.9kg

朝 0/300kcal

昼 550/600kcal
ご飯 250kcal
牛肉 150g 300kcal

おやつ: 380/200kcal
ジンジャエール 200kcal
ぶどう 180kcal

夜:0/300kcal
合計:940/1400kcal

61日目(5/24)

体重:52.9kg

朝 300/300kcal
プロテインバーとチョコ 300kcal

昼 500/600kcal
ご飯 250kcal
豚肉とバター醤油炒め 250kcal

夜:350/300kcal
回鍋肉 250kcal
ほうじ茶ラテ 100kcal

合計:1150/1400kcal

62日目(5/25)

体重:52.6kg

朝 400/300kcal
プロテインバーとチョコ 400kcal

昼 350/600kcal
ご飯 250kcal
納豆 100kcal

夜:500/300kcal
豚の角煮 500kcal

合計:1250/1400kcal
やっと体重減ってきた...!

63日目(5/26)

体重:52.1kg

朝 368/300kcal
炭酸水 0kcal
ご飯 168kcal
ツナ 50kcal
プロテインチョコ 100kcal
紅茶 50kcal

昼 470/600kcal
キャベツと豚肉のしゃぶしゃぶ 200kcal
ピーマンの和え物 20kcal
ご飯 250kcal

おやつ:
グミ 62kcal

バターコーヒー 150kcal
夜:0/300kcal

合計:1250/1400kcal

64日目(5/30)

体重:52.1kg

朝 368/300kcal
レーズンクッキー200kcal

昼 470/600kcal
お寿司5皿 700kcal
タピオカ 400kcal

夜:0/300kcal

合計:1300/1400kcal

65日目(5/31)

体重:52.1kg

朝 0/300kcal

昼 1000/600kcal
はらみ丼 800kcal
ジンジャエール 200kcal

夜:0/300kcal
ヤクルト 25kcal
ぶどう 200kcal

合計:1225/1400kcal

まとめ

先月なかなか超えられなかった52kgの壁を突破できた...!
これで、ダイエット開始時54.8kg→53.3kg→52.1kgときて、目標の48kgまであと-4kgとなりました。

だんだん筋トレも飽きちゃったし、レコーディングもだんだん適当になってきたし、最近また夜に眠れなくなってきてしまって(もともとかなりの夜型)後半は夜ご飯をかなり控えめにするという強行突破でした...反省。

あと、なんやかんや月に1kgしか痩せませんね。太るのは簡単だけど、痩せるのってとても難しい...。
6月からは朝昼2回の筋トレと、夜ちゃんと寝ることをしっかり頑張りたいと思います!

「アジャイルな見積もりと計画づくり」を読みました

今回は、「アジャイルな見積もりと計画づくり」という本を読みました。

なぜこの本を読んだのか

私は現在、スクラムを導入して開発をしています。
会社で説明を受けて普段からチームのみなさんと一緒に見積もりをしたりKPTをしたりしているのですが、見よう見まねでやっている部分があります。例えば、「見積もりを相対的につけるということはわかったけど、どうして相対的につけるんだろう?」というような疑問をたくさん持っています。アジャイル開発の本質を知るべくこの本を読もうと思いました。

この本で学べること

  • 見積もりや計画づくりをどうやって行うのか学べる
  • そうしたプラクティスが大切なのはなぜか学べる

この本の対象者

  • あらゆる規模のアジャイルプロジェクトに従事するプロジェクトマネージャー、プロジェクトリーダー、開発者、経営者

第1章 計画の目的

アジャイルな計画"づくり"で大切なのは、出来上がった計画より、計画を立てる"活動そのもの"
見積もりと計画づくりは期日やスケジュールを決めるものではなく、価値の探求であるべきで、「何を作るべきか?」問いに答える作業だと書いてありました。1章めからアジャイルに対する私が今まで持っていた印象が根本からひっくり返されました。

第2章 なぜ計画づくりに失敗するのか

2章では、計画作りに失敗する理由についてです。

  • 計画づくりでは、作業ごとにタスクを立てると失敗する。フィーチャを単位にするべき。
  • 作業を同時並行すると余計に遅れるので失敗する。
  • 見積もりをコミットメントと勘違いするとプロジェクトが失敗する。見積もりは(X日までに終わる)確率で、コミットメントは日付
  • 納期を優先してしまい、ユーザーにとって本当に必要な機能が削られるという失敗。

機能ごとに計画を立て、優先順位をつけ、その機能に集中することがプロジェクトが失敗しないコツなのかもしれないです。

第3章 アジャイル手法

アジャイルなチームとはどんなチームであるかについて。

  • アジャイルチームはあらかじめ決められた計画に従うよりも、おきた変化に適応することに価値を置く
  • チームが最終的に達成したいことはプロジェクトの顧客とユーザーに最大限の価値を提供すること。
  • プロダクトオーナー ... プロダクトのビジョンを提供し、チームが開発するフィーチャの優先順位づけに責任をもつ役割。
  • 満足条件 ... 実現すべきフィーチャとフィーチャが期待通りに実装されたことを確認する概要レベルのテストとして表現される。

アジャイルのチームには、一人一人に役割やゴールがあることがわかりました。

第4章 ストーリーポイントによる規模の見積り

ストーリーポイントが相対的に規模を見積もるものだと説明されていました。

レストランでソーダを頼むときは、スモールサイズとラージサイズを聞いて自分にあった量を頼めば良くて、ソーダの具体的なg数まで言わなくてもいいです。こんな感じで、ストーリーポイントも、あのタスクよりは大きいor小さいで規模を見積もっていきます。

第5章 理想日による見積もり

アメフトの試合は、4時間と決められていても時間通りに終わることは少ないです。(日本だと、野球中継の方がわかりやすいかも)
同じようにプロジェクトも、実際に終わる時間(インタビューやCMの時間も入れたアメフト試合の中継時間)よりも理想時間(純粋にアメフトの試合時間)で考えるべきだそうです。
さらに、ユーザーストーリーひとつにつき、実装とテストとPOの確認時間も含めた理想時間を考えることが望ましいとされています。

第6章 見積もりの技法

6章では、見積もりの技法:プランニングポーカーについて出てきます。
見積もりに労力をかけすぎるのは良くないので、10を超えない非線型の数値「 1 , 2, 4, 8」などでプランニングポーカーをするのがオススメだそうです。

第7章 再見積もり

見積もりをやり直したいときにどうするべきか?がわかりました。

進捗が想定通りではないからという理由で見積もりをやり直してはいけません。
また、ベロシティを補正装置として使うことで見積もりの不正確さがなくなります。

第8章 ストーリーポイントと理想日

ストーリーポイントで見積もる方法と理想日で見積もる方法について書かれていました。

ストーリーポイント

ストーリーポイントで見積もる場合、その見積もりはチームの技術力によらない。
理想日での見積もりよりも早く見積もりができる。

理想日

理想日で見積もる場合、プロジェクト関係者に説明しやすいメリットがある。

理想日で見積もっているうちに見積もり力も上がって、タスクを相対的に大きいか小さいか考えられるようになるので、自然とストーリーポイントで見積もるようになっていく。

第9章 テーマの優先順位付け

何事も優先順位をつけるのは大切です。

優先順位をつけるときに必要なのは、

  • 金銭価値
  • 必要となるコスト
  • 得られる知識の量とその意義
  • 提言できるリスク

の4つです。

第10章 金銭価値による優先順位づけ

10章では、財務的な分析から優先順位をつけていきます。

収益のモデル化は以下の4つで十分で、さらに効果を予想するのは大抵2年先までで十分です。

  • 新しい顧客
  • 既存の顧客が追加で購入
  • 既存の顧客が継続して使用してくれる利益
  • 業務の効率化による利益

第11章 「望ましさ」による優先順位づけ

金銭で優先順位をつける方法の次は、望ましさによる優先順位づけについてです。

苅野の分析による優先順位づけ
  • 当たり前のフィーチャ...必須
  • 線形のフィーチャ...あればあるほどいい
  • 魅力的なフィーチャ...あれば魅力的。
相対的重み付けによる優先順位づけ
  • フィーチャについての利点
  • フィーチャがないことの悪影響
  • 開発するためのコスト

どちらの手法でもよく、自分の組織にあった方を選びましょうとのこと。

第12章 ユーザーストーリーの分割

ユーザーストーリーの分割の方法について。

  • 扱うデータに沿って分割するパターン
  • ストーリーを実現するためのユーザー操作に沿って分割するパターン
  • エラーハンドリングやセキュリティ、ロギングなどの横断的な機能でも分けられる
  • 一方で、細かいストーリーをまとめた方がいい場合もある。

第13章 リリース計画づくりの基本

13章から第4部に入ります。ここからはスケジュールの立て方について学びます。

例えば、6ヶ月後に新しいプロダクトをリリースしたい場合、1イテレーションが2週間であれば13回イテレーションを回せます。
ベロシティが20ptであれば、260ptを超えないようにストーリーを選び、それぞれに優先順位をつける。
これの一覧がリリース計画です。リリース計画は、各イテレーションが始まるときに必要に応じて更新するようにします。

第14章 イテレーション計画づくり

リリース計画が立てられたら、ユーザーストーリーを実装することに集中するためにイテレーションプランニングを計画します。

イテレーション計画は、リリース計画とは異なりユーザーストーリーをタスクに分解し、理想時間で見積もります。
やり方はベロシティ駆動とコミットメント駆動の二つがあります。

余談ですが、コラムにあったイテレーションの始まりを「月曜始まり金曜終わり」にするのではなく「金曜始まり木曜終わり」にするというのは目から鱗でした。木曜終わりにすると、終わらなかった分を金曜の午前にやることができるし、午後はレビューとイテレーションの計画を立てるのに当てて1日を終えることができるからだそうです。確かに私自身も、月曜始まり金曜終わりでやっていた頃は、金曜に終わってない分を土日に作業したりしていました。現在の会社は、曜日ではなくてチームごとの会議と全体の会議を合わせてイテレーションの長さを決めたりしています。

第15章 イテレーションの長さを決める

全てのチームが使えるイテレーションの長さはありません。
リリースまでの期間や、不確定要素の高さなど、様々な条件を考慮しながら自分たちで決めます。
だいたい2〜4週間が多いそうです。

第16章 ベロシティの見積もり

ベロシティの見積もりには、以下3つの方法がある。

  • 過去の実績値を平均する。(ただし、チームやプロジェクトの性質、技術などに大きな変化がないか確認する。)
  • 実際にイテレーションを実施する
  • ベロシティを予想する

第17章 不確実性に備えるバッファの計画

バッファの持たせ方について。
フィーチャーバッファ...機能に優先順位をつけて、「全て実装するわけではない」と合意をとるやり方。(買い物の時間が30分しかないので、ほしいものリストにある37個のうち20個しか買わない...みたいな感じ。)

スケジュールバッファ...スケジュール全体にバッファを持たせるやり方。(旅行に行くときに、準備、車、飛行機の搭乗で70分かかるとしたら、100分前にでる。うまくいったら30分暇つぶししないといけないけど...みたいな感じ。)

バッファは水増しではない。バッファはもちろん小さい方が望ましい。
「3日かかる」と心では思っているのに「5日かかる」と口で言ったらそれは水増しなのでよくない。

第18章 複数チーム編成プロジェクトの計画づくり

この章では、一つのプロジェクトに複数のチームが関わっているときに役立つ4つのテクニックについて解説されていました。

  • チームで見積もり基準を同じにする
  • 複数チームが同じプロジェクトで作業するとき、ユーザーストーリーを早い段階で見積れるようにしておく
  • 今後予定されているイテレーションのいくつかまでの先を見越して計画を立てる
  • チーム間で合流バッファを設ける

第19章 リリース計画のモニタリング

ベロシティとは、一回のイテレーションで完了させた仕事量を測定したものです。
作業に取り掛かっていても、完了していない分はポイントに入れません。
ベロシティの推移をみる為に、リリースバーンダウンチャートやバーキングロットチャートなどのグラフがあります。

第20章 イテレーション計画のモニタリング

イテレーションの進捗を把握するのに役立つのが、タスクボードといイテレーションバーンダウンチャートです。
タスクボードは、チームによってラベルを変えてもいいですが、私のいるチームではよくBacklog / Open / WIP / In Review / Closeとかでカテゴリ分けされています。
イテレーションバーンダウンチャートは、縦軸に残作業の合計時間を、横軸にイテレーションの何日目かを取る折れ線グラフです。

また、個人単位でベロシティは計測してはならないと書いてありました。そうすると、チームの誰かが困っていても個人のベロシティを優先するような仕組みになってしまうため、チームのベロシティの寄与にはならないからだそうです。なるほど...。

第21章 計画とコミュニケーション

見積もりと計画に関するコミュニケーションは頻繁で正直なものであるべき。
計画や進捗状況を伝える方法として、グラフを使ったもの、過去イテレーションをグラフにしたものなどがあります。

第22章 なぜアジャイルな計画づくりがうまくいくのか

アジャイルな計画づくりの目的とは、どんなフィーチャを、どれだけのリソースを投入して、いつまでに作り上げるのか、この問いの最適解をイテレーションを繰り返しながら近づいていくこと。
計画を頻繁に見直したり、タスクではなくフィーチャを基準として見積もりを立てる。
不確実性を受け入れて、プロダクト開発全体の問いに答えていく行為。

第23章 ケーススタディ:ボムシャルタースタジオ

23章では、6ヶ月遅れているというあるゲームソフト開発のプロジェクトにアジャイルを導入した例を見ていきます。
今までの章で学んだ大切な点を、会話形式で一気に読むことができます。

まとめ

見積もりと計画づくりは期日やスケジュールを設定するためだけのものではなく、計画づくりとは価値の探求だ、という言葉を読んでとても納得・感心しました。この一言にアジャイルの本質の全てが詰まっていると感じました。

昔話になるのですが、チームの誰一人としてアジャイルについてよくわからないままプロジェクトを進めていたことがありました。
用語やフレームワークだけアジャイルっぽいことをしていたのですが、作ってから「こういうことじゃないです」と作り直しになったり、進捗に正直でない人がいて、全然約束してた時間に間に合わなかったり、めちゃくちゃでした。

何が言いたいかというと、この経験から、アジャイルフレームワークだけ導入しても絶対にアジャイル開発はうまくいかないということです。「なぜ、これをやるのか?」 チームメンバー全員がわかっていないと、各見積もりや計画づくりの段階で話し合うべきことがわからなくて後から出てきた新たなタスクに対処できなかったり、計画を立て直すのが難しいくなったりするのかな、と思いました。

私も将来後輩ができて、プロジェクトを回すようになったときは、「プロジェクトの進め方」ではなく「なぜこれをするのか」に焦点を当てて伝えていきたいなと思いました。

次はスクラムブートキャンプを読みたいです!


ここまでお読みいただきありがとうございました。