よこなのへたのよこずき

noteもよろしくね

Javaのレコード(Records)は入れ子にして便利に使える #javajo #java14

結論

タイトル通り。

前置き

先日Java女子部でこんなイベントを行いました。
javajo.doorkeeper.jp

型の基本から最新情報まで学べる豪華な会で、知らないことも多くとても面白かったです。
他の多くの参加者にとっても同様だったようで、満足度の高いイベントになりました。西川さんありがとうございました!

さて、Java 14からプレビュー機能として「レコード」が追加されました*1

特徴の一部を西川さんの資料から拝借しました:

  • イミュータブルである
  • recordは暗黙のうちにfinalである
  • recordクラスのメンバー変数はfinalである
  • 値がすべて同じならequals()ではtrueを返さなくてはならない

Java女子部のイベントではサンプル付きでレコードについて学んだのですが、
フィールドがint型やString型だけだったので、 「レコードは入れ子にできる?したらどうなる?」という疑問が湧きまして。実際使うときって入れ子にしたいし。
ということで、それを動かして調べてみるのが私の宿題となったのでした。

ソースコード付き実験と解説

レコードを定義してみる

大好きな「あつまれどうぶつの森」風サンプルにしました。実際のあつ森はこの何億倍も複雑ですが。

  • 名前と色の情報を持った家具がある
  • 家具はリメイクすることで色を変えられる
  • 家具は複数個ポケットにしまうことができる

を満たすクラスたちをレコードとして作ってみます (サンプルにおいて package とか import は省略してます)。

クラス名の後にコンストラクタ風にメンバー変数を渡すと便利なメソッドやらが色々生成されます(後述)。
Scalacase class みたい。

/**
 * 家具の名前
 */
public record FurnitureName(String value) {}
/**
 * 家具の色
 */
public enum FurnitureColor {
    RED,
    BLUE,
    YELLOW,
}
/**
 * 家具
 */
public record Furniture(FurnitureName name,
                        FurnitureColor color
) {
    // 2021.09 追記: レコードには自動でgetterが生えるので本当はこのメソッド要らないですね…
    // しかし、これがある状態で後述の検証をしちゃったので残しておきます。
    public FurnitureName name() {
        return name;
    }
}
/**
 * 家具を入れるポケット
 * 入れる位置がkey, 中身がvalue
 */
public record Pocket(Map<Integer, Furniture> furniture) {}

FurniturePocketコンパイルされた後どんなメンバーを持つか見てみます。

$ javap -p Pocket.class
Compiled from "Pocket.java"
public final class com.example.animal_crossing.main_character.Pocket extends java.lang.Record {
  private final java.util.Map<java.lang.Integer, com.example.animal_crossing.item.Furniture> furniture;
  public com.example.animal_crossing.main_character.Pocket(java.util.Map<java.lang.Integer, com.example.animal_crossing.item.Furniture>);
  public java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public java.util.Map<java.lang.Integer, com.example.animal_crossing.item.Furniture> furniture();
}
$ javap -p Furniture.class
Compiled from "Furniture.java"
public final class com.example.animal_crossing.item.Furniture extends java.lang.Record {
  private final com.example.animal_crossing.item.FurnitureName name;
  private final com.example.animal_crossing.item.FurnitureColor color;
  public com.example.animal_crossing.item.Furniture(com.example.animal_crossing.item.FurnitureName, com.example.animal_crossing.item.FurnitureColor);
  public com.example.animal_crossing.item.FurnitureName name();
  public java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public com.example.animal_crossing.item.FurnitureColor color();
}

javapコマンドに詳しくなくてもかんたん!以下のことが分かりますね。

  • record で宣言をすると Record クラスを継承したクラスとなる
  • レコードクラス自体は final となる
  • レコードクラスのメンバー変数は private final となる (ので、setterは生成されない)
  • toString(), hashCode(), equals(), getter, コンストラクタが自動で生成される

レコードにふるまいを持たせてみる

さてここで「ポケットから家具をひとつ取り出してリメイクしてまたポケットにしまう」というコードを実行できるようにレコードを拡張してみます。 レコードはイミュータブルなので Furniture インスタンスを直接書き換えることはできません。
ということで、 PocketFurniture にリメイクに必要なメソッドを生やしてみました。
慣れないJavaですが、Stream API使いに改善の余地があったら教えて下さい

/**
 * 家具
 */
public record Furniture(FurnitureName name,
                        FurnitureColor color
) {

    /**
     * 家具の色を指定したものに変える(リメイクする)
     *
     * @param newColor リメイク後の色
     * @return 色の変わった新しい家具
     */
    public Furniture remake(FurnitureColor newColor) {
        return new Furniture(name,
                newColor);
    }
}
/**
 * 家具を入れるポケット
 * 入れる位置がkey, 中身がvalue
 */
public record Pocket(Map<Integer, Furniture> furniture) {

    /**
     * 指定した位置の家具を取り出す
     *
     * @param position 取り出す位置
     * @return 取り出した家具
     */
    // 余談なんですが、最初はOptional<Furniture>を返すようにしてたものの
    // 呼び出し元がmapやflatMap祭りになって見辛くなったので今回は強気のgetにしました
    public Furniture takeOut(int position) {
        return furniture.get(position);
    }

    /**
     * 指定した位置の家具を、別の家具と入れ替える
     *
     * @param position 入れ替える位置
     * @param newFurniture 入れ替え後、ポケットの指定した位置に入る家具
     * @return 入れ替え後の家具が入った新しいポケット
     */
    // これもうちょっとスマートに書けるのかな?
    public Pocket replace(int position, Furniture newFurniture) {
        Map<Integer, Furniture> replaced =
                furniture.entrySet().stream()
                        .map(e -> {
                            if (e.getKey() == position) {
                                return Map.entry(position, newFurniture);
                            } else {
                                return e;
                            }
                        })
                        .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
        return new Pocket(replaced);
    }
}

レコードの特徴を確認してみる

Java女子部と同じように equals() メソッドの挙動を見て、値が同じであればtrueを返すのを確認することにしました。
次のようなコードを -enableassertions オプション付きで実行してみます。

Furniture cuteTable = new Furniture(new FurnitureName("かわいいテーブル"), FurnitureColor.RED);
Furniture coolChair = new Furniture(new FurnitureName("かっこいい椅子"), FurnitureColor.BLUE);

// かわいいテーブル(赤)・かっこいい椅子(青)が1つずつ入ったポケットをつくる
Pocket myPocket = new Pocket(Map.of(0, cuteTable, 1, coolChair));

// かわいいテーブルを青にリメイクする
Pocket onceRemadePocket = myPocket.replace(0, myPocket.takeOut(0).remake(FurnitureColor.BLUE));

// かわいいテーブルを再び赤にリメイクする
Pocket remadeAgainPocket = myPocket.replace(0, myPocket.takeOut(0).remake(FurnitureColor.RED));

// 1回目のリメイクでPocketインスタンスが作り直される
assert myPocket != onceRemadePocket;

// 1回目のリメイクでPocketの中身が始めと異なる
assert !myPocket.equals(onceRemadePocket);

// 2回目のリメイクでPocketインスタンスが作り直される
assert onceRemadePocket != remadeAgainPocket;

// 2回目のリメイクでPocketの中身が始めと同じと判定される
assert myPocket.equals(remadeAgainPocket);

System.out.println("問題なくここまでくればOK");

実行結果は次のようになったので、想定通り!

問題なくここまでくればOK

今回はここまで。

余談

javap -p -c -v xxx.classの結果を見て、 equalsメソッドの生成についてもうちょっと細かいところも見てみたんですが
それも記事に入れようとすると公開まで時間がかかりそうなので諦めました。へへへ

このへんにたどり着いた↓ jdk/ObjectMethods.java at 827e5e32264666639d36990edd5e7d0b7e7c78a9 · openjdk/jdk · GitHub

パッと思いつく下手な英文和訳パターン5選

f:id:ihcomega:20200604213016j:plain

前回に引き続き、英語の小ネタです。英語を日本語にするときの「あるある」を思いつくがままに書いてみます。(あくまで私の感覚でより良い訳し方をオススメしている記事にはなりますが)気をつけよう!
なお、例文は不自然じゃない程度になるべく直訳しています。

要らない主語は省こう

  • (例) Before we talk about this issue, let's take a look at the handout.
    • △ 私達がその問題について話す前に、(お手元の)印刷物をご覧ください。
    • ○ その問題について話す前に、(お手元の)印刷物をご覧ください。
  • (例) This tool changes the way you manage bugs.
    • △ このツールで、あなたがバグを管理する方法が変わりますよ。
    • ○ このツールで、バグを管理する方法が変わりますよ。

英語は日本語に比べると主語を明示しがちですが、それを忠実に翻訳する必要はありません。特に、一般論を語るときや大衆を相手にしたときの weyou は典型的な省略対象かなと思います*1

要らない指示語は省こう

  • (例) There is a sweet apple on the desk. You can take it.
    • △ 机の上に甘いりんごがあります。それを持っていっていいですよ。
    • ○ 机の上に甘いりんごがあります。持っていっていいですよ。
  • (例) He was angry. This is because his brother ate all cookies.
    • △ 彼は怒りました。それは何故なら兄(弟)がクッキーを全部食べてしまったからです。
    • ○ 彼は怒りました。何故なら兄(弟)がクッキーを全部食べてしまったからです。

主語の省略に似た話ですが、要らない目的語は割愛しましょう (ひとつめの例)。
また、This is why ~, It is interesting to do ~みたいに訳す必要のない itthisthatなどを使った慣用表現がたくさんあるのでそれも注意しましょう (ふたつめの例)。

関係詞や修飾語で長くなった文・語は区切ろう

  • (例) Spring Batch provides reusable functions that are essential in processing large volumes of records, including logging/tracing, transaction management, job processing statistics, job restart, skip, and resource management.
    • △ Spring Batchは、ロギング・トレーシング、トランザクション管理、ジョブ処理の統計、ジョブの再実行やスキップ、そしてリソース管理などをふくむ大量のレコードを処理するのに不可欠な機能を再利用可能なものとして提供します。
    • ○ Spring Batchは大量のレコードを処理するのに不可欠な機能を再利用可能なものとして提供します。たとえば、ロギング・トレーシング、トランザクション管理、ジョブ処理の統計、ジョブの再実行やスキップ、そしてリソース管理などです。
    • ○ Spring Batchはロギング・トレーシング、トランザクション管理、ジョブ処理の統計、ジョブの再実行やスキップ、そしてリソース管理などの再利用可能な機能を提供します。これらは大量のレコードを処理するには不可欠です。

うーん、めっちゃあるあるなのにいい例が浮かばないよ〜。ひとまず一例をSpring frameworkのドキュメントから拝借しました (リンク)。
しかもこのくらいの長さなら一文でもそんなに問題はないですね。要は原文の文の数に引きずられる必要はないということです!途中で文を区切るのも翻訳者の自由なので、長すぎる名詞や文をそのまま訳す必要はありません。
英語は言葉の前にも後ろにも修飾語をいっぱい付けられるので、気をつけないと主語と述語が行方不明になりそうな長文が爆誕します。

和製英語は程々にしよう

  • (例) Checking emails is my daily routine.
    • △ メールチェックは私のデイリールーティーンです。
    • ○ メールチェックは私の日課です。

上の例文はまだ可愛らしいものですが、カタカナが大量に並んで理解しづらい文をしばしば見かけます。エンジニアは英語圏から来た言葉をそのまま使うことも多いので、技術的な文章ではなおさらありがちですね。
どうしてもカタカナにしかならないものは仕方ないですが、例えばinternationalとかglobalみたいな(似たような例しか浮かばなかった…)カタカナでも漢字でも表現できる言葉はどちらがいいか選ぶ習慣をつけたいものです。

呼びかけや問いかけは日本人が言いそうか考えてみよう

  • (例) Do you need more information?
    • △ もっと情報が欲しいですか?
    • ○ より多くの情報はこちらに掲載しています。
  • (例) Wanna watch the video?
    • △ ビデオが観たいですか?
    • ○ ビデオもご覧いただけます。

プロモーションやキャンペーンなどでよく見かけるのですが、相手を誘うような文言を正直に訳すと「失礼な!」「急に馴れ馴れしいぞ」といった印象を与える文になることがあります。
相手が日本人だったら、なるべく日本流のお誘いをしましょう。

終わりでーす。また思いついたら書きまーす😺

*1:逆に、和文英訳において文脈から判断した主語を補うのは難しさのひとつみたいですね。Twitterで翻訳をしてくれるGoogle translateくんなんかもしょっちゅう間違えてます。私自身について書いたツイートなんだけどHeって書かれていることがしばしば…

英語で「彼らはスマホを持っています」と言うとき、スマホは単数形でも複数形でもOK

って皆さん当たり前に知ってましたか…?知ってた方はもうこの記事を閉じてください(;▽;)
自分はというと単数の方が文法的に正しいと思っていたんですが、違ったようです。
どちらか一方が正解だったら記事にし甲斐があったのに、どっちでもいいなんて…。

具体例とともに説明すると、人が複数人いて各々がスマホを持ってるとき

They have a smartphone.

とも

They have smartphones.

とも表すことができるというわけです。

複数のスマホを「配分」すると捉えるか、複数のスマホの「集合」で捉えるかが異なるものの、いずれも同じことを表現できるみたいです。
この「配分」「集合」っていうのが文法的にキーワードだと初めて知りました。「配分単数」とかでググると色々ヒットします。

なお、この違いについてネイティブの方に聞いてみたところ、単数か複数かはどっちでもいいけど、意味がちょっと曖昧になるとのことでした。
どう曖昧かを図示してみると次のようになります。

f:id:ihcomega:20200528002320j:plain
表現の曖昧さ。結局スマホはいくつあるんだ?

ちなみに、『ロイヤル英文法』には「各々」という意味を出したいなら単数にすればOKとも記載がありました。
ただ、分かりやすさを重視するなら

Each of them has a smartphone.

とか

They are sharing a smartphone.

といった表現が良さそうですねー!


参考文献

綿貫陽『ロイヤル英文法改訂新版』(2000) p.726-727

コミュニケーションの方向に着目したふりかえりの方法

前職FOLIOではめっちゃいろんな経験をしたので、今更ながら少しずつブログに出してみることにしました。


はじめに

今回のテーマはチームの「ふりかえり」です。レトロスペクティブとか言ったりもするアレ、KPTとかやるアレです。
多くのチームと同じように、私の所属する開発チームも定期的なふりかえりを行っていました。会の構成を決めファシリテーションをするのは私です。

ふりかえりを進めるのは結構難しく苦戦しましたが、「これで上手くいってるのかな?」「どうしたらもっと良いふりかえりができるかな?」と考えながら色々試していくと、解決したい課題や改善点が段々と見つかってきました。そんな中、行き着いた*1方法があるので紹介します。

ふりかえりのやり方

道具はありきたりで、ホワイトボードとふせん(色の区別はしないので1色で十分。カラフルでも別にOK)です。
まずはホワイトボードを縦に1本区切り、左は「ポジティブなこと」右は「ネガティブなこと」のエリアとします。さらに、ポジティブエリアを3つ、ネガティブエリアを2つに分けます。

ふりかえりで書き出すものと配置

そして、各エリアに該当の付箋を貼り出し、皆で時計回りに見ていくというものです。

なぜこの方法を取ったか・解決したかった課題

課題に対するアクションの議論で時間足りない問題

過去にふりかえりの時間が足りなくなることがよくあったので、改善のひとつ*2として「議論しなくていいものは議論しない」仕組みを取り入れようとしました。
上下に分かれているネガティブエリアは、簡単に言うと要議論なもの(下)とそうでないもの(上)です。上半分はとにかく自分の中から外へ「出す」ことを重視して読み上げつつおしゃべりするだけとし、下半分はチームで受け止め時間をかけて話し合います。

この分類を思いついたきっかけは、たまたま目にしたばふぁ(@bufferings)さんのツイートでした。

「Keepしたいわけじゃないけど良いなと思ったこと」と「解決したいわけじゃないけど何か嫌だったなーと思ったこと」もあるよねーって。

「確かに今まで、ネガティブな内容というだけで、アクションを取らなくていいことにも検討の時間を割いていたかも?それって本当に必要?」とすごくハッとしたのを覚えています。

チームの頑張りに目を向けて欲しい気持ち

当時のチームは、新しいプロダクトをどんどん出すような作業より、地道で人目に触れない改善、歴史あるマイクロサービスのリファクタリング、金融業界特有の法的要件とじっくり向き合う静かだが激しい戦いなどが多いという特徴がありました*3
ただメンバーはハンパなく優秀で努力家で真面目で、すごすぎてすごかったので(語彙消失)、プロダクトという形とは違うところでも、チームの良いところをいっぱい見つけてワクワクして欲しい思いがありました。しかし、日々作業に没頭していると、そんなことを気にかける余裕がなくなったりもします。

そこで、「誰に対する」ポジティブな気持ちかを軸に、3象限に分けて丁寧に見直す習慣を作りました。

  • チーム(または個人) で続けたいこと
  • 自分 がドヤりたいこと
  • チームメンバー にお礼したいこと

軸について補足すると、漠然と「いいことを挙げてください」と言われたとき、チームの変化に気付くのか個の良さに目が行くのか、他人を褒めるのか自分の成果を堂々と表現できるのか、その結果にはかなり個人差があると感じます。それをふまえて、誰もが、チームも個も、他者も自分も見つめてみてほしいなと考えての工夫でした。
なお、いずれも議論が必要なことは少なく、簡単な読み上げとともに、皆で喜びの共有や拍手をしながら全部見ていって終わりです。

実際のホワイトボード

5象限の意味

それぞれの解説でも書きましたが、分かれた5つはどれもコミュニケーションの方向が異なると言えるのではないかと自分なりの整理をつけています。もちろん超正確に分類できるわけではないので話半分というか、なんとなくこんな気がするというだけですが😏

おわりに

ふりかえりはチームの数だけやり方や特徴がありそうですが、そうしたスタイルが確立された後も、マンネリ化させずに「今のベストなふりかえり」ができているか考え続ける必要があるなと思います。って、何事もそうですよね。ミーティングの場だけ設定してノー準備で「先週と同じ!」というのはなるべく避けたいですね。

参考にした書籍

ばふぁさんのツイートのみならず、大好きな『アジャイルレトロスペクティブズ』も大いに活用しました。いつもアイディア出しを助けてくれる素敵本です*4

今回書いたアクティビティは本にある「喜、怒、哀 (Mad Sad Glad)」をかなり参考にしています。
あと、紹介は割愛したんですが、「満足ヒストグラム」を参考にしたアクティビティも毎回やっていました。

手法の名前(どうでもいい余談)

先日、以前このふりかえりを一緒にやっていた奥田ニキ(@yoskhdia)から「あのふりかえり、名前ある?」と連絡もらったんですが、特に考えていなかったのでそう伝えたところ…

こうなりました。

('_')!?

*1:ゴールがあるわけではないのでもちろんいつまでも改善し続けるべきですが、数ヶ月はこのやり方で安定していました

*2:他に思いつくのはファシリテーションの質を上げる、開催時間を伸ばす、などですね

*3:こういう特徴がないチームでも同じやり方で問題ないと考えていますが、こうした特性はかなり気にしていました

*4:過去にこんな記事: 『アジャイルレトロスペクティブズ』を読み、ふりかえりで「KPT」以外の技を繰り出そう - よこなのへたのよこずきも書いています

1on1は必ず議事録を残す(ときどき公開だってする)

これはFOLIO Advent Calendar 2019 16日目の記事です。
昨日は@grimroseさんのScala.jsとcatsとその仲間たち - Qiitaでした!


昨年の秋から、リーダーとして採用とかチームの健康診断(?)とかをやっています。
難しいしなかなか上手くいきませんが、自分よりずっとベテランなメンバーの皆にアドバイスや見守りをいただきつつ1年生を終えました。

書籍や先人のブログ、周りからの声なんかを参考に見よう見まねでやってきましたが、何をするにも意識していたのは「前回との繋がり」がなくならないようにすることです。
ふりかえりや月次報告会のように、数週間に1度行うようなアクティビティはどうしても前回の記憶が薄れがちです。それでも、毎度新しい気持ちで望むのでなく、あくまで連続したイベントの中の1回と意識することで

  • よいことや成長の積み重ね
  • 課題やもやもやの経過観察

を大事にしてきました。

些細で当然のことなようですが、忙殺されると後手になったりもするので、小さなことでも1年続けられてよかったかなという感想を抱いています。
さて、このエントリでは、中でも工夫した1on1についてちょっとだけ詳しく書いてみます。

やったこと

  • メンバーごとに議事録をとり、いつでも過去を引き出せるようにした
  • 1on1前に前回分を見て、引き続き取り扱った方がよさそうな話題があるかチェックしてから望んだ

(便宜上、リーダーやエンジニアリングマネージャーががやる方を1on1のホスト、メンバーを1on1のゲストと呼びます。一般的な呼称があったら教えてください)
ゲスト専門だった頃は共有ドキュメントとしてオンラインに1on1の議事録がある状態を体験したことがなかったし、自分にとってはそれを残すこと自体が新しい試みでした。
過去の経験から、自分でメモを取ると「雑すぎて見返してもよく分からん」「そもそも話すのに夢中で何もメモできなかった!」なんてことになりがちだったので、はじめから「ホストが記録を残すよ」という体にすることで、ゲストには話すことに集中してもらいつつそこそこ意味の分かる記録を残すことができたように思います。

1on1はフォーマットを大体決めていたのですが、その中に「前回との差分」という項目も入れていました。
ちょっとだけ準備に時間はかかりますが、必ず前の議事録を見返してから1on1に望むことで、「この前より状況よくなったね」「多分これ未だに解決してないよね、すまん」と経過観察を行っていました。

副次的な効果

「前回の繋がり」のみならず、1on1の記録は他にも役立ちました。

ホストとゲストで認識の齟齬が減る

ゲストが話したことをホストが書き起こすことで、ホストの理解がゲストの思いから乖離していないかを確認することができました。
実際、「これはどちらかというと○○という意味です」「さっきはそう言ったけどやっぱりこうでした」みたいな、訂正のコメントを貰うこともあって助かりました。

希望に応じホストとゲスト以外にも公開し、便利に用いることができる

せっかくドキュメントができるということで、希望者の分だけ、希望する範囲で公開もしていました。
もちろん完全自由にしたので、人によって毎度全社に公開したり、同じ職能の人にだけ見せたり、基本は非公開でときどきチームに公開したり、様々です。
公開された分は、チームメンバーが閲覧して共感コメントを残したり、他チームのリーダーとか経営メンバーが見て状況を把握したりするのに使われています。
個人的には、私だけで解決できない課題の相談相手と目線を合わせたり、リーダーの引き継ぎをしたりする際に役立ちました。

↓議事録を公開してみようと決めたとき社内wikiに書いたもの。1番思想がまとまっているので貼っておきます。おとうふっていうのは我がチームのことです📛

1on1の運用について思いを語ったポエム

1on1って、やってみるまでは「何かいいことを言わないといけないんじゃないか」「相談されたらスマートに解決しないといけないんじゃないか」ととても緊張していたのですが、回数重ねるにつれ、とにかく相手に喋ってもらって、後からアクションへ移せたらいいかなと考えるようになりました。
それ以降は気持ちとしても楽になり、純粋に尊い時間として1on1を迎えられています。 まぁ、後からでも、聞いたことを日々の行動や意思決定に反映させるのはとっても難しいのですが…。


よく聞く「メンバーが気持ちや意見を話してくれるのはありがたい」っていうのはリーダーのポジショントークやろって思ってたんですが笑、本当にありがたいことなんだと心から思った2019年…

勘違いしちゃいけないのは、リーダーのため(だけ)の1on1じゃないので、私が満足するだけじゃ意味ないんですけどね!
引き続き精進!!


明日は@krrrr38さんです!

『いちばんやさしいGit&GitHubの教本』執筆開始から終了までのできごと

共著で出させていただいたいちばんやさしいGit&GitHubの教本 人気講師が教えるバージョン管理&共有入門 (「いちばんやさしい教本」シリーズ)について、「執筆作業」って実際のところどんな感じなの?といった内容を、実体験とともに記録します。

昨年の終わりに書いた、執筆を進めるための自己管理に関するエントリもありまーす。
ihcomega.hatenadiary.com
本については、多分もう1エントリくらい書きます。内容にフォーカスしたやつ。

📕執筆のきっかけ

jjug.doorkeeper.jp

もう3年前になりますが、共著者のしょぼちむさん(@syobochim)とJJUGナイトセミナーでGitの入門セッションをやったことがあります。これを知った編集担当のリブロワークス大津さんより、JJUG宛に執筆のご依頼をいただいたのがスタートでした。2018年の1月終わり頃です。

声をかけてくださった大津さん、きっかけをくださったJJUGにはとても感謝しています。

📕協力者探し

実際の作業を開始する前に、共著者、そしてレビュアーという2大協力者を見つける必要がありました。

とてもありがたいことに、相談したらすぐにOKをくれたしょぼちむさんが共著者となり、レビュアーは昔からとってもお世話になっているうらがみさん(@backpaper0)といろふさん(@irof)が引き受けてくださることになりました。

共著者探しのようす

📕構成の検討

3月の終わり頃、まずは章立てを考えるべく、しょぼちむさんと案を持ち寄り相談会をしました。ちなみに、対面で打ち合わせしたのはこれ含め2回のみ(いずれも執筆開始前)で、それ以降はすべてオンラインでのコミュニケーションでした。

あまり意見が割れることもなく、書く内容についてはスムーズに合意がとれた印象です。悩んだのは、概念の説明を先にするか、いきなり手を動かすハンズオンから始めるかといったことくらいでしょうか。なお結局、

  1. 理解しないままとりあえず触ってみる
  2. 何が起きているかよく分からないが一応バージョン管理らしいことはできる
  3. 雰囲気で使い続ける
  4. 意図しない挙動に出くわしたときに一気に詰む

という自らの経験に基づき、読者には同じ経験をしてほしくない思いから前者を取りました。

いちばんはじめの構成案

📕執筆開始

さて、構成案を提出し、5月頃から試しに第1章「Gitとは何か」を書き始めました。試しと言ったのは、

  • 執筆用ツール(後述)の使い方を確認する
  • 文体や内容などの方向性を確認する

といった意味合いの作業だったためです。

しかし…書き始めが5月とは…。打ち合わせが3月、しかも意見が割れずスムーズに進んだと書いておきながら1ヶ月空白期間があることが驚きですよね。そう、我々なかなか進めなかったのです。(これは私個人の話ですが、)「何から始めたらいいんだ」「やらなきゃいけないけど不安だけを募らせ進捗はない」といった状態が続いてしまったように思います。

そんなとき、うらがみさんが状況の確認やリマインドもしてくださったのに助けられました。申し訳なさと感謝でいっぱいです。はじめに紹介したエントリ(FOLIOで学んだマネジメントやリーン開発の知識を本の執筆に活かす - よこなのへたのよこずき)のような工夫も、この時期の遅れがきっかけだったりもします。ぴ、PDCA…。

✏執筆用ツール

「いちばんやさしい教本」シリーズの執筆には、強力なツールが用意されています。先程もご紹介した編集担当の大津さんが作ったatomプラグインで、これがあれば書きながら完成イメージを確認することができます。

見たほうが早いので見せます!

「いちやさシリーズ」の執筆を支えるatomプラグイン

すごいですよね。左側が原稿です。マークダウンをベースに、独自の記法も用いて書けば、右側のようなプレビューをリアルタイムに確認しながら執筆作業ができるのです。

  • ほぼマークダウンなので楽に書けるしバージョン管理もしやすい
  • 章の分量を適切に調節しやすい
  • レイアウトに関する編集担当の方とのコミュニケーションがスムーズにできる
  • 完成イメージが見えるためモチベーションがアップする

などメリットがたくさんで、とてもありがたいツールでした(以下、リンクです)。

atom.io

atom.io

📕執筆作業の本格化

試しに書いた第1章がapproveされ、構成案に従ってひたすら書くフェーズに入りました。もちろん、構成案は何度も見直しながら、10月頃まで作業が続きます。

出版までの作業一覧

編集担当の方と原稿をやりとりした回数を図示してみました。DTP (参考: DTP - Wikipedia) をはじめ専門用語もありますが、要は編集担当の方と著者とで交互に内容を見直し、修正とレビューを繰り返す作業をしていたということです。

✏レビュー

自分が出したPRは57件、コメントもたくさん

レビュアーのうらがみさん・いろふさんには感謝してもしきれません。特に、

  • 技術的な正しさや分かりやすさ: 入門書ということもあり、両者のバランスが非常に重要だった
  • 現場で使える情報: 様々な使い方ができるGitの、何を伝えれば現場で役立つ知識となるか考え続ける必要があった

を追求する上で、お2人のアドバイスは不可欠でした。様子を少しお見せします。

正確性のチェックや・・・

分かりやすさに関するアドバイスや・・・

使い方議論や・・・

そして嬉しいコメントも!

マージまで見届けてくださって、こういうリアクションつけてくださってたのも全部励みになっていました。

このレビューの内容こそ、GitHub入門者に見てほしい学び多きものですね。お2人とも、本当にありがとうございました!

ささやかなお礼として、お2人には本書に登場していただいた

スクリーンショットの工夫

入門書ということもあり、スクリーンショットはそりゃもう大量に撮りました。そんな中、しょぼちむさんとそれぞれ別のマシンで作業していたため、環境の差異をなるべく小さくする必要がありました。撮る範囲やフォントサイズなどをはじめ、しょぼちむさんにヒアリングして気合で揃えた部分もあるし、ちょっぴり工夫したところもあるのでそれを書いておきます。何かというと、ターミナルのプロンプトの表示をしょぼちむさんマシンに合わせる方法です。

しょぼちむさんと統一されたプロンプト

こんな感じです。当たり前のことながらPC名が異なったので、PS1を編集することで実現しました。このおかげで、 ichiyasa という本に登場するユーザーを作る必要もなく、ほんのちょっとだけ楽できた気がします。

export PS1="\[\033]0;$TITLEPREFIX:${PWD//[^[:ascii:]]/?}\007\]\n\[\033[32m\]ichiyasa@DESKTOP-LHHCMC7 \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\] \`__git_ps1\`\[\033[0m\]\n$"

📕編集チェック

初稿が書き上がったら、大津さんによる編集作業が始まります。構成や表現の改善、分量の調整などをとても丁寧に行っていただき、また、未経験者がつまずきそうなポイントの補足依頼や質問も投げかけていただきました。初心者向けで書いたつもりでも、親切さが足りない部分が多々あるなぁと痛感する日々でした。特に、「なぜそうするのか」「どうしてこうなるのか」といったwhyに関する質問はとても勉強になったポイントです。

リモートリポジトリの情報はなぜ2行表示される?

例えばこのようなご質問。 git remote -v って同じような結果が2行表示されるんですよね。でも、私の目にはこれまで1行にしか見えていなかったと言っていいほどで、それがなぜなのかとか、各行の意味の違いとか、今回の執筆で初めて意識しました。大津さんからはこうしたコメントをたくさんいただき、知らなかったことの学習もできました。

何度も何度もレビューを繰り返しよい内容にしてくださったこと、心より感謝しております。

📕刊行

11月後半にすべての工程が終了しました。 進捗の遅れがあったり、すごい量の修正に圧倒されたり、いろいろなことを乗り越えてなんとか出版することができました。月並みですが、物理本を初めて受け取ったときはとても嬉しかったですね。我が子…。

同僚や友人に献本もして、フィードバックを貰えているのがとてもありがたいです。ブログを書いてくださるみなさまも、本当にありがとうございます。

📕写真撮影

最後に、脱力しそうな話題を。表紙のイラストについても少し書いておきます。

いちばんやさしいGit&GitHubの教本 人気講師が教えるバージョン管理&共有入門 (「いちばんやさしい教本」シリーズ)

「いちやさ教本」シリーズは、イラストレーターさんによるとってもリアルな似顔絵がいたる所に載ります。元となる写真はプロのカメラマンによるもので、インプレスさんのスタジオで撮影しました。表紙用と中身用4種類と、結構な時間をかけて撮っていただき、これも貴重な経験でした。他の著者の方はガッツポーズやイイネポーズくらいにとどめている励ましポーズが、自分の場合 :ok_woman: 風になっているのがイチオシ(?)です。オリジナリティを出していいとカメラマンの方がおっしゃっていたので、勝手にやりました。

:ok_yokona:

ちなみに、自分は無言での撮影だったにもかかわらず、しょぼちむさんは写真撮影のときカメラマンの方に「Gitがんばろう!」「よくできました!」とか言わされていてとても謎でした(面白かった)。

まわりの方にただただ感謝

そんなこんなで出版にこぎつけることができたのも、出版後に嬉しい反応をいただけているのも、多くの方の協力あってのことです。みなさまにはただひたすらに感謝が尽きません!!
ありがとうございました😊そして引き続き『いちばんやさしいGit&GitHubの教本』をよろしくおねがいします😊

『アジャイルレトロスペクティブズ』を読み、ふりかえりで「KPT」以外の技を繰り出そう

かれこれ1ヶ月ほど前でしょうか、チームで新しいことを始めようとしてるんだけどイマイチ進まないな〜という状況が訪れたので、ふりかえりをすることにしました。ここ数ヶ月属してきたチームでは、振り返りというと同僚の@Mura_Miによる次の記事にある方法が便利で、よく使ってきました。また、以前は定番の「KPT」をやることもよくありました。

t-and-p.hatenablog.com

ところが、今回やりたいふりかえりは、これまで取り組んだ手法ではワークしない可能性がありました。というのも、まだこれからやっていくぞというフェーズなので、見返せるような具体的な材料がスムーズに出せなかったり、チーム内のコンテキスト共有が不十分で不完全燃焼な議論に終わったりしてもおかしくない状況だったためです。
なお、弁解しておくと、コミュニケーションが苦手あるいは不足しがちなメンバーというわけではなく、「新しいこと」に向かう姿勢やイメージがまだ十分に議論・共有できていない時期だったのです。具体的には、またまた@Mura_Miによる記事 FOLIO を支えるエンジニアリング組織の七転八倒記: 2018年冬 - TechとPoemeの間 に記載の、バックエンドエンジニアをサブグループ化した直後でした。

また、これはフェーズや手法云々ではないのですが、

  • 具体的なアクションに結びつかない
  • 継続的な効果測定ができない
  • ふりかえり自体に価値があったのか曖昧である

といった課題を残すふりかえりを過去に何度も経験してきました。

せっかく集まるからには

  • 全員がアイディアを持つことができ、発言できる
  • ふりかえりの場の具体的なゴールを定め、達成する
  • 議論した内容がその場限りにならず、何らかのアクションに結びつく

を目指して準備をしようと決めたのですが、具体的なアイディアが浮かばず…。どうしたもんかと考えていたとき、以前@syobochimさんが書いていたブログ記事を思い出しました。

syobochim.hatenablog.com

ここで紹介されている『アジャイルレトロスペクティブズ』、タイトルのとおりレトロスペクティブのhow-toやTipsが記載された本です。ふりかえりの具体的な方法も紹介されているようだったので、明日使える知識として何かヒントが得られればと手に取ってみました。

📖読んで学んだこと

💁ふりかえりをする会の構成

会の時間のすべてを、課題の抽出と解決策の検討にあててしまうことってよくありますよね。ところが、『アジャイルレトロスペクティブ』では、次のような構成に分けて取り組むことが有効だと述べています。

  1. 場を設定する
    • まず集まったメンバーに感謝を述べ、会の目的と目標を伝える
    • 全員が1度口を開くチャンスを与える
    • 会の進め方を説明する
    • チームの「価値」や「約束」を再確認し、見直す (ない場合は設ける)
  2. データを収集する
    • 客観的なデータ(開発した機能、完了したストーリーなど)を収集する
    • チームメンバーの感情を確認する
    • 集めたデータをレビューする
  3. アイディアを出す
    • 起こったことの原因や物事のやり方などについて考え、よりよい方向へ進むためのアイディアを出す (解決策には飛びつかない!)
  4. 何をすべきかを決定する
    • アイディアから、取り組む項目を決定する
    • 担当者を決める
  5. レトロスペクティブを終了する
    • 板書や付箋など、アウトプットを記録に残し、共有する
    • レトロスペクティブ自体に価値があったかどうか振り返る

💁ふりかえりを計画・実行するための進め方

何を検討してどう計画を立てたらよいか、実際のふりかえりの場においてどんなことを管理したらよいかといった内容も、具体的に考えねばならないことと併せて分かりやすく示されています。

  1. 計画する

    • チームを知る
    • 目標を決める
    • 場所を決める
    • 全体の時間とタイムボックスを決める
    • 取り組むアクティビティを決める
    • 参加者を決める
    • 周りのサポートを受ける
      など
  2. 実行する

    • アクティビティを管理する
    • 集団ダイナミクスを管理する
    • 時間を管理する
    • 自分自身を管理する
      など

💁さまざまなふりかえりの方法

ページ数も多く割かれボリュームたっぷりなのが、会の構成に沿った分類で紹介されているふりかえりの方法たちです。

  • 「場を設定する」アクティビティ: 6種
  • 「データを収集する」アクティビティ: 8種
  • 「アイディアを出す」アクティビティ: 9種
  • 「何をすべきかを決定する」アクティビティ: 6種
  • 「レトロスペクティブを終了する」アクティビティ: 9種

種類の多さを示すために数字だけ書きましたが、どんなものがあるか、こればっかりは実際に本を見てみるのが1番です。世の中KPTだけじゃないんや・・・。
これだけあれば、面白そうなものや使えそうなものもきっと見つかりますし、「長期のイテレーションに向いている」といった、役立つシーンについての説明もあるのが検討時には嬉しいです。

📖やってみたこと

自分のチームの状況に合っていて良さそうだと思った方法をいくつか実際に取り入れる予定でアジェンダを組みました。

  1. 場を設定する: 「チェックイン」を使おう
  2. データを収集する: 「満足ヒストグラム」を使おう
  3. アイディアを出す: 「5つのなぜ」を使おう
  4. 何をすべきかを決定する: nullを使おう
  5. レトロスペクティブを終了する: 「投資時間対効果」を使おう

null... 4つ目だけは本から合いそうなやつが見つからず、知っている方法でなんとか目的を達成しようと決めてしまいました。

💁うまくいったこと

上に挙げた方法でいうと、やり方もシンプルで明確な「満足ヒストグラム」だけは機能した気がします。 それ以外だと、

  • 目的
  • 目標
  • タイムボックス

をしっかり決めておいたので、進行する上で派手に迷うことがなく、なんとか場のゴールにたどり着くことができました *1

💁うまくいかなかったこと

正直、準備していた方法のうち、「満足ヒストグラム」以外はろくに実行できていません。敗因は

  • 本で学んだことを自然あるいは臨機応変に使えない (おそらく理由含めての理解が足りないので、HOWを真似するので精一杯になる)
  • 会の時間を短く設定しすぎた
  • チームの現状に対する理解が足りなかった
  • 諦めた (会のゴールさえ達成すればいいやと早々に思考を切り替えてしまった)

などだと思っています。

💁所感

うまくいったこともいかなかったこともありますが、この本は頻繁に見返したいし、行き詰まったときにヒントをくれる存在として活用していきたいです。
このエントリを書くにあたって読み返してみて、理解しきれていなかった部分や欠落してしまっていた部分も明らかになりましたし・・・。幸いチャンスはたくさんありそうなので、効果検証しながらいろいろ試してみます。

📖おまけ

そもそもファシリテーションをするときの姿勢みたいな話になりますが、準備してうまくいくイメージを持っておくことってとても大事。と最近改めて思うことが多いです。慣れていてもぶっつけでは質が落ちるし、時間がないからってサボると結局集まった人の時間が無駄になりかねません(エビデンスはあまり持ち合わせていませんが、新卒研修でも『ファシリテーションの教科書: 組織を活性化させるコミュニケーションとリーダーシップ』でもそう言ってましたし、経験上そう。もちろん、ただただ能力が高くてできちゃう人もいますが)。準備をしてうまくいく保証はないが、準備をしないとうまくいかないことが多々あるといった感じでしょうか。地道に、知識のインプットと経験を積み重ねて、その質や効率を高めていきたいですね。

*1:チームメンバーが自分より大人なので…絶大なサポートあってですが