Software engineering from east direction

六本木一丁目で働くソフトウェアエンジニアのブログ

アジャイル開発におけるメンタルヘルス 〜駆け出しアジャイル記録〜

TL;DR

  • アジャイル開発における「あるあるの失敗」は、コミュニケーションを一瞬でも取り逃すと発生しうる
  • どういうときに流れに飲み込まれ、メンタルの追い込みが発生しうるかを考えた
  • 何を主眼としているかを何度もコミュニケーションし、発生させてしまいかねない副作用を避ける、流れに飲み込まれないための施策が必要だろう

背景

所属企業で、かつてからのチーム開発の課題や、WORK FROM HOME な事情もあり、アジャイルムーブメントをに取り組んでいます。そのなかで、現職での取り組みを始めてざっと3ヶ月弱となり、教科書どおりには決していかない、自分たちにとって最適なものは何かを日々レトロスペクティブなどで探っている日々。そんな発展途上な段階の思考をdumpしてしまおうという記事。

上記資料については、プロジェクトをどう進めるかについては、説明していないが、チームの取り組み方を変えた後に、プロジェクトの取り組み方自体に対して、漸進的にリズムを作っていっている最中という状況。

以下、取り除いたほうが良さそうだと感じたリスクを感覚レベルの粗末な文章で書き連ねていく。

生産性を気にしていないか?それを主眼にしていなくても視界にはいることのリスク

前提:ストーリーポイントでの見積もり、消化ポイントをメトリクスに取ることによるベロシティ計測

見積もりの手法として、いくつか他PJでも採用されている「ストーリーポイント」を使用している。これは、だいたい3日でできるといった差込なしの作業に対する見積もり(理想日による見積もりとよく表現される)のではなく、それぞれのissueを相対評価大きさで図るもの。

たとえば、「注文完了時にメールを送信する」を1ptとしたら、「注文情報を表示する」は相対的にメール送信するよりもやること多いし、技術的にも触れるバリエーションが多いから3ptくらいかしら、的な形で相対評価で、そのタスクがはいるばけつはど〜れ?って考えるやり方といえる(と認識している)。

そして、それを1週間など一定期間でどれだけの大きささばけたか、を計測していくことで、自分たちが見積もりに対してどれだけの速度でさばけるかを、ベロシティとして認識する。平均速度のようなものなので、何らかそのメトリクスに下降傾向とかがあったら「あれ?どうしたのかな?体調が悪い?」といった形で図れるといった効果も期待される。

チームのメトリクスと見ても、個々人の生産性に"感じる"リスク

個人としてチームのメトリクス内で「どれだけの大きさ」できた?みたいなのが、意識内に入ってしまうところはある、だってにんげんだもの

これに対して、小さい組織の分にはコミュニケーションの中で「なぜいまこれをしているのか」について会話をすることで何らか対策が取れるだろうが、人数が増えると大変そう。やり方をフレームワークと捉えてしまうと、即座にフレームワークの罠に陥ってしまうだろう。「前職でやってたけどつらかった」といった話はこういった経験から生まれるのかもしれないですね。

今のところ考えること: 成果(WHAT)と取り組み(HOW)の振り返りは分離する

極端なことを言うと、たくさんストーリーポイントを消化しようがしまいが、成果(WHAT)がでてフィードバックがもらえてっていうループが回せるか、が重要と心得る。

プロジェクトの成果を振り返る場では、プロダクトに対して純粋に「こうしたほうが良い?」・「ここはこう治そう」と向き合うことが出来るが、チームでの取り組みを振り返る(レトロスペクティブとよんでいる)場で仮にWHATを図ろうとした場合にできることは「消化ポイントがどれくらいだったか」になる。これがよくない。明確にWHATとHOWの振り返りを分離することで、ベロシティを上げることから視線を外す事が必要なのではないか。

また、想定した成果が出なかったよぉっていうときには、それはプロジェクトの成果として考えると良いのだろう。たとえばプロジェクトにどれだけ時間を費やしたか、といった占有率、とかそういうことが分析として考えられる。

ある種、PJ単位にすることは逃げ道を用意できる側面もあるだろう。いろいろ他のこともしていたので〜だったり。逃げるは恥だが役に立つ

そんなことを思っているので、スプリントレビュー(PJの成果レビュー)とレトロスペクティブ(チームでの取り組み振り返り)を分けることにしている。

適度なプレッシャーを保てるか

1週間っていう期間をおいて、毎週成果を出しましょうっていうのは、リリースが毎週繰り返されるみたいなお気持ちに近いところがあるので、それなりのプレッシャーは精神にかかることにはなる。だからこそメンタリング装置が各所に仕込まれているっつう話なんだろうが、このプレッシャーが適度なものになっているかは、気にしないといけない。

自分なりの努力を重ねることを元プロ野球選手のイチローが言っていたが、ゆうて自分なりに馴染む温度で仕事をすれば良いのであって、過プレッシャーはよくない。

個人にとってのHOWとWHAT

プログラマ個人にとって、HOWの理解→WHATへの焦点といった段階があるのか、とか早朝朝5時思い立ったのは、たとえば、いまからBASEの中でAPI作ってくださいねってときに、何が焦点になるかというと人によって異なっていて、3びきのこぶたのテンションでいうと、

  1. PHPを書くぞ
  2. ブラウザからアクセスされるAPIを書くぞ
  3. BASEのサービスを作るぞ

みたいな感じでそれぞれどこに焦点があたっているかで、なんとなくその人の仕事感みたいなところが出るのかな、とかおもう。

1がわりとHOWよりで、3がWHAT寄りだが、1が焦点の状態で1に取り組むと、HOWに対するプレッシャー、つまり、「PHP難しそうだけど頑張るぞぉ...」っていうプレッシャーがのってくる。

さて、そのうえでイテレーションで動くものをつくりましょう、なり、なんらか明確な言葉で成果を定義されると、その焦点は自然と2以降にずらされる。

結果的に、これまでHOWのプレッシャーが掛かっている状態で、さらにWHATのプレッシャー、つまり「今週中に自分がやりきらないといけないのはこのAPIを...」とか、「ユーザーが待っているし問い合わせも日々見るから早くリリースを...早く...」と、上乗せされる。

この事象に対して、HOWのプレッシャーに戦略的に鈍感になることで、すぐにWHATを実現しよう、みたいな話が技術的負債のあれこれに、つながっていったりするのだろう

無意識的にHOWのプレッシャーに鈍感であることは、「プロとしてレベルの低い仕事をしていることに気が付かない」可能性を含んでいるので危険だろうけども。

今のところ考えていること その人にとってのプレッシャーがどこにのっているかによって計画の立て方を変えるのが良いのかもしれない

たとえば、オンボーディング期間とかの状態で、即座に明日リリースだからシュッと全部実装してデプロイしてください、みたいなことをいうと、極端にHOW/WHAT両方のプレッシャーが押し寄せて、震度7大震災ですいやーんこわーい、って話。

そういう期間であることを加味した設計が必要なのだろう。ペアオペなどで知識を同化していく〜みたいな話も、精神の余裕があってこそ。

個人が職能横断的であることが求められる昨今

個人が職能横断的にであることが求められる昨今ホンコン。これ自分は麻痺してるんだけど、けっこう大変なんですねっていうことをおもい。

組織重力の3つの法則というみんなでアジャイルの中で語られている話だと、組織の個人は自分のサイロの中で簡単な仕事を優先する、みたいな話があるので、別に自分たちが自立してだいたいのものはカバー範囲にありコントロール下にある「簡単な仕事」にしていくことは、プロダクトの課題解決にあたってはなくては厳しいと思うが、あくまでそれはチームの話

思っていること 個人が職能横断的ではなくてもいいことは改めて言語化しないといけないのだろう。

アジャイルチームのメンバー構成の要件にはプロフェッショナルがいることを上げているが、特化した専門性は必ず必要になる。 チーム状況によっては、ある程度、専門外のことをやる必要があるが、それが強いられることはない。

専門的組織との関わり方

職能でレイヤーの切られた組織において、職能横断的であることが求められた場合、その人の志向性とミスマッチする可能性がある

PHPで世界をとりたい、みたいな人に「今からTerraform書いてAWSのインフラ作ってくれ」って言うのはその人にとって不幸せな余分な時間になるだろう。

あるいはデザインやML的な文脈でも違う専門性なので、そこに対して職能横断的であることを強いるのは精神衛生上良くない。

おもうこと プロジェクトの関係者 != チーム

チームであることを強いると、上記のミスマッチを発生させてしまう可能性がある。プロジェクトの捉え方について認識をすり合わせることは、仕事をしていく上で大事だが、それとはまた別の話。

What are you doing? 何をいましているのか・どうやっているのかをプロジェクトとしたら、チームであることを強いるのは「どこにいるのか」を規定してしまう。

たとえば、突然あなたは明日からメイドカフェのチームとして振る舞ってもらわないといけないので、猫耳をつけてくださいって言われたら、とりあえず退職届を書くことになると思うのね。 メイドカフェを立ち上げるPJをやるからそのPJにJOINしてもらいます、その中ではこういうふうに考えてやっていくの、さぁ猫耳をつけてって言われたら、いやそれでも退職届を書くことに...

例が悪かった。いい例が思いつかないが、具体的な話に戻ると、スプリントレビューに入ってもらう人と、レトロスペクティブに入ってもらう人は、明確に違う風にしていいと思っているということ。

これは、1PJ=1TEAMの1-1の関係であれば両方入るカバレッジが100%だし、社前提がアジャイルな文化です、っていうならそれもカバレッジ100%だが、世界は多種多様でよくわからないので、自身がどういう状況にいるのかを考えた上で、!= であることを改めて確認したほうが良いのだろう。

これは、組織学習の過程とも言えるかもしれない

上記の怪文書は、ある種これまで潜在的に課題だったものが発見される過程なのかもしれない。

アジャイル開発は組織学習をプロセスに取り込んでいます。アジャイルなチームとなっている組織とそうでない組織を比較して、個々のメンバーを眺めてみると、確かにアジャイルなチームのほうが優秀なメンバーが揃っているように見えるでしょう。しかし、初めから優秀なメンバーを揃えないとできないというわけではありません。おそらく、アジャイルな方法論を取り入れることができないほど優秀でないメンバーであれば、他のプロセスを採用したとしてもうまくいく可能性はありません。

広木 大地. エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング (Japanese Edition) (Kindle Locations 3144-3149). Kindle Edition.

生JSONを扱うのにちょっと便利な json.RawMessage と観測した実例

TL;DR

  • JSONを扱う際に、標準のjsonパッケージでは、 RawMessage という型が用意されている
  • JSON構造の文字列を取り出して、なんらか整形して出力、といったユースケースにちょっと便利

json.RawMessage

JSONを扱う際に、標準のjsonパッケージでは、 RawMessage という型が用意されている。

// RawMessage is a raw encoded JSON value.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte

godoc.org

RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.

上記の説明にある通り、 RawMessage は、 json.Marshaler interface と json.Unmarshaler interface を実装しているため、 JSON decode / encode に用いることが出来る。

https://godoc.org/encoding/json#Marshaler

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

https://godoc.org/encoding/json#Unmarshaler

type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}

Marshal

たとえば、次のようにJSONを受け取り、その後それを json.MarshalIndent() で整形すると言ったことも可能。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
)

func main() {
    m := json.RawMessage(`{"hoge": false, "huga": "piyo"}`)

    c := struct {
        FlexJson *json.RawMessage `json:"json"`
    }{FlexJson: &m}

    md, err := json.MarshalIndent(&c, "", "\t")
    if err != nil {
        log.Fatalf("error: %#v\n", err)
    }
    fmt.Fprint(os.Stdout, string(md))
}

https://play.golang.org/p/FFyY4fS89Du

ここで、JSON形式として破綻している構造の文字列だった場合は、json.MarshalIndent()にて、json.SyntaxError が返答される。

error: &json.SyntaxError{msg:"invalid character ']' after object key:value pair", Offset:88}

https://godoc.org/encoding/json#SyntaxError

// A SyntaxError is a description of a JSON syntax error.
type SyntaxError struct {
    msg    string // description of error
    Offset int64  // error occurred after reading Offset bytes
}

func (e *SyntaxError) Error() string { return e.msg }

Unmarshal

たとえば、配列形式の中に異なる構造のJSON Objectsがある場合、次のように、Unmarshalしてコード内で処理することも出来る。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
)

func main() {
    res := []byte(`{
  "field1": [
    {"hoge": false, "huga": "piyo"},
    {"ponyo": 1, "piyo":  false}
  ]
}`)

    type c struct {
        Field1 []json.RawMessage `json:"field1"`
    }
    var cc c
    if err := json.Unmarshal(res, &cc); err != nil {
        log.Fatalf("error: %#v\n", err)
    }

    for _, v := range cc.Field1 {
        var dst interface{}
        if err := json.Unmarshal(v, &dst); err != nil {
            log.Fatalf("error: %#v\n", err)
        }
        fmt.Fprintf(os.Stdout, "%#v\n", dst)
    }
}

https://play.golang.org/p/MsJFzMoLmKc

OSS内での使用例

json.RawMessageの現実世界で活用されているOSSの例として、mackerelio/mkr内で利用されています。

具体的には、mkr monitors pullというコマンドを使用した際に、Mackerelサービスに設定されている監視設定をローカルに落としてくることが可能なのですが、その際の処理に json.RawMessage が活用されていました。

func decodeMonitors(r io.Reader) ([]mackerel.Monitor, error) {
    var data struct {
        Monitors []json.RawMessage `json:"monitors"`
    }
    if err := json.NewDecoder(r).Decode(&data); err != nil {
        return nil, err
    }
    ms := make([]mackerel.Monitor, 0, len(data.Monitors))
    for _, rawmes := range data.Monitors {
        m, err := decodeMonitor(rawmes)
        if err != nil {
            return nil, err
        }
        ms = append(ms, m)
    }
    return ms, nil
}

https://github.com/mackerelio/mkr/blob/ef0237b6e6c18cab2d9ce3d0fd34e166076f5fb0/monitors.go#L109

ここでの処理は、APIレスポンス内にある monitors キー以下に、JSON Objectの配列が含まれているのを、[]json.RawMessage と定義することで取り出しています。

json.RawMessageを利用した利点として、これ配列内でさらにJSON Objectをdecodeして、中のtypeキーの情報を取得、その内容によってunmarshalする構造を切り替えるということをしています。

func decodeMonitor(mes json.RawMessage) (mackerel.Monitor, error) {
    var typeData struct {
        Type string `json:"type"`
    }
    if err := json.Unmarshal(mes, &typeData); err != nil {
        return nil, err
    }
    var m mackerel.Monitor
    switch typeData.Type {
    case "connectivity":
        m = &mackerel.MonitorConnectivity{}
    case "host":
        m = &mackerel.MonitorHostMetric{}
    case "service":
        m = &mackerel.MonitorServiceMetric{}
    case "external":
        m = &mackerel.MonitorExternalHTTP{}
    case "expression":
        m = &mackerel.MonitorExpression{}
    case "anomalyDetection":
        m = &mackerel.MonitorAnomalyDetection{}
    }
    if err := json.Unmarshal(mes, m); err != nil {
        return nil, err
    }
    return m, nil
}

発想としては、以下のブログ記事内の

engineering.linecorp.com

ですので、SDKではUnmarshal用の別typeを用意し、その中でまずは type だけ先に読み取り、それから改めて型を決定してUnmarshalする、という方法を取りました。

という方法と類似していると見れそうです(と、@budougumi0617さんに教えていただきました)。

このようなケースがひとつ、 json.RawMessage の活用例としてあげられそうです。

mkr/monitors.go at ef0237b6e6c18cab2d9ce3d0fd34e166076f5fb0 · mackerelio/mkr · GitHub

f:id:khigashigashi:20200623021642j:plain:w320

Fin

PHPコードの些末なレビューの機械化を phpcs と slevomat/coding-standard で加速しよう

TL;DR

  • PHPコードにおける、constはpublic/privateつけようね、とか、戻り値type hintingは、型名の前にspace入れようね、みたいな話、それphpcsに指摘してもらおう
  • quizlabs/php_codesniffer と slevomat/coding-standard を使用する
  • 細かくコーディングルールを拡充して、機械化を加速できる

どうすればいいか

なるべく設計的な意思決定があまり介在しないような定型的なレビューを人間がやるのは、レビュワーもレビュイーも両方疲弊してしまう。その解決案として、slevomat/coding-standardを使うのが手としてあります。これは、quizlabs/php_codesniffer のsniffs(検証ルールのようなもの)を様々提供しているライブラリです。

github.com

これを使い始めるのはかんたんで、composer require --dev したあとに、

$ composer require --dev slevomat/coding-standard

rulesetにconfigとして追加する。

ruleset.xml

<?xml version="1.0" encoding="utf-8" ?>
<ruleset name="php-pj">
  <description>ruleset based on PSR2</description>
  <exclude-pattern>vendor/*</exclude-pattern>
  <rule ref="PSR2">
  </rule>
  <config name="installed_paths" value="../../slevomat/coding-standard"/><!-- relative path from PHPCS source location -->
</ruleset>

まず、<config>により、slevomat/coding-standardが提供するルールを認識できるようにする。

<config name="installed_paths" value="../../slevomat/coding-standard"/><!-- relative path from PHPCS source location --> ですね。

以降は、 <rule> に使いたいものを指定していきましょう。

こういうのを指摘してもらえばいいんじゃない

さまざまなルールがあるが、個人的にこれは現場でも使おう、と思ったものをいくつかピックアップします。

定数定義には可視性指定しよう

SlevomatCodingStandard.Classes.ClassConstantVisibilityを使用すると、定数定義にて public または private を指定しているかどうかを指摘してくれる。

例えばこういうコードだった場合に、

    const HOGE = 'hoge';

こう指摘される

----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 31 | ERROR | Constant \Hoge\Huga::HOGE
    |       | visibility missing.
----------------------------------------------------------------------

次のようなコードに直すように、チームみんなで統一することができる。

private const HOGE = 'hoge';

default nullはnullableだよ

SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue を使用すると、デフォルト値をnullとしている引数の型宣言が nullable になっているかをチェックしてくれます。

    private function getDateFromFormat(string $date = null)

これは、こう指摘される。実質デフォルト null にしている引数のtype hintingは nullable なのでこちらのほうが健全な感じはある。

----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 1291 | ERROR | [x] Parameter $date has null default value, but is
      |       |     not marked as nullable.
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

戻り値のタイプヒンティング前の space

SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing を使用すると、戻り値のタイプヒンティングの前にspaceが入っているかをチェックしてくれます。

こういうコードがあるとする、

    public function hoge():void

これは、こう指摘される

----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 907 | ERROR | [x] There must be exactly one space between return
     |       |     type hint colon and return type hint.
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

これまでピックアップしたものを設定すると次のようなruleset.xmlになる。

<?xml version="1.0" encoding="utf-8" ?>
<ruleset name="php-pj">
  <description>ruleset based on PSR2</description>
  <exclude-pattern>vendor/*</exclude-pattern>
  <rule ref="PSR2">
  </rule>
  <config name="installed_paths" value="../../slevomat/coding-standard"/><!-- relative path from PHPCS source location -->
</ruleset>
<config name="installed_paths" value="../../slevomat/coding-standard"/><!-- relative path from PHPCS source location -->
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing"/>
<rule ref="SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue"/>
<rule ref="SlevomatCodingStandard.Classes.ClassConstantVisibility"/>

その他

実行時の注意点として、ローカルのグローバルなphpcsで実行すると認識できないので、ちゃんと ./vendor/bin/phpcs を使用しましょう。composer scriptなりから呼ぶと自然とそのレポジトリ内のものを使用するのでよき。

PHPコードでの、`empty()`避けようねとか`===`のほうがベター、などは phpstan/phpstan-strict-rules を使って指摘しよう

TL;DR

  • PHPアプリケーションにおいて、表題のような「PHPを使う上で自制心を持とうな」みたいな温度感でstrictな書き方を推奨される昨今
  • こういうのは往々にして人間が言うのはそのうちげんなりしてくるし、逆に言われる方も同じ
  • PHPStanが提供しているカスタムルール phpstan/phpstan-strict-rules を使おう

前提

PHPStanを使うことを前提としています。

phpstan/phpstan-strict-rules

github.com

PHPStanは、「PHPStanでCustomRuleを作る」という発表でも解説されている通り、任意のカスタムルールをクラスとして定義することで、ルールを追加できます。しかし、すでにPHPStanが提供しているルールもいくつかあります。その一つが phpstan/phpstan-strict-rules です。

導入方法は

かんたんで、 composer require --dev phpstan/phpstan-strict-rules でinstallしてから、 PHPStanの設定ファイル(ex. phpstan.neon)に加える。

すべてのチェック項目を加えたい場合はincludesに追加すれば良い。

parameters:
  level: max
  paths:
    - src
    - tests
  ignoreErrors:
    - '#Dynamic call to static method PHPUnit\\Framework\\.*#'
includes:
  - vendor/phpstan/phpstan-phpunit/extension.neon
  - vendor/phpstan/phpstan-strict-rules/rules.neon

個別の項目を一つずつ加えたい場合は、servicesに追加すれば良い。

services:
  -
    class: PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule
    tags:
      - phpstan.rules.rule
  -
    class: PHPStan\Rules\StrictCalls\StrictFunctionCallsRule
    tags:
      - phpstan.rules.rule

どういう指摘をしてくれるか

たとえば、 empty() を使用したコードが有る場合は次のように指摘される

Construct empty() is not allowed. Use more strict comparison

あるいは、in_array() の第三引数をtrueにしていない場合はこう

Call to function in_array() requires parameter #3 to be set.

その他指摘される項目は、GitHubのREADME.mdにずらっと書いてあるので、自分たちにとって全て取り入れられるのか・一部のみなのかを判断するとよい。

導入の注意点

すべてのルールを適用すると、phpstan/phpstan-phpunitを入れていても、PHPUnitを用いたテストコードが次のように怒られてしまいます。

/Users/kazukihigashiguchi/src/github.com/baseinc/yellbank-php/tests/Api/ClientTest.php:54:Dynamic call to static method PHPUnit\Framework\Assert::assertSame().
/Users/kazukihigashiguchi/src/github.com/baseinc/yellbank-php/tests/Api/ClientTest.php:155:Dynamic call to static method PHPUnit\Framework\Assert::assertSame().
/Users/kazukihigashiguchi/src/github.com/baseinc/yellbank-php/tests/Api/ClientTest.php:191:Dynamic call to static method PHPUnit\Framework\Assert::fail().
/Users/kazukihigashiguchi/src/github.com/baseinc/yellbank-php/tests/Api/ClientTest.php:233:Dynamic call to static method PHPUnit\Framework\Assert::assertSame().

こういうのは、Issueにもある通り、ignore patternに追加することで対応しましょう。

  ignoreErrors:
    - '#Dynamic call to static method PHPUnit\\Framework\\.*#'

開発チームについて考えてアジャイルについて行動してみた | 書評『みんなでアジャイル ――変化に対応できる顧客中心組織のつくりかた』

TL;DR

  • 『みんなでアジャイル ――変化に対応できる顧客中心組織のつくりかた』 を読んで、実際に現実の(渡しがいる)チームの問題について考えた
  • 自分は、アジャイルのプラクティスについてなんとなく知っているが、実際に「アジャイルでのチーム開発」をやったことがない人間だった
  • そんな人間にとって、「アジャイルとはそもそも何なのか?何だったのか?どうすれば現実にうまく適用できるのか?」を考えるきっかけをくれる良書だった。

『みんなでアジャイル ――変化に対応できる顧客中心組織のつくりかた』とは

この書籍は、2020年03月に、日本語訳版が発売された。この書籍の訳者である ryuzee さんは、fukabori.fm: 32. みんなでアジャイル w/ ryuzeeに出演して直接この書籍の内容について解説してくださっている。

www.oreilly.co.jp

著者の、Matt LeMayという方は、Sudden Compassの共同設立者兼パートナーであり、同社は、 「OUR CLIENTS」にある通り、American ExpressやSpotifyなどの組織の顧客中心主義を実践する支援をされている。

f:id:khigashigashi:20200510052153p:plain

www.suddencompass.com

そんな著者の書いたこの書籍は次のように説明されている。

本書では、「顧客から始める」「早期から頻繁にコラボレーションする」「不確実性を計画する」をアジャイルの3つの原則とし、この原則を組織で共有し実践していく方法とその課題を解説します。原則を素早く実現するためのアイデアや方法、原則が適用できているかを確認する方法とうまくいかない場合の対応法などを紹介します。 アジャイルの原則を理解してゴールを定め(目標)、自分たちにあったアジャイルラクティスを見つけ(方法)、現実的な成果をもたらしているかを計測し(成果)、これらを見直しながら繰り返すことでアジャイルを継続的に強化する方法を解説します。またワークシートを用意しており、自分の環境に照らし合わせて考えることができます。 https://www.oreilly.co.jp/books/9784873119090/

つまり、この書籍は アジャイルの原則を組織で共有しいかに実践するか、それに至るまで・実践する際の課題について解説したものだ。読者として読んだ感想としては、「プランニングポーカー」とか「イテレーション」とか、個別具体的な方法というよりかは、その考え方・仕事の仕方としてのアジャイルをどう捉えて実践するかに焦点を当てている。

また、リーン開発・デザイン思考との比較についての言及しているため、近い概念との境界・輪郭をよりはっきりさせてくれる。

リーン開発やデザイ ン思考は事業企画フェーズ、アジャイルは設計から実装を経てのリリースまで のフェーズ、DevOpsは実装後期から運用のフェーズ。もちろんオーバーラップ する時期もあるが、大きく分けるとこのようなフェーズごとのアプローチと解釈できよう。 本書では、これらに別の解釈も加える。リーン開発は効率性(投資効果の最大 化)を目的とし、アジャイルは迅速性を高めることを目的とし、デザイン思考は ユーザービリティ(使い勝手)を目的とする、と筆者は定義する。

「みんなでアジャイル」 まえ書き

自分は、何らかチーム開発のプラクティスを実践することについて、たしか2年前くらいから考えていた。しかし、アジャイルでのチーム開発をやったことがある人達の話を聞くと、「うまくいった」・「うまくいかなかった」という両極端の意見を聞くことが多く、とても戸惑っていた。

そもそも「アジャイルはうまくいく・いかない」という次元の手法の話なんだっけっていう疑問を持っていたが、それに対してうまく理解を落とし込む機会がなかった。しかし、この書籍は私のこの疑問に明快な言葉で説明してくれました。

以降、書籍を読んで自分が引っかかったこと・学んだこと・考えたことを記していきます。

アジャイルソフトウェア開発宣言

アジャイルムーブメントの始まりは、History: The Agile Manifestoにて知ることができる。

On February 11-13, 2001, at The Lodge at Snowbird ski resort in the Wasatch mountains of Utah, seventeen people met to talk, ski, relax, and try to find common ground—and of course, to eat.

スノーバードというリゾート地にて集まった17人が合意し、共有しようとした価値観は次の短い文章に集約されている。

f:id:khigashigashi:20200510052218p:plain

agilemanifesto.org

ここには一切の手法・ツール・プラクティスのことが言及されていない。本書籍でもこのことを重要だと主張しており、アジャイルを単に「手法」と呼称していることについて次にように語っている。

 そのため私は、アジャイルが単に「手法」と呼ばれているのを聞くたびに少し 苛立つ。そう、たくさんの手法があるのだ。前述したスクラムやエクストリー ムプログラミング、クリスタルもそうだし、最近開発されたSAFeやLeSSもそ うだ。アジャイルの価値観を実践に移すための青写真を提供してくれる手法は 多い。だが、アジャイルをプロセスやツールとして定義することがなぜ的外れ なのか、それを理解するためにアジャイルソフトウェア開発宣言の 208 文字を そこまで目を凝らして見る必要はない。

1.1 ムーブメントとしてのアジャイルを理解する

ムーブメントとしてのアジャイル

実際に、読んでいくと、この書籍は、アジャイルをつぎの2つに分類している

その上で、それらを連携させる「ムーブメントとしてのアジャイル」を提唱している。手法としてのアジャイルラクティスに重点がおかれており、マインドとしてのアジャイルマインドセットに重点が置かれる。それに対して、ムーブメントとしてのアジャイルとは、マインドセットとプラクティスは容赦なくつなっがっている状態を目指すものである。

ムーブメントとしてのアジャイルでは、アジャイルの原則とプラクティスを明確にし、自分たちにどう適用するかを積極的に決定する、という役割が自身に求められる。言い換えると、他人が決めた価値・原則・プラクティスに従うという受動的な役割ではないことを、この言葉は示している。

そのため、思考と行動の双方に高い基準が求められ、新しい考え方と新しい働き方を必要とする。

脱線 概念が浸透していくプロセス

昨今、「流行っている」DDDなどを見ても同様に、戦術面にフォーカスがあたっている、いわゆるプラクティスに重点が置かれている状態から、(月並みな表現になるが)ビジネスに向けることといったマインドセットに重点が置かれるべきだと主張され、それらは一気通貫してマインドセットとプラクティスがつながるムーブメントとして捉える認識が広がっていく、といったふうな流れがあるように感じる。

なにか概念が広がっていくプロセスというのは、HOW的なプラクティスが注目され、なぜやるのか・その理由はなにかといったWHYに注目するように揺り戻され、最終的にWHY-HOWが一連の思考の枠組として理解される流れを踏んでいくものなのかもしれない。

スクラムやXP、LeSS、SAFeとアジャイル

正直、この辺がそれぞれお互いにどのような輪郭を持って捉えるべきなのか時系列がいまいちわかっていなかったが、歴史的経緯について非常に理解できた。

アジャイルの誕生は、たとえば印象派の芸術運動のように、何人かの実践者が独立しながら同時進行するイノベーションのもとで生まれたものである。書籍内に紹介されている通り、かんたんな年表にすると、次のように整理できる。

f:id:khigashigashi:20200510052247p:plain

自分たちの北極星を見つけること

この表現は、自分が所属企業のチームで実践するに当たり、非常に気に入って使わせていただいている。自分たちの北極星という表現は、この書籍の訳者である ryuzee さんが出演したpodcast fukabori.fm: 32. みんなでアジャイル w/ ryuzeeにて肉声で説明いただいたのが一番分かりやすかったが、自分は、季節が移り変わっても北極星の位置が変わらないように、状況が変わり時間が立っても変わらない自分たちが大事にしたい・目指したい目標と理解した。

言われてみれば言語フレームワーク等の技術選定をする際には至極当たり前の思考プロセスとして、「なにか課題なのか?」・「どのようなソフトウェアを目指したいのか?」という問いが一番最初に来るのに、それがチーム論・組織論では例外なはずがない。

書籍では、自分たちの現状を厳しくみることの重要性や、仕事のやり方をちょっと変える参考の方法にするだけではあまり効果がない、ことについて指摘している。

成功するアジャイルの適用は、常に厳しく正直に現状を見ることから始まる。 何がうまくいっていて、何がうまくいっていないのか。アジャイルを今の仕事 のやり方をちょっと変えるだけのことと思っているなら、アジャイルから得られ るメリットもちょっとだけになるだろう。今のやり方を選んだ元になっている現

2章 自分たちの北極星を見つける

これらについて フレームワークの罠 と表現しているが、それを回避するためには次の2つのステップを経る必要を説いている。

  1. チームや組織がどうなりたいか、そして何がそれを妨げているかを正直に 厳しく見ること
  2. チームや組織が掲げられたゴールにたどり着くために従う必要のあるア ジャイルの原則を選ぶ(必要なら特殊化する)こと

これは、アジャイル云々関係なく、物事全般的に言えることであり、あらゆる場所で思い出していきたい。

脱線:自分たちの北極星はどこだろう

もともと、自分自身この書籍を手にとった理由として、開発チームとしてどこに向かえばより「生き生き」と仕事できるのか、という点について漠然とした課題があった背景がある。 どういう景色かというと、だいたい全体で150人くらいの規模のサービス会社の50人弱のエンジニア組織の中で、他チームからの協力も含めピザを囲んで食べれる規模の小さなチームにいる。

そこでは、良くも悪くも個人技の集積で絶妙なバランスで顧客に対する成果となるサービス・機能を提供・運用できていた。しかし、プロジェクトの関係者の増加・期間の大きいもの、並行で考える開発プロジェクトの増加、マーケティング施策の実現やCustomer Supportからの問い合わせに迅速に対応していくこと、などが求められる中で、個人の力の集積ではなくチームとしてどう成果を出していけるか、を考える必要を感じていた。

「遠くに行くにはみんなでいけ」的な言葉があるが、月並みな表現をすると「俺たち今日もいい仕事ができるな!ちゃんと世界に価値を発揮できてるぞ!」 と言いたいぞっていう具合だった。

どうやっていきたい?っていうの実際にzoomで話したりした結果、この課題感が「アジャイル的な表現」なのかと問われると、正直わからないが、次のようになった。

1. メンバー: 個々人の達成感
2. チーム全体: 関係各所との「約束」を守る

そのために、進行において優先度高く取り組んでいきたいことは以下です。

個々人の納得感と達成感のあるマイルストーン と 重要マイルストーンに対するブレークダウンと見積もりの継続的評価

表現としては、「顧客中心」な表現とは言えないが、サービスを提供する顧客にしっかり価値を提供する、ことに対してブレークダウンしたお気持ちではある(※ 「北極星は変わらない」が、チーム内の宣言文は、より適した形でリライトされ続ける気がする)。

スプリントでの作業

アジャイル手法全体を一つのプラクティスに集約する一つの表現を書籍では、「タイムボックス化したイテレーションで作業すること」と表現していた。「スプリント」という表現がより聞き馴染みがあるかもしれない。

顧客ニーズに基づいて作業に優先順位をつけ一定期間のスプリントを実施する。スプリント後にフィードバックを得て、次のスプリントのて作業に優先順位をつける。短い期間で顧客のフィードバックを受けるフィードバックループを回すことが顧客中心主義となるヒントだ。

ここでいう「顧客」って誰になるんだっけ、を考える

自分はサービス会社にいるので、その文脈での確認になるが、自分自身のいる開発チームの動き方は大きく2種類のことを同時並行で行っている。

  1. 新規機能の開発
  2. 既存機能の改善・保守

「2. 既存機能の改善・保守」については、例えば2weekのsprintで顧客に届ける価値はそのまま本番にリリースして、顧客に使ってもらい、その後の反応をフィードバックとして得られれば次の計画に活かせるのでイメージが付きやすい。

「1. 新規機能の開発」については、2weekにおける顧客フィードバックを得るための顧客は、プロジェクトオーナーということだろうか。実際にプロジェクトオーナーと動くものを持って話すと「この機能はこうしたい」といったフィードバックが得られるので、そういうことなんだよな?

更に具体的なタスクレベルにブレークダウンしたときに、例えば、2weekで「backendのAPIを用意します」・「infra環境を作ります」といった場合は?それについてもプロジェクトオーナーと合意し、その成果について確認・説明すると、プロジェクト状況や「こういうことは対応してますか?」といった会話ができそうか。

実際の組織における課題「組織重力の3つの法則 」

ムーブメントとしてのアジャイルを実践するにしても、現実の組織は、変えることが難しいことがある。「従来の仕事の仕方」に人をつなぎとめておく力は、重力と同じように広範囲に及ぶ。筆者はそれを「組織重力の3つの法則」と呼んでいる。普段漠然と感じて考えていたことが明快な言葉で説明されていて腹落ちの度合いがすごかった。具体的には次の3つをあげている。

● 組織の個人は、日々の責任ややる気を伴わない場合、顧客対応を避ける。 ● 組織の個人は、自分のチームやサイロの居心地のよさのなかでいちばん簡単に完了できる仕事を優先する。 ● 進行中のプロジェクトは、プロジェクトを承認した最上位者の決定がない限り続く。

1章「アジャイル」とは何か?なぜ重要なのか

1. 組織の個人は、日々の責任ややる気を伴わない場合、顧客対応を避ける。

これについては、個人レベルでの組織レベルでも、心当たりがある事象だと感じた。自分のKPIや成果に焦点がいってしまい問い合わせ対応などの顧客対応の優先度が下がってしまう事象は、様々な要因で発生するように見える。

もちろん自身のKPIなるものを「全く達成できませんでした」とは言えないが、一方でサービス会社だと24時間365日サービスは顧客に使われ、そのサービスに何らか不具合や不明点があった場合には、顧客へ価値が届けられず、サービス業態によってはその人の重要な生計の流れが止まってしまう可能性がある。

「日々の責任」・「やる気」というバラメータは、それらの優先度を上げるかどうかについて、大きなバラメータになるし、組織・チームレベルでもそこに対する評価に対して一貫性が取れていない状態が危険っていうのはそうだなと。

サービス会社における「顧客対応」はタイムボックス内の計画でどう扱う?

これって、スプリント計画には当初入ってない "差し込み" タスクになると思うが、これについてどのように扱っていることが多いのだろうか。これを単に "差し込み" として扱って、スプリントレビューで「なんか成果出てなくない?」ってなるのは明らかに「顧客中心主義」の価値観とは違うよね。

これをどう扱うと、顧客対応に対して積極的であり続けて、かつチームとしてもそれを「いいじゃん!かっこいいなお前!価値出したな!」とわいわいできるんだろうか、というところに興味がある。

現時点の扱い方では、顧客対応ができた場合は、その難易度に応じた「ストーリーポイント」をつけて、当該スプリントで実施したissueに追加する、というふうにして、カンバン上で可視化している。

2. 組織の個人は、自分のチームやサイロの居心地のよさのなかでいちばん簡単に完了できる仕事を優先する。

うーあるわ〜(激しく首を縦に振りながら)だった。自分がすぐにイメージしたのは、例えばバックエンド領域のチームが、その他のレイヤ(フロントエンド・インフラ)を扱うために調整が必要なことをさけてむりやりバックエンドのレイヤだけで完結しようとする事象を思い立った(例えば、監視SaaSを使えばより運用上の有益なところに調整を嫌ってバックエンドの実装でそれを代用したり)。

後は、純粋に利害関係者が増えるとそれだけ多種多様な意見が出て、ソフトウェア開発者があんまり好きじゃないような組織間調整的なものが発生したりすると、億劫になってさけちゃいますよね。

後者については組織の文化や目指す先やプロダクトについての共通価値観の情勢などが影響するのだろうけど、前者はこの重量があるからこそ、可能な限り機能横断的である方がいいよな、と思っている。

後記

アジャイルをやろうとしているにしても、やらないにしても、この書籍は非常に一般的な組織的な課題について語っているので、自分の景色を分析するための思考の枠組みとして、いい材料になった。

この書籍を読んだからこそ、「やっぱりチーム課題を考えよう」と重い腰を上げるきっかけになった。なんらか漠然とした課題・もやもや感を感じている状況の方は、『みんなでアジャイル ――変化に対応できる顧客中心組織のつくりかた』、ぜひ手に取ることをおすすめします。

PSR-3とCakePHPから見るNull Object Pattern

TL;DR

背景

CakePHP 4.0 の変更点を追っている際に、次のような記述があった。

Cake\Database\Connection::setLogger() no longer accepts null to disable logging. Instead pass an instance of Psr\Log\NullLogger to disable logging.

https://book.cakephp.org/4/en/appendices/4-0-migration-guide.html

これまで、nullを渡してロギングを無効にする方法をとっていたが、Psr\Log\NullLoggerを渡して無効化するように案内されていた。

NullXxxと見ると、NullObjectパターンが想起されたので、Psr\Log\NullLoggerを入り口として、PSR-3Null Object Pattternの説明を試みる。

PSR

そもそも、PSRとは、PHP Standards Recommendations1の略で、PHP-FIG2というコミュニティ団体による、コミュニティにおいて(ある程度)影響が大きい標準化勧告である。PHP開発に馴染みのある方であれば、普段良く使用しているフレームワークやライブラリが、この勧告によって提示されているInterfaceをサポートしていたりする。AcceptされたものからDraft段階のものを含めてNo.19まで提案されており、冒頭に上げたCakePHPもPSR-15やPSR-16などをサポートしているフレームワークの一つです。

PSR-3 Logger Interface

その中の、No.3であるPSR-33は、すでにAcceptされているPSRで、Logger Interfaceを規定する。つまり、ロガーライブラリの標準となる共通インターフェースを定めようというものになる。

www.php-fig.org

The main goal is to allow libraries to receive a Psr\Log\LoggerInterface object and write logs to it in a simple and universal way.

基本的なインターフェースとして、RFC54254で定義された8つのレベルにログを書き込むためのメソッドを公開する。そして、9つめのメソッドとして、ログレベルを第一引数として受け入れるlogを公開する。

<?php
namespace Psr\Log;

interface LoggerInterface
{
    public function emergency($message, array $context = array());
    public function alert($message, array $context = array());
    public function critical($message, array $context = array());
    public function error($message, array $context = array());
    public function warning($message, array $context = array());
    public function notice($message, array $context = array());
    public function info($message, array $context = array());
    public function debug($message, array $context = array());
    /**
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, $message, array $context = array());
}

https://github.com/php-fig/log/blob/4aa23b5e211a712047847857e5a3c330a263feea/Psr/Log/LoggerInterface.php#L3

logメソッドのPHPDoc5を見ると明らかですが、ログレベルがRFC5425[^4]で規定されたレベル以外の場合は、\Psr\Log\InvalidArgumentExceptionを返すことが指定されている。

Psr\Log\NullLogger

この、PSR-3[^3]のLogger Interfaceの「1.4 Helper classes and interfaces[^5]」にて、Psr\Log\NullLoggerがInterfaceと一緒に提供されている点について説明されている。

The Psr\Log\NullLogger is provided together with the interface. It MAY be used by users of the interface to provide a fall-back “black hole” implementation if no logger is given to them. However, conditional logging may be a better approach if context data creation is expensive.

フォールバックの実装を提供するために使用することができるblack hole実装となっています。

<?php

namespace Psr\Log;

/**
 * This Logger can be used to avoid conditional log calls.
 *
 * Logging should always be optional, and if no logger is provided to your
 * library creating a NullLogger instance to have something to throw logs at
 * is a good way to avoid littering your code with `if ($this->logger) { }`
 * blocks.
 */
class NullLogger extends AbstractLogger
{
    /**
     * Logs with an arbitrary level.
     *
     * @param mixed  $level
     * @param string $message
     * @param array  $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, $message, array $context = array())
    {
        // noop
    }
}

github.com

継承しているPsr\Log\AbstractLoggerにて、8つのログレベルの公開メソッドが実装されているため、LoggerInterfaceを満たすものとなっています。

フレームワークにおける使用例

このPsr\Log\NullLoggerの使用例をCakePHPの内部実装で見てみます。PSR-3の\Psr\Log\LoggerInterfaceへの依存へ変更しているPRから、見ていきます。

-    public function setLogger(?QueryLogger $logger)
+    public function setLogger(LoggerInterface $logger)

github.com

CakePHP3.x以前では、ロギングを無効にするために、Cake\Database\Connection::setLogger()nullを渡す方法をとっていました。

        $connection = ConnectionManager::get('test');
        $connection->setLogger(null); // 無効

この場合、以降ロガーを呼び出す際に、if ($this->_logger === null)といった条件分岐などを使用してチェックするようなコードを用意することになります。

それに対して、NullLoggerを利用する場合は、そのようなチェックをせずとも、同一のインターフェースを利用することができます。

        $connection = ConnectionManager::get('test');
        $connection->setLogger(new NullLogger()); // 無効

このようなメリットを享受できるコード設計パターンは、Null Object Patternというパターンの特徴として見ることができます。

Null Object Pattern

Null Object Pattern6とは、オブジェクト指向言語おけるパターンで、参照される値がないか、定義されたニュートラル(null)動作を持つオブジェクトを指します。「プログラムデザインのためのパターン言語―Pattern Languages of Program Design選集7」や、「リファクタリング 既存のコードを安全に改善する(第2版)8」にて、本として初めて紹介されたパターンとなります。(※ 「リファクタリング 既存のコードを安全に改善する(第2版)[^8]」では、Special Case Patternとも表現されています。)

これは、GoF (Gang of Four)の23個のデザイン・パターンではありませんが、現代のプログラミングの現場において広く知られる「デザイン・パターン」といえます。

先程のCakePHPの例では、次のようなクラス関係を表現しています。

f:id:khigashigashi:20200102191704p:plain

デザイン・パターンは、オブジェクト指向ソフトウェアを設計する際の経験を記録、カタログ化したものです。繰り返し現れる構造をパターンとしてまとめたものです。「問題」・「解決」・「コンテクスト」の大きく3つの要素をそのパターンから見出すことができます。

まとめ

PSR-3の標準的なインターフェースとともに提供されているクラスから、NullObjectというパターンを紹介しました。


  1. PHP Standards Recommendations (https://www.php-fig.org/psr/)

  2. PHP-FIG (https://www.php-fig.org/)

  3. PSR-3 (https://www.php-fig.org/psr/psr-3/)

  4. RFC5425 (https://tools.ietf.org/html/rfc5424)

  5. phpDocumentor (https://www.phpdoc.org/)

  6. Null Object Pattern (https://en.m.wikipedia.org/wiki/Null_object_pattern)

  7. プログラムデザインのためのパターン言語―Pattern Languages of Program Design選集 (https://www.amazon.co.jp/dp/4797314397)

  8. リファクタリング 既存のコードを安全に改善する(第2版) (https://www.amazon.co.jp/dp/B0827R4BDW)

年末にちょうどいい「やり抜く人の9つの習慣」と「やる気が上がる8つのスイッチ」

TL;DR

  • 「やり抜く人の9つの習慣 コロンビア大学の成功の科学」を読んで、目標設定を冷静に振り返ると、継続性のある目標になりそう
  • 「やる気が上がる8つのスイッチ」を読むと、自分自身のやる気のタイプや他の人のやる気のタイプを冷静に分析することができそう
  • 「やり抜く人の9つの習慣 コロンビア大学の成功の科学」・「やる気が上がる8つのスイッチ」と2冊で、1時間足らずで読める

読むきっかけ

風呂で YouTube をダラダラと眺めていた際に、ふと目に入ったメンタリスト Daigo の 「12/31に読むと人生変わる本【1時間で読める】1」という動画をさくっと見た。

1時間かからずに読めそうという点で読んでみたのがこちらの二冊でした。

  • ‪ハイディ・グラント・ハルバーソン の やり抜く人の9つの習慣 コロンビア大学の成功の科学2
  • ‪ハイディ・グラント・ハルバーソン の やる気が上がる8つのスイッチ3

この2冊が紹介されているのは、目標達成のために継続する方法・やる気を出すきっかけを得る方法を、セットで得るため、と動画内では紹介されていました。

が、実際に自分が興味を持ったのは、次の2点においてでした。

  1. やる気から見た8つのタイプ
  2. 自身の目標設定の再評価

1. やる気から見た8つのタイプ

「ハイディ・グラント・ハルバーソン の やる気が上がる8つのスイッチ[^3]」で説明されている、やる気から見た8つのタイプでした。目の前にいる人がどういうモチベーションで日々取り組んでいて、何に喜びを感じるのか?という点について考えることが多いのですが、その考えるフレームとしてこのタイプは非常に良い枠組みになりそうです。

2. 自身の目標設定の再評価

また、「2020年を実践知識をより多く獲得し体系化する一年へ4」にて行った、自身の2020年の目標設定が、これらの心理学的な観点において、有効たりうるかを再評価したいという思惑があります。

2020年を実践知識をより多く獲得し体系化する一年へ - Software engineering from east direction

この2つの観点でこの書籍を振り返ります。

1冊目「やり抜く人の9つの習慣 コロンビア大学の成功の科学」

「ハイディ・グラント・ハルバーソン の やり抜く人の9つの習慣 コロンビア大学の成功の科学[^2]」には、目標の設定の具体性などさまざま継続してやり続けるための方法が書いてありますが、一部「なるほど」と思った点だけ。

if-thenプランニング

目標達成のためにやるべき行動を明確にするための一つのアイデアです。日々追われていると、やるべきことが多すぎて、何から手を付けていいかわからない、そのようなときがあります。このような自体に対処するために、心理学で効果実証された方法が、if-thenプランニングと呼ばれる方法です。

つまり、(if)もし、Xだったら、(then)Yをするという形式で習慣づけたい行動を明文化するアイデアです。

例えば、「もし、午後6時になったら、会社のジムで汗を流す」といった風に。この方法が習慣化しやすい理由として、脳の構造上、「XならY」という文章を記憶しやすい特徴があると本書では説明しています。

私自身、この書籍をうけて、「2020年を実践知識をより多く獲得し体系化する一年へ[^4]」にて、「なにか焦りを感じるときがあれば、すっと深呼吸」という表現で、外部環境に左右されない精神性を保とうと考えたのですが、if-thenプランニングの形式で、「もし、心に焦り・もやもやを感じたら、1回深呼吸する」という風に変えました。

「これまで思考」と「これから思考」

これは、シカゴ大学の心理学者ミンジョン・クーとアエレット・フィッシュバックの研究によって整理された、目標に対する2つの視点です。

「これまで思考」とは、「どこまでやり遂げたのか」に視点を向ける思考スタイルで、「これから思考」とは、「あとどれだけやらなければいけないのか」に視点を向ける思考スタイルです。

実験の結果、「これまで思考」の強い人は、早い段階で達成感を持つために、早く気が緩んでしまうという結果が出ているそうです。

そのため、「これから思考」を重視して、目標までの距離を図ることが、モチベーション維持における重要な点と言えそうです。

2冊目「やる気が上がる8つのスイッチ」

「ハイディ・グラント・ハルバーソン の やる気が上がる8つのスイッチ[^3]」は、いかにして自分あるいは他人のモチベーションのスイッチを入れるかという点について説明しています。この書籍では、画一した一つの方法だけを示しているわけではないことが特徴です。つまり、体調不良をお医者さんが診断するときに多種多様なタイプに応じて必要な処方箋が違うのと同様に、「やる気」という点においてもそれぞれのタイプに応じて必要なアプローチが違うという点を強調しています。

証明マインドセットと成長マインドセット

まず、その人がどのようなマインドセットを持っているかについて、2つのマインドセットを紹介しています。

証明マインドセットを持つ人は、自分の能力の証明に焦点を当て、エネルギーを注いでいます。つまり、人に自分の能力を見せつけ認めさせようとしているタイプです。そのため、意識的/無意識的に他人と自分を比べます。そして、ミスをすることをいつも恐れ、自分にはできない/無理だということが人にも自分にもわかってしまいことを怖がります。

端的な表現を使うと、「すごい人と思われたい」人と言えます。一方で、成長マインドセットは、「すごい人になりたい」人です。

成長マインドセットを持つ人は、他人の目をあまり気にせず、他人が自分をたとえ認めてくれなくても、やると思ったことをやる人です。困難に直面したときも粘り強く頑張り続けるという特徴があり、有利に働きやすいのは「成長マインドセット」です。

私達が固定的にどちらにマインドセットを持つというわけではないようですが、私自身、「証明マインドセットが顔を出していたな?」と反省することが度々あるなと気づくことがあります。きっと、人間だから他の方もそういうときが思い当たるのではないかなぁとおもうのですが、注意が必要ですね。

獲得フォーカスと回避フォーカス

たとえ同じ目標に向かっていても、そのアプローチは人によって違います。それはどこに焦点を当てるかによって変わりそうですが、それが「獲得フォーカス」・「回避フォーカス」という整理です。

  1. 獲得フォーカス(Promotion Focus)
    • 高いレベルの仕事: 獲得であり達成
    • 動機づけ: 称賛を得る
  2. 回避フォーカス(Prevention Focus)
    • 高いレベルの仕事: 安定感であり信頼性
    • 動機づけ: 批判を避ける

これらはどちらが良いというよりかは特徴としてどちらよりかという風に人を見ると面白いかもしれません。

多くのことに手を出しがちなのが獲得フォーカスなのに対し、回避フォーカスはやり始めたことは最後までやろうとします。途中でやめたり、考えを変えたりするのが苦手なのです。獲得フォーカスの人が仕事を先延ばしにしがちなのに対して、回避フォーカスの人は最初から時間を多めに見積もり、期限までに仕事を完了できるようにします。

ハイディ・グラント・ハルバーソン. やる気が上がる8つのスイッチ (Japanese Edition) (Kindle Locations 222-225). Kindle Edition.

8つのタイプ

これまで上げた「マインドセット」・「フォーカス」に「自身の有無」を加えた3つの軸で、8つのタイプが現れるようです。

  1. 中二病
  2. うざいやつ
  3. 臆病者
  4. 退屈な人
  5. やる気の空回り
  6. まじめな見習い
  7. 新星
  8. 熟練の匠

書籍では、これらのタイプ別に治療法を提示していますが、「7. 新星」・「8. 熟練の匠」が目指すべき境地と解説しています。

たとえば、新星は、

というタイプで、個人が持っている能力を存分に発揮しているよいレベルだとしています。

また、熟練の匠は、

というタイプで、目立たなくてもしっかりとその場を支えてくれる人たちです。

この整理がいいなと思うことは、この整理によって、タイプが違う人に対してその能力の発揮を認識しやすくなる点です。正直なことを言うと、自分が「獲得フォーカス」が強い人間だと自己認識している分、「回避フォーカス」が強い方の思考やモチベーションを理解しづらい側面があります。しかし、この整理によって、「その人は回避フォーカスで成果を上げている熟練の匠タイプなんだ」と納得できれば、タイプが違っても理解できる。非常にいいアイデアだなと感じました。

まとめ

以下の2冊を読み始めて、2冊で1時間足らずで読めたので、年末最後に一冊という方には、ちょうどいい分量なのではという感じでした。

  • ‪ハイディ・グラント・ハルバーソン の やり抜く人の9つの習慣 コロンビア大学の成功の科学[^2]
  • ‪ハイディ・グラント・ハルバーソン の やる気が上がる8つのスイッチ[^3]

また、この書籍から多くの参考文献のリンクが貼られているので、人間観察の材料としての心理学の入り口としてもちょうどいいと思います。