Paper2 Blog

ともに、かける

マインドセット:「やればできる!」の研究

マインドセット:「やればできる!」の研究

マインドセットとは心の在り方です。能力を伸ばし続けることができるしなやかマインドセットと対極となる硬直マインドセットを様々な例を交えて解説しています。以下を確認し、硬直マインドセット寄りの考えを多く持つ方に当書籍はおすすめです。

硬直マインドセットとしなやかマインドセット(書籍より引用)

上記のように端的な言葉で表現すると「そんなの知っているぞ?」と感じる人も多いかもしれません。当書籍の中では多くの具体例をもとに両マインドセットを比較しながら解説しています。

具体例で硬直マインドセット寄りの考えを持っていることに気付けることもあります。豊富な具体例を読みながら自分自身に問いかけ、自らを見つめ直し、マインドセットを変えるきっかけになる一冊です。

それでは両方のマインドセットを少しだけ紹介します。

しなやかマインドセットの根底には人間の能力は努力次第で伸ばすことができるという信念があります。だからこそ挑戦を続け、失敗を成長の糧にして進んでいくことができます。

硬直マインドセットは高い能力が天性のものと考え、失敗したら能力がないとあきらめ、努力は無駄と考える傾向があります。

成長しやすい方がどちらかは明らかでしょう。また成功の考え方にも差が出ます。

能力を固定的にとらえる世界では、自分の賢さや才能を証明できれば成功、自分の価値を確認できればそれが成功だ。一方、能力は伸ばせるものと考える世界では、頑張って新しいことを習得できれば成功。自分を成長させることができれば成功なのだ。

成長することが成功という考え方は持続的でとても良い考え方だと思います。振り返ると私は前者に近い考えで生きてきた時間の方が長いです。ここ5年くらいは後者に成ろうと頑張っていたりします。

しかしまだ当てはまってしまうな、、と感じたのは以下の硬直マインドの特徴です。

硬直マインドセットの人はなぜ、今すぐ完璧にできなくてはいけないと思うのだろうか。それは、1回のテストや1回の評価で自分の価値が永遠に決まってしまうと思っているからだ。

根底として完璧を求めるところがあり、それが失敗した時のダメージを増幅していると思います。自分の価値が永遠に決まってしまうというのも、そんなわけないと頭で分かっていても感じてしまう自分はいます。

一方で以前はそれが怖くて挑戦を避けてきたのですが、最近はそれを受け止める覚悟で挑戦するようにしています。

実際に成長を成功とする考えの方が強くなっていると感じます。

まず頭で理解して実践しながらゆっくりと変化の芽を育てていくことが重要だと思います。引き続き頑張ります。

なお、当書籍でもほとんどの人が両マインドセットを併せ持っていると述べられています。両方を理解した上で適宜しなやかマインドに寄せることで今後の成長速度を早めていけるでしょう。

しなやかマインドに興味を持った方や、変わりたいと思う方は是非読んでみてください。

より良い育休にするために考えていること

2月上旬に第二子が生まれる予定で、育休を3ヶ月いただきます。大変な時期を家族で支え合いながら乗り越え、その経験により結束を強める貴重な期間になると考えています。一方で収入が減り、仕事における成長も鈍化するという代価もあります。だからこそ本気でより良い期間にしていきたいです。そのために色々考えたことを書いてみます。

育休の目的

厚生労働省育児・介護休業法の概要を読んでみると、制度自体は子育てに時間的制約を抱えている時期の労働者の仕事と家庭の両立支援を意図していることが読み取れます。また、休業の定義には

労働者が、原則としてその1歳に満たない子を養育するためにする休業

と書かれています。

  • 仕事と家庭の両立
  • 1歳に満たない子を養育する

というのが重要そうです。これらは前提として、目的を以下のように定義してみました。

大変な時期を家族で支え合いながら乗り越え、その経験により結束を強める。

上記の目的を達成するために、以下のことに注力していきたいと考えています。

  • 新生児のお世話
  • 産褥期(さんじょくき)の妻の回復
  • 第一子の心のケア
  • 家族との思い出作り

これ以降ではそれぞれの考えを書いていきます。

新生児のお世話

第一子の時もおむつ替えなど含めしていましたが、仕事をしているのもあり比重は妻の方が大きかったです。今回は私が多くなるくらいの気持ちでどんどんお世話をしていく所存です。

沢山触れ合い、愛情を注いでいきたいなと考えています。仕事をしているとその余裕がないこともあったので、育休でそれができるのは大きいなと思います。夜泣きなど体力的にきついところなどもありますが、色々と工夫をしながら乗り越えていきたいです。

産褥期の妻の回復

出産を終えた女性の身体が、妊娠前の状態に回復するまでの期間を「産褥期(さんじょくき)」と言います。産後にやってはいけないことがあるくらい、産後の身体は弱ります。

一人目が2020年に生まれた時は前職で男性育休の文化がなかったのもあり、産褥期に妻は里帰りをしていました。なのでそこを支えるということはあまりできていません。今回は産褥期も含め家族で乗り越えることに大きな意味があると思っています。

妻は妊娠中も色々なことに気を使い、第二子をお腹の中で育ててくれました。感謝しかありません。産褥期における妻の回復を支えるのは、私の感謝を表す良い機会だとも思っています。産褥期の家事・育児は全部やるくらいの気持ちで全力で妻の回復を後押ししたいです。

第一子の心のケア

夫婦共に子供が好きなので、娘への愛情は結構注げている気がします。第二子が生まれるとどうしてもそちらに集中しないといけない場面が増えるので、娘の体験としては愛情が減ったように感じると思います。二人目の出産で一人目が赤ちゃん返りするというのもよくあることです。娘の成長のための通過点と捉えつつも、しっかりケアをしていきたいと考えています。

例えば量を減らさないという観点で親を独り占めできる時間を積極的に作ってあげるなどもしたいです。それがしやすいのも育休の良いところだろうなと感じます。

生まれてみないとわからないのですが、娘の特徴を踏まえて夫婦で色々なパターンを想定していたりします。娘も家族が増えたことをより喜べるような工夫をしていきたいです。

家族との思い出作り

育休期間の収入は減りますし、仕事における成長も鈍化します。全部を手に入れることはできません。育休の方が重要と判断して私は3ヶ月の育休を選びました。費用対効果を良くするために効果を上げることも考えていきたいです。

私は家族との思い出が人生において重要な資産だと考えています。そこで家族との思いでをたくさん作り、アルバムを残すことを考えています。思い出にも焦点を当てているのは私なりの育休をより良くするための工夫だと思っています。

アルバムには育休中の子育て風景や、第二子の成長過程、ちょっとしたお出かけの写真など色々な思い出を詰め込みたいです。企画として家族の集合写真を毎日撮ってそれを1ページに並べるというのもやろうとしています。出産前から撮り始めているので今は3人ですが、そのうち出産で妻が入院して2人の写真になり、帰ってきたら4人になり、、、という過程を1ページに収める予定です。

まとめ

育休について考えていることを書いてみました。子供の特性によるので不確実性が高く、うまくいかないことも多いと思います。自分の中では大きな代価を払う決断ではあったのでより良くするために色々考えることは重要だったと思います。さて、頑張るぞ〜〜〜。

DIE WITH ZERO 人生が豊かになりすぎる究極のルール

DIE WITH ZERO 人生が豊かになりすぎる究極のルール

人生をより豊かにするために優先すべきことを気づかせてくれました。私の考え方に大きく影響を与えてくれる良書でした。特に仕事に夢中になってしまっている人は今しかできない大切なことを見逃しているかもしれません。早めの段階で一度読んでみることをオススメします。バランスが重要です。

当書籍における筆者の一番の主張は以下です。

生きているうちに金を使い切ること、つまり「ゼロで死ぬ」を目指してほしい。

「ゼロで死ぬ」ためのマインドやアメリカの制度や資産状況の調査結果などを踏まえて、何故「ゼロで死ぬ」ことを目指すべきかを丁寧に説明しています。とても良い選択肢だと思いましたが、残念ながら私は「ゼロで死ぬ」という一番重要なコンセプト自体は共感できませんでした。

しかし、この主張の中には筆者の色々な考えが包含されています。私は以下の考え方に強く共感しました。

ただ生きるだけではなく、十分に生きる。経済的に豊かになるだけではなく、人生を豊かにするための方法を考える。

書籍の中では仕事やお金を稼ぐことに夢中になってしまい、年を取ってから資産はあるけど後悔している人のお話などが出てきます。お金があっても若く健康だったり、子供が幼いうちにしかできない経験がたくさんあります。

お金を稼ぐことは確かに重要ですが、それらをバランスよく経験していくことが人生をより豊かにすることにつながります。私は特に子供との今しかできない経験について深く考えるきっかけになりました。

以降では当書籍を読んで具体的に変化があったことを2つ紹介してみたいと思います。

  1. 2人目の育休を1ヶ月から3ヶ月に伸ばした
  2. 妻の時短勤務でさらに勤務時間を減らす予定

2人目の育休を1ヶ月から3ヶ月に伸ばした

もうすぐ2人目が生まれるのですが、私の育休を1ヶ月から3ヶ月に伸ばしました。収入が減ってしまうことに妻と共に漠然とした不安を持っていて、1人目の時に妻が回復するまで必要だったギリギリのラインの1ヶ月で取得することにしていました。すると5人の同僚や上司から「本当にそれだけで良いの?」と心配の声をいただきました。実はその中の一人が薦めてくれた本が当書籍でした。

3ヶ月の生活を乗り越える貯金はあるので、それなら以下のような経験を優先すべきだと考えが変わり、3ヶ月に伸ばしました。

  • 出産で身心共に大変だった妻の回復をできるだけサポートする。その経験が夫婦の絆をより強くする。
  • 1人目の赤ちゃんというべらぼうにかわいい時期をたくさん一緒に過ごせる。その経験が自身の人生をより豊かにする。
  • 3歳の娘とも触れ合う時間が増える。その経験が自身と娘の人生をより豊かにする。

妻の時短勤務でさらに勤務時間を減らす予定

家のローンや子供の養育費など色々お金がかかるので共働きをしています。ファイナンシャルプランナーに資産計画のシミュレーションをしてもらったことがあるのですがめちゃくちゃ余裕とはいえない状況です。

ただ、なんとかはなります。いざという時に困るかもしれないリスクを取ってでも、今しかない子供との時間の優先度を上げようという考えになりました。夫婦で話し合い、少なくとも子供が低学年を終える頃までは妻の時短勤務をフル活用しようということになりました。

元々妻はできたら子供とずっといたいという思いを持っていたので、妻も子供達にもより良い経験になるのではと期待しています。それが私にとっての幸せでもあります。

まとめ

結果的に人生何があるかわからないのでより良い選択がある可能性はあるでしょう。お金を稼げるときに稼いでおいた方がよかった可能性もあるかもしれません。私はそのリスクを取ったとしても、今のかけがえのない家族との経験を優先すると決断しました。あとはこれを正解にするように頑張るだけです。

当書籍を読んで共感したことや、考えが変わったことなどを記載してみました。もし「自分にも影響ありそうかも」と思っていただけて当書籍を読むきっかけになれば私も嬉しいです。

Cloud MonitoringのSlack通知でメンションを利用する

🎄 SRE Advent Calendar 2023 23日目の記事です。

Google Cloud MonitoringのアラートポリシーによるSlack通知でグループへのメンションなどを活用したい場合があります。例えばエラーバジェットを急激に消費しているファストバーンアラートなどはより気付きやすくなるようにメンションをつけておきたい場合もあるかと思います。

サマリ

Cloud MonitoringのDocumentationに記載した内容はSlackのtext objectとして表示されるため、メンションしたい場合は特別に解釈される文字列を利用する必要があります。例えばグループメンションは <!subteam^ID> を利用します。

@groupと書いてもメンションされない

Documentationに直接 @group と入力してもSlack通知時にはメンションとして扱われません。

Cloud MonitoringのDocumentation入力画面

以下のようにメンションになりません。

うまくメンションされない時のSlack通知画面

メンションにする方法

Cloud MonitoringのDocumentationに記載した内容はSlackのtext objectとして扱われるため、メンションしたい場合は以下のように特別に解釈される文字列を利用する必要があります。

  • グループメンション
<!subteam^ID>

特定グループにメンションしたい場合は上記の文字列を利用します。ID 部分をグループIDで置き換えます。グループIDはusergroups.list Web APIで検索することができます。 また、ブラウザで開いて特定のユーザーグループを編集するときのURLにもIDが含まれるのでそこから取得することもできます。

  • 特定ユーザへのメンション
<@ID>

特定ユーザにメンションしたい場合は上記の文字列を利用します。ID 部分をユーザIDで置き換えます。こちらはプロフィールからも取得できます。

プロフィールでのメンバーIDの取得

  • 特別なメンション
<!here> <!channel> <!everyone>

@here @channel @everyone などの特別なメンションを利用する場合は上記の文字列を利用します。ただし、これらのメンションは多くのユーザに通知してしまう傾向があるため極力利用しないことが推奨されています。

上記文字列を活用することで、Slack通知時にメンションを利用することができます。

特別な文字列を利用してメンションした際の通知

(おまけ)その他の特別な文字列

  • チャンネルへのリンク
<#C123ABC456>

アラート通知時に特定のチャンネルを見て欲しい時があります。そういう時は上記の文字列が利用できます。

  • dateフォーマット
<!date^timestamp^token_string^optional_link|fallback_text>

こんなのあるんだ的なやつですが、任意のフォーマットで時刻を表示できます。

Block Kit Builderでdateフォーマットを試してみる

まとめ

Cloud MonitoringのSlack通知でメンションを利用する方法を紹介しました。意外とネットですぐ見つからなかったので小ネタとして書いてみました。どこかで役に立てば幸いです。

Cloud FunctionsをOpenTelemetry Goでトレースする

🎄 OpenTelemetry Advent Calendar 2023 13日目の記事です。

Google CloudのCloud FunctionsをOpenTelemetryでトレースする方法をご紹介します。ローカル、Google Cloud両方で試せるサンプルも用意したので適宜試してみてください。

サマリ

Cloud Functionsの計装ではTracerProviderのShutdown処理を実施せず、毎回のFunction実行でSpanをForceFlushする。一方で低いレイテンシーが求められる場合はSpanの欠損を許容し、ForceFlushを実施せずにSpanをバックグラウンドで送信することなども検討する。

前提

OpenTelemetryの初期化

OpenTelemetryの初期化を実施します。

package greeting

import (
    "context"
    "os"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/propagation"
    "go.opentelemetry.io/otel/sdk/resource"
    "go.opentelemetry.io/otel/sdk/trace"
    sdk "go.opentelemetry.io/otel/sdk/trace"
)

// InitTracing initializes tracing.
func InitTracing() *sdk.TracerProvider {
    var opts []otlptracehttp.Option
    if localOnly := os.Getenv("LOCAL_ONLY"); localOnly == "true" {
        // In local environment, TLS is not set up.
        opts = append(opts, otlptracehttp.WithInsecure())
    }

    client := otlptracehttp.NewClient(opts...)
    exporter, err := otlptrace.New(context.Background(), client)
    if err != nil {
        panic(err)
    }

    resources, err := resource.New(
        context.Background(),
        resource.WithHost(),
        resource.WithAttributes(
        // Custom attributes
        ),
    )
    if err != nil {
        panic(err)
    }

    tp := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(resources),
    )

    // Set the global TracerProvider to the SDK's TracerProvider.
    otel.SetTracerProvider(tp)

    // W3C Trace Context propagator
    otel.SetTextMapPropagator(propagation.TraceContext{})

    return tp
}

通常は以下のようにcleanup用の関数を返し、適切にShutdownできるようにします。FunctionsではTracerProviderを返します。

   cleanup := func() {
        ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
        defer cancel()
        if err := tracerProvider.Shutdown(ctx); err != nil {
            log.Printf("Failed to shutdown tracer provider: %v", err)
        }
    }
    return cleanup, nil

Shutdown処理をしないというワイルドな使い方をするのがCloud Functionsの計装の特徴です。理由などについては後述します。

HttpHandlerの計装

計装対象のHttpHandlerをラップしてSpanを作成するようにします。ラップしたHttpHandlerを返すInstrumentedHandler関数を作成します。

package greeting

import (
    "context"
    "log"
    "net/http"

    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
    "go.opentelemetry.io/otel/trace"
)

type Flush interface {
    ForceFlush(context.Context) error
}

type HttpHandler = func(w http.ResponseWriter, r *http.Request)

// InstrumentedHandler wraps the function with OpenTelemetry instrumentation.
func InstrumentedHandler(functionName string, function HttpHandler, flusher Flush) HttpHandler {
    opts := []trace.SpanStartOption{
        // customizable span attributes
        trace.WithAttributes(semconv.FaaSTriggerHTTP),
    }

    // create instrumented handler
    handler := otelhttp.NewHandler(
        http.HandlerFunc(function), functionName, otelhttp.WithSpanOptions(opts...),
    )

    return func(w http.ResponseWriter, r *http.Request) {
        // call the actual handler
        handler.ServeHTTP(w, r)

        // NOTE: ForceFlush() may extend the function's duration. It must be used carefully.
        //       If ForceFlush() is not called, spans are send on background.
        //       Backgraound tasks are not recommended in Cloud Functions. Span data sometimes get lost.
        err := flusher.ForceFlush(r.Context())
        if err != nil {
            log.Printf("failed to flush spans: %v", err)
        }
    }
}

トレースコンテキストから親スパンの情報を抽出するためにはotelhttpパッケージを用います。ポイントはForceFlush関数でSpanの送信を明示的に実行している部分です。

上記の関数を利用して計装したCloud Functionsの実装が以下です。トレースがつながることを確認できるように NEXT_ENDPOINT が設定されていた場合はotelhttpでトレースコンテキストを付与して次のエンドポイントにリクエストを送信しています。

package greeting

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

func init() {
    // NOTE: Usually TracerProvider should call Shutdown() at the end of the program.
    //       It is difficult to do so in Cloud Functions.
    //       This issue can be mitigated by using ForceFlush() to flush spans.
    tracerProvider := InitTracing()
    handler := InstrumentedHandler("greeting", greeting, tracerProvider)
    functions.HTTP("Greeting", handler)
}

// greeting is the function's core logic.
// It resoponses "Hiya!" and calls the next function if NEXT_ENDPOINT is set.
func greeting(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hiya!")

    // sleep for extending the span's duration
    time.Sleep(100 * time.Millisecond)

    err := greetNext(r.Context())
    if err != nil {
        log.Println(err)
        w.WriteHeader(http.StatusInternalServerError)
    }
}

// greetNext calls the next function.
func greetNext(ctx context.Context) error {
    next := os.Getenv("NEXT_ENDPOINT")
    if next == "" {
        log.Println("I have no freinds :(")
        return nil
    }

    // call the next function.
    // otelhttp sends a trace context to the next function.
    res, err := otelhttp.Get(ctx, next)
    if err != nil {
        return err
    }

    // Must close the response body to avoid leaking connections.
    err = res.Body.Close()
    if err != nil {
        return err
    }

    log.Println("I said hi to my friend :)")

    return nil
}

一番のポイントはinit関数です。初期化したTracerProviderを直接利用することは普段ないと思います。ForceFlushを実行するために、InitTracing関数でTracerProviderを受け取り、InstrumentedHandlerに渡しています。*2

上記で実装の説明は以上になります。Cloud Tracesで確認すると以下のようなトレースが取得できます。

ForceFlushについて

Cloud Functions計装のポイント、ForceFlushについてもう少し詳しく説明します。

そもそもTracerProviderのShutdown処理は本来実施すべき処理です。リソースを解放し、SpanのFlushを実施します。しかし、Cloud Functionsはインスタンスの終了時にいい感じでクリーンアップ処理をする方法を提供していません。

さらに行儀よく使うならTracerProviderを毎回作成し、毎回Shutdown処理をするというのもできるかもしれません。ただ、さらにレイテンシーが高くなる可能性があります。

そのためTracerProviderはGlobalで共有し、Shutdown処理をしない。その代わりにSpanの送信を適切に制御するくらいがちょうど良いバランスなのかなと考えています。リソース解放漏れがあってもCloud Functionsのインスタンスが終了するのであればあまり問題ない気もしています。

Cloud Functionsはバックグラウンドでの処理を推奨していません。確実にSpanを送信したい場合はForceFlushが必要です。一方で性能要件を満たせない場合は、Spanの欠損を許容しバックグラウンドでのSpan送信に頼るのもありかと思います。

まとめ

Cloud Functions(Go、HTTPトリガー)の計装について紹介しました。ForceFlushの考え方は言語、トリガーの種類に関係なく共通です。

Cloud Functionsの計装ではTracerProviderのShutdown処理を実施せず、毎回のFunction実行でSpanをForceFlushするのが良さそうです。一方で低いレイテンシーが求められる場合はSpanの欠損を許容し、ForceFlushを実施せずにSpanをバックグラウンドで送信することなども検討してください。

*1:Dynatraceの記事をベースに作成しています。Pub/Subトリガーを利用する場合も当記事とDynatraceの記事を参考にすれば作れると思います。

*2:otel.GetTracerProvider関数を使えばInitTracingで返す必要ないのでは?と思い試してみましたが、GetTracerProvider関数が返すtrace.TracerProviderインターフェースはForceFlush関数を含んでいませんでした。そのため型アサーションなどの処理が必要になり少し複雑になります。そのためInitTracing関数でTracerProviderを返す方がシンプルかなと思います。

障害対応の教科書

システム障害対応の教科書

暗黙知になりやすいシステムの障害対応が形式知として体系的にまとめられていてとても良かったです。障害対応レベルや対応フローなどの仕組み化が出来ていない組織では特に有用かと思います。また、後進育成を考えるインシデントコマンダーなどにもオススメです。内容は業界関係なく参考になりますが、SIer業界ならではの複数ベンダと障害対応をする難しさについても説明があり大変面白かったです。

本書籍の一つの特徴として、インシデントコマンダーの考え方が根幹となっている点が挙げられます。日本ではSRE本により広まった感じがありますね。インシデントコマンダーは障害発生時の意思決定者です。障害対応の方針を決め、全体を導き、管理をします。インシデントコマンダーを中心として、作業担当、ユーザ担当、CIOなどの役割が他に紹介されています。それぞれ、自組織ではどのように当てはまるかを考えてみると良いでしょう。

また、障害対応の仕組みとしては高度な部分まで記載があると思います。他社を含めて多くの組織が関わる障害対応について解説があります。私が今見ているシステムでは顧客を除くとステークホルダが自社に閉じることが多いです。それでも大変そうなので、他社の組織も巻き込んで解決するとなると難易度が跳ね上がると思います。

基礎の部分もしっかりと説明があるので、自社に必要なレベルを見極めながら導入を進めると良いと思います。第7章では障害対応のレベルを「人の動き」「プロセス」などの7個の観点で判定できます。現状のレベルと理想の差分などを考えてみても良いかもしれません。理想のレベルは複数ベンダで大きなシステムを管理するのかなど前提で変わると思います。ビジネスとしてどのレベルが必要かが重要です。

当社ではインシデント・レスポンスの事前準備がされています。対応フローや障害レベルの定義などは各プロダクトに行なわれています。私が入社した当初から既に整備されていたのもあり、SREとして学ぶべきと思いつつも優先度が上がっていない状況でした。今回年明けにインシデント・レスポンスミートアップを企画することになり、ちゃんと学習する機会ができて良かったと思います。また、体系的に学ぶ中で当社が基礎的な部分をしっかりとで実践していることがちゃんとわかりました。1つだけ改善案が見つかったので、ちょっと提案してみようかな〜と思っています。

システムの障害対応について基礎から応用まで多くの内容が体系的にまとまっている良い書籍でした。障害対応の仕組み化ができていない組織では非常に参考になる書籍だと思います。是非読んでみてください。

おまけ

良かった・面白かったポイントをピックアップしてみます。

システム障害対応の目的は、システムを直すことではありません。ユーザの業務影響を極小化し、早期に業務を復旧させること。これがシステム障害対応の目的です。システムを直すことは、業務回復の手段の1つであり、目的ではないのです。

これはめちゃくちゃ重要ですね。障害対応について初めて学んだ際に「確かに、、、!!最悪完全に直す必要はないな、、、!!」と衝撃を受けたことを覚えていますww

インシデントコマンダーは、障害対応を行うサービス・システム・技術への深い知識を持っている必要はありません。(中略)重要なのは、技術力よりも障害対応をコントロールするためのマネジメントスキル、コミュニケーションスキルなどです。そして、全体の方向性や透明性の確保を行うことが、インシデントコマンダーの行動の重要な成功要因です。

これは確かにな〜と思いました。当社では、、、という話をしてみたいのですが言っていいのかわからないのでこのくらいにしておきますww

Good Code,Bad Code: 持続可能な開発のためのソフトウェアエンジニア的思考

Good Code, Bad Code ~持続可能な開発のためのソフトウェアエンジニア的思考

プロフェッショナルなエンジニアが常に意識している重要な概念が紹介されています。経験が3年以内のエンジニアに特におすすめの一冊です。経験豊富なエンジニアの場合、他のエンジニアへのメンタリングに役立ちそうです。私の師匠は「今まで理解していたけど言語化するとこうなるよなあ」と言ってました。実際本書の中の表現をPRのレビュでもらっていたことを本を読んで知りました。言語化大切です。また、説明もかなり丁寧で、疑似コードをベースに詳しく説明してくれるのでかなり腹落ちしやすいです。

私はインフラメインでキャリアを積んできたので、プログラマーとしては3年以内のエンジニアになります。知らない内容も多く非常に勉強になる一冊でした。目次は以下の通りです。Part1に理論編とありますが、Part2以降も綺麗に考え方や理論を言語化してあります。そのため、どのような背景があり何故そのように書くと信頼性の高いコードを書けるのかなどを深く理解することができます。

- Part 1  理論編
  - Chapter 1  コードの品質
  - Chapter 2  抽象化レイヤー
  - Chapter 3  コードでの契約
  - Chapter 4  エラー
- Part 2  実践編
  - Chapter 5  コードを読みやすくする
  - Chapter 6  想定外の事態をなくす
  - Chapter 7  誤用しにくいコードを書く
  - Chapter 8  コードをモジュール化する
  - Chapter 9  コードを再利用、汎用化しやすくする
- Part 3  ユニットテスト編
  - Chapter 10 ユニットテストの原則
  - Chapter 11 ユニットテストの実践

読んでいく中で既存のプロダクトコードの中で既に利用されているプラクティスを色々理解できたので本当に勉強になりました。仕組みとして理解せずに従っていたものもありました。今回理解を深められて大変良かったです。いくつか内容を紹介してみたいと思います。

Dependency Injection (DI)

Chapter 8のDIの説明が大変勉強になりました。DIの仕組み自体を他のコードを真似て利用したりはしていたのですがその背景や目的についての理解は浅かったです。正直めちゃくちゃ感動しました。

DIにより依存を減らし、より堅牢なモジュールを作る。またそれによりテストもしやすくなる。素晴らしい。

またインターフェースの使い所を正直理解しきれていないところがあったのですが、DIでの用途を疑似コードと一緒に読みながら完全に理解しました(?)。

他にも特定クラスの中でファクトリのロジックも持つとモジュール性が失われていくので、インスタンス作成時のファクトリーを作っておくのが重要など実践的な内容も多く紹介されていました。

テストのフィラソフィー

ユニットテストについても基本的な考え方が記載されています。私が良いなと思ったのは複数の考え方(フィラソフィー)を紹介している点です。上級者の書いたコードに機能追加をしていく場合、そのやり方に従うのでこの辺りを理解していない場合があります。私は普段の会話などで何となく理解していたのですが、以下のように綺麗に学派として別れていたのは知りませんでした。

・モック派 (Mockist)
「ロンドン学派」と呼ばれることもある。支持者は、「エンジニアは、テストでプロダクションの依存関係を使用することを避け、代わりにモックを使用する必要がある」と主張する。モックを使用することは、多くの場合、戻り値を提供する依存関係のすべてに、スタブを使用する必要があることも意味する。

・古典派 (Classicist)
「デトロイト学派」と呼ばれることもある。支持者は、「モックとスタブの使用は最小限に抑えるべきであり、エンジニアは、テストでプロダクションの依存関係を使用することを優先するべきである」と主張している。プロダクションの依存関係を使用できない場合は、フェイクを使用することが次の優先事項となる。モックとスタブは、プロダクションの依存関係とフェイクを使用できない場合の最後の手段としてのみ、使用を勧める。

上記の内容はおまけ部分で、より実践的な内容も書かれています。例えばパブリックAPIのみをテストするのは非常に効率の良い方法ではあるが、非パブリックAPIで重要な箇所をテストできないことはある。重要な非パブリックAPI部分はテストをすることを考えた方が良いことなども説明されています。こちらは今の開発で理解していたところでもあるので、非常に重要だよなあと読みながら思いました。

まとめ

本書はプロフェッショナルなエンジニアが常に意識している重要な概念を紹介し、初級者から経験豊富なエンジニアまで参考になる内容が詰め込まれています。特に依存性の注入やユニットテストの哲学などの実践的な内容が詳しく解説されており、読むことで多くの気づきを得ることができました。おすすめの一冊です。