きり丸の技術日記

技術検証したり、資格等をここに残していきます。

GitHub Actionsで常に実行するステップを作成する(ジョブステータスのチェック関数)

検証中、成功していたGitHub Actionsが意図しない箇所で失敗するようになりました。失敗したログがGitHub Actions上にあるものの、SSHでのアクセスができないのでログファイルを取得することはできません。

ログをArtifactoryに上げるworkflowは使用していたものの、テスト成功時のみアップロードする意味のないものになっていました。

※ その時書いた記事。【CICD】GitHub ActionsでJavaのテスト結果をアップロードする

今回の記事では、workflowをテスト失敗時、または常に実行して、失敗時に処理を追いやすくします。

この記事を読んでわかること

  • ステップの成功、失敗を問わずに目的の処理をするステップを作れるようになる
    • テストの後処理を実行できる

ジョブステータスのチェック関数

if条件ステータス関数を使用することで、以前のステップの実行結果を元に対象のステップを実行判断させます。デフォルトはsuccessです。

公式使用例

steps:
  ...
  - name: The job has succeeded
    if: ${{ success() }}

チェック関数一覧

  • success
    • 失敗やキャンセルが1つもない場合に実行する
  • always
    • 常に実行する
  • failure
    • 失敗した場合に実行する
  • cancelled
    • キャンセルしたときに実行する

今回の処理で使用したステップ

- if: always()
  name: Upload test result
  uses: actions/upload-artifact@v2
  with:
    name: test
    path: build/reports/**/*

ソースコード

github.com

終わりに

テスト結果をGitHub ActionsのArtifactoryにアップロードする記事を書いたときに、エラーが発生した時にもArtifactoryにアップロードされていることを確認すべきでした。こういう時に横着していると気づけないですね。

自分のミスに早期で気付くためのCI/CDなので、もっと有効な機能を知って今後に生かしていきたいです。


もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、Twitterのフォローもよろしくお願いします。私の励みになります。

参考資料

GitHub Actions公式サイト docs.github.com

f:id:nainaistar:20201018204827p:plain

リモートワーク、本当にうまく行っていますか?「見えない課題を見えるようにするピアコーチング」にイベント参加しました

現在、ほぼ1人で仕事しています。一応、チームにもう1人エンジニアはいるのですが、自分と違って別のプロジェクトにも参画しているので、基本は1人で作業しています。1人でもくもくと作業しているので、現在のプロジェクトとしては上手くいっている認識ですが、今後チームでリモートワークを行うことに対して不安を持っていました。

なので今のプロジェクトから離れてチームでのリモートワークに準備するため、今回のイベントに参加しました。

イベントページ

redjourney.doorkeeper.jp

開催日

2020-10-20(火)20:00 - 21:00

見えない課題を見えるようにするピアコーチン

※ 以降、感想まではメモ。


人は「感情」と「無意識」で動く。仕事で他人に感情を出す機会があるか。publicで感情を出すことは恥ずかしいことだと思われている。よっぽどではないと感情で動かない。表出化している意識は一部のみ。パターンで行動しているのも無意識。

自己認識の問題として有名なものに、ジョハリの窓がある。形式的には窓は4分割されているが、実際の自分も知らないし他人も知らない未知の窓のエリアが大きい。完璧な自己認識は不可能。

相手のことは分からない
→知るために話そう(まだいい)

自分のことは分からない
→気づいていない
→どうしようもない

整理できていない。分かっていない。言葉にする必要がある。無意識を意識的に、言葉にして引っ張り出す必要がある。言語化をし続けた方がいい。登壇者は3年くらい実施しても、やった気にならない。以前と比べて10倍近く分かった気がするけど、毎回新しい発見がある。

聴く 相手を発見する < 話す 自分を発見する

両方必要。でも、話す方が大切。↑を実現できるのがコーチング。

ピアコーチングで感情と無意識を出す機会を作っていく。人間は他人との対話により自分を知ることができる。

無人島で一人で育った場合は自分を認知できない。他人に話すことで、自己を確立できる。

コーチングとは?

  • セラピー/カウンセリング
    • マイナスを0にする活動。痛みや機能不全を癒し、個人や周囲との関係性の中で乗じる葛藤に対処。
  • コンサルティング
    • 問題を診断し、解決策を処方し、時にはその解決策を実行する
  • メンタリング
    • 自身の経験に基づく知恵とガイダンスを提供する(主に助言)
  • コーチン
    • 個人的な変化をサポート。目標を設定し、主体的に行動し、やり遂げることに焦点を当てる。そのために、ことだけではなく、その人のパーソナルな部分(無意識や感情)も取り扱う。自分でドライブできるようにする。

ピアコーチングとは?

「ピア」とは仲間のこと。同僚や仲間同士でお互いにコーチングしあう。コーチとクライアントの両方の役割を担う。

ピアコーチングで大事なこと

ヒト(人) > コト(事)
コトを通してヒトの話をする。1on1での価値は、その人を話せるようになるかということ。コトだけで話が終わることが多いがもったいない。

ピアコーチングの3つのポイント

  • 問い
  • フィードバック
  • Doing重視

問い

自己認識 = 自分を知る「問い → 自分を言語化

自分で自分を知る=内的自己認識

フィードバック

こう見える(反映) > したほうがいい(助言)
客観的な認知をフィードバック
行動が正しい・正しくないは置いておいて、そう周りに思われていることを伝える

承認が大事

他人からどう見られているか知る =外的自己認識

Doing重視

行動に移さないと、自分を知れない、変化できない

リモートワークだとベストを尽くせているかを認知できない。

行動 → ふりかえり → 次の行動計画(目標設定)

必ず行動につなげる。繰り返すことで、感情・無意識を表層化させ、行動を変化させていく。

スクラムのプラクティスを元にピアコーチングの型を作った

  • リリースプランニング
  • 1on1
  • スプリント

リリースプランニング

個人OKRなど数カ月単位の目標

1on1

ふりかえり → 深堀り → スプリントプランニング

ふりかえり

YWKやKPT等のフレームワークがある

深堀

問い/感情カードを使う。怒りや恐怖、希望等。 何が邪魔していたか、何が壁なのか、どうなると嬉しい?等を問い合わせる。

スプリントプランニング

ふりかえり、深堀した結果、タスクにする

コーチ役について

  • フラットな関係の人がやるといい
    • 利害関係が無い
      • 同僚などでもOK
      • 遠い部署が理想
    • 同じ部署の仲間であれば相手を知ることができる
  • 上司がやるのは何位井戸が高い
    • 利害関係がある
    • Being(在り方)を求められ、かなり難しい
    • 技術があれば、不可能ではない

リモートで相互発見する

ピアコーチングの利用価値。関係性を深める。行動を後押しできる。 研修で学んだことの定着 → 組織を変える

ピアコーチングは組織を変革することに繋がる。

今回、何故スクラムと紐づけたか?

  • スクラムは顧客や価値に向き、プロダクトや現場を変化させ続けるプロセス
  • コーチングは目的や目標に向け、個人を変化させ続けるプロセス

共通点

フィードバックサイクルを回し続けて改善する。スクラムに、個人の学びが加わるとチームの本質的な変化が始まる。

感想

なんで自分が1人プロジェクトでも上手くいっているかというと、会社でtimesを導入して積極的に使っているので、無意識を意識的に表層化させていたからかもしれない。特に困った内容をひたすらtimesに垂れ流したうえで、答えをもらったりすることが多いので、1人で仕事している感じが無いからかもしれない。publicに感情を出すことに抵抗もない。逆に出しすぎて困るという反応を貰ったくらい。

おそらく、そういう色んな点がマッチして、個人的にリモートワークが得意な性質が備わっていたからだと思われる。


1年前にチームで活動していた時は、ピアフィードバックは行っていたが、結局やらなくなってしまった。その時に廃止した原因は、同僚に点数をつけていたので悩んでしまうということが原因だった。今回のピアコーチングでは、相手をどういう風に認知しているかを伝えるだけになるので、次回導入しても上手くいくかもしれない。

コロナが始まってからはソロタスクに分解されたためチームワークは行っていなかったが、活動が見えない人もいた。チームとして活動しつつ、生産性を上げるためにはメンバー間でピアコーチングできるようにまずは会話することから始めた方がいいと感じた。


今回、メモ書きになってしまったが、何故コーチングが必要なのかということが理解できた。内的自己認識はほぼできている認識だが、外的自己認識が行われる環境が無いので、積極的に導入していきたい。別件でも、外的自己認識こそが自己価値を高めるためのヒントになることを言われたので、今後数十年戦うためにもちゃんと認識を高めていきたい。

終わりに

もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、Twitterのフォローもよろしくお願いします。私の励みになります。

【Java】よく使うassertThatのメソッド集【AssertJ】

「assertThat」と検索すると私のブログに引っかかる人がいるようなので、この記事を書きました。ただ「AssertJ」と検索すると、たくさん有用な記事も見つかります。

なので、この記事は「AssertJ徹底解説」ではなく、「きり丸がよく使うAssertJのメソッド」というところで新規性を出していきます。

環境

  • JUnit 5
  • AssertJ
    • org.assertj:assertj-core:3.13.2

※ 上記を指定せず、下記で一気にimportしています。 org.springframework.boot:spring-boot-starter-test:2.2.4.RELEASE を使用しています。

まとめ

  • 必須級
    • isEqualTo
    • isInstanceOfSatisfying
  • 準必須級
    • SoftAssertions
  • あったら便利
    • hasSize

だけ覚えれば問題ありません。

必須級

isEqualTo


比較対象が同一であることを確認します。基本中の基本です。ただし、isEqualToで使うために不必要に情報を丸めてしまい、エラーメッセージが適切でないことがあるので注意。ちゃんとエラーメッセージのレポートを確認しながら、テストしましょう。

String actual = "123";
String expect = "123";

assertThat(actual).isEqualTo(expect);

なお、Javaの仕様上、クラスでequalsメソッドが実装されていないと、インスタンスが違う場合は比較できません。めんどくさいので、わたしはLombok@Data@Valueで自動生成させてます。

  @Test
  void test_001(){
    Animals expect = new Animals("100");
    Animals actual = new Animals("100");

    assertThat(actual).isEqualTo(expect);
  }

NGなパターン。

  class Animals{
    String id;
    Animals(String id){
        this.id = id;
    }
  }

エラーメッセージ。

Expecting:
 <jp.co.kelly.biz.domain.NestedList$Animals@268d9b4b>
to be equal to:
 <jp.co.kelly.biz.domain.NestedList$Animals@3098daa7>

OKなパターン。

  class Animals{
    String id;
    Animals(String id){
        this.id = id;
    }

    @Override
    public boolean equals(Object obj){
      Animals animals = (Animals)obj;
      return this.id.equals(animals.id);
    }
  }

同じインスタンスであることを確認したい場合は、isSameAsがありますが…。私は中身が同じであれば、インスタンスが別でもいいので、isSameAsは使わないです。

isInstanceOfSatisfying

エラーのハンドリングが正しいことを確認する。assertThatThrownByと組み合わせる。

// Bookクラス
public class Book{
    String isbn;
    public Book(String isbn){
        if (isbn.length() == 13){
            throw new RuntimeException("ISBNの桁数が正しくない");
        }
    }
}

エラーが発生しうる条件でassertThatThrownByメソッドを呼びます。isInstanceOfSatisfyingには第一引数に目的のExceptionのクラス、第二引数にExceptionの中身を確認します。もし、Exceptionが発生することだけを確認したければ、isInstanceOfでも問題ありません。

assertThatThrownBy(
    () -> new Book("1")
).isInstanceOfSatisfying(
    RuntimeException.class,
    (e) -> assertThat(e.getMessage()).isEqualTo("ISBNの桁数が正しくない")
);

// Exceptionの中身は無視したい場合
assertThatThrownBy(
    () -> new Book("1")
).isInstanceOf(
    RuntimeException.class
);

同等のメソッドをassertThatThrownByとisInstanceOfSatisfyingを使わなかった時の書き方も記載しておきます。正常終了しない場合と目的以外のExceptionが発生した場合を確認しなければならないので、書き方が非常に大変です。

try{
    new Book("1");
    fail();
} catch (RuntimeException e){
    assertThat(e.getMessage()).isEqualTo("ISBNの桁数が正しくない")
} catch(Exception e){
    fail();
}

準必須級

SoftAssertions


複数のテストを一気にテストができるようになります。例えば、下記の例でhasSizeで100と指定すると通常であれば後続のテストが動きません。SoftAssertionsを使用すれば、途中で失敗しても全てテストしてくれます。ただし、これはテストを後回しにする方法なので、assertAllを呼び忘れるとテストされずに正常終了します。

List actual = List.of("1", "2");
List expect = List.of("1", "2");

SoftAssertions softly = new SoftAssertions();
softly.assertThat(actual).hasSize(2);
softly.assertThat(actual).isEqualTo(expect);
softly.assertThat(actual).contains("1", "2");

// ここで一気に比較する。忘れてはいけない!
softly.assertAll();

これはチェイン的な書き方しても、メリットがあります。通常通りであれば、下記のエラーメッセージしか出てきません。

assertThat(actual)
  .hasSize(100)
  .isEqualTo(null)
  .contains("1","2","3");

エラーメッセージ。

Expected size:<100> but was:<2> in:
<["1", "2"]>
at jp.co.kelly.biz.domain.AssertX.test_xxx(AssertX.java:95)

しかし、SoftAssertionsを組み合わせることで、一度のテストで下記のメッセージが出力されます。特にエラーの行数も一緒に出力されるので、かなり好きです。

softly.assertThat(actual)
  .hasSize(100)
  .isEqualTo(null)
  .contains("1","2","3");

softly.assertAll();
Expected size:<100> but was:<2> in:
<["1", "2"]>
at AssertX.test_xxx(AssertX.java:95)
    
Expecting:
 <["1", "2"]>
to be equal to:
 <null>
but was not.
at AssertX.test_xxx(AssertX.java:96)
    
Expecting:
 <["1", "2"]>
to contain:
 <["1", "2", "3"]>
but could not find:
 <["3"]>

at AssertX.test_xxx(AssertX.java:97)

なお、私はチェイン的な書き方よりも、1行1行確認する方が好きです。

書き方としては優れていますが、テスト成功している行に対して処理を追加する必要があります。そのことにより、既存のテストを壊してしまう可能性があることに違和感があります。

この辺に関しては好みですが、テストはできる限りシンプルにしたいので1行1行確認する方が好きです。


他の言語でも同様の挙動するメソッドがあるはずなので調べてみてください。Pythonではsubtestというメソッドが同等の動きをする認識です。

あったら便利

hasSize


Listのサイズを確認できます。最終的にはhasSizeの確認は不要になりますが、TDDで小さく確認するときの足掛かりになるので、私はまずサイズ確認してからそのあとリストのisEqualToを使用しています。

List actual = List.of(1, 2, 3);
List actual = List.of(1, 2, 3);

assertThat(actual).hasSize(3);
assertThat(actual).isEqualTo(expect);

Collection型のsize()を使ってisEqualToを使う方法もありますが、中身の検証をしたいのか、サイズの検証をしたいのか一見で分からなくなります。なので、sizeに関してはhasSizeを使用しています。

assertThat(actual.size()).isEqualTo(3); // サイズを知りたい?
assertThat(actual.get(2)).isEqualTo(3); // 中身を知りたい?

まとめ

  • 必須級
    • isEqualTo
    • isInstanceOfSatisfying
  • 準必須級
    • SoftAssertions
  • あったら便利
    • hasSize

終わりに

テストはできる限りシンプルにしたいので、使用するメソッドをできる限り減らしたいと考えてます。シンプルな方が、もしJUnit6が出て、AssertJが対応しなかった時に移行もしやすいですからね。もちろん、エラーメッセージが適切になるので、メソッドを覚えれば覚えるほどわかりやすいです。

もっといろいろと知りたい場合は、下記にAssertJのサンプルページもあるので、そちらから色々見てください。

参考記事

AssertJの公式ページ

github.com

AssertJのサンプルページ

github.com

AssertJ使い方メモ(Qiita)

qiita.com

assertEqualsとassertThatの比較記事

nainaistar.hatenablog.com


もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、Twitterのフォローもよろしくお願いします。私の励みになります。

f:id:nainaistar:20201013111905p:plain