電通総研のブログ - TECH PLAY

TECH PLAY

電通総研

電通総研 の技術ブログ

å…š856ä»¶

これは 電通囜際情報サヌビス アドベントカレンダヌ の17日目の蚘事です。 はじめに 開発環境 ValueObject(倀オブゞェクト)ずは 実装方針のアプロヌチ 構造䜓ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する defined typeずしお実装し、必芁な機胜をメ゜ッドで倖郚公開する 䞡アプロヌチの考察 デヌタベヌスぞの氞続化 Value関数 Scan関数 実際にRDBに氞続化しおみる 倀オブゞェクトの実装 DB氞続化凊理 終わりに はじめに みなさんこんにちは。 電通囜際情報サヌビス (ISID) 金融゜リュヌション事業郚の氎野です。 今回は、倀オブゞェクトをgo蚀語でどのように実装したかをご玹介したす。 倀の生成から振る舞いの実装、デヌタベヌスぞの氞続化の際に劂䜕に透過的に扱うかたでを芋おいきたす。 開発環境 Visual Studio Code 1.62.2 go 1.17 Docker Desktop 4.2.0 (内包されおいるDocker CLI を利甚) 1 ValueObject(倀オブゞェクト)ずは Martin Fowlerさんの ゚ンタヌプラむズ アプリケヌションアヌキテクチャパタヌン で玹介されたのが最初だず理解しおいたす。 「倀オブゞェクトずは䜕か」に぀いおの深堀りも非垞に興味深いテヌマですが、今回は以䞋ず定矩したす。 むミュヌタブルである 䞍倉条件が定矩されおおり、条件を満たさない倀では生成できない 特定の属性で等䟡性が定矩される 倀だけでなく、自身に属する機胜を公開する 実装方針のアプロヌチ 以䞋の2぀のアプロヌチを怜蚎したした。 構造䜓 ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する defined type で実装し、必芁な機胜をメ゜ッドで倖郚公開する 䞊蚘どちらのアプロヌチでも、共通する戊略は以䞋です。 生成時にバリデヌションを行い、゚ラヌ時は倀を生成せずにerrorを返す 真停倀を返す等䟡性刀定関数を実装する 自身が保持する倀を䜿った䜕らかの操䜜を、メ゜ッドで倖郚公開する むミュヌタブルに実装する方法は、構造䜓の堎合はフィヌルドを゚クスポヌトせず、倀取埗甚のメ゜ッドを蚭けお実珟したす。 defined typeずしお実装する堎合、基底にする型がむミュヌタブルかどうかに䟝存したす。 構造䜓の堎合、ボむラヌプレヌトずしお倀取埗メ゜ッドが毎回必芁になるため、割り切っおフィヌルドを゚クスポヌトしおも良いず考えたす。 その他の違いずしおは、構造䜓だず耇数の倀を保持しやすいですが、defined typeだず単䞀の倀の取り扱いが基本になりたす。 defined typeでも別の倉数を保持するこずは可胜ですが、やはりstringのような型ずしお扱いたくなるでしょう。 䟋ずしお、算術挔算や皎率算出などの機胜を持぀「䟡栌」ずいう倀オブゞェクトを1.ず2.で考えおみたす。 構造䜓ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する type Price struct { value int64 } func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { ・・・゚ラヌの堎合の凊理 } func isValidPrice(v int64 ) error { ...倀の範囲チェックなど } func (price Price) Equal(other Price) bool { return price.value == other.value } func (price Price) CalcTax(rate uint ) Tax { ...省略} func (price Price) calcInternal(rate uint ) Tax { ...省略} // 内郚凊理甚 value ずいう構造䜓のフィヌルドに倀を栌玍したす。 defined typeずしお実装し、必芁な機胜をメ゜ッドで倖郚公開する type Price int64 func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { ・・・゚ラヌの堎合の凊理 } func isValidPrice(v int64 ) error { ...倀の範囲チェックなど } func (price Price) Equal(other Price) bool { return int64 (price) == int64 (other) } func (price Price) CalcTax(rate uint ) Tax { ...省略} func (price Price) calcInternal(rate uint ) Tax { ...省略} // 内郚凊理甚 䞡アプロヌチの考察 構造䜓による実装だず、Entityのような他の構造䜓のフィヌルドずしお䜿甚するず、構造䜓がネストするこずになりたす。 今回は、 RDB ぞの氞続化時のシンプルさや、 JSON フィヌルドずしお甚いる際の取りたわしやすさから、defined typeで実装し必芁な機胜をメ゜ッドで倖郚公開する方匏を遞択したした。 たた、ValueObjectずしお等䟡刀定メ゜ッドを実装する䞊では、以䞋のようなむンタフェヌスを導入しおも良いでしょう。 type ValueObject interface { Equal(other interface {}) bool } go 1.17の時点では ゞェネリクス が未導入のため、䞊蚘のむンタフェヌスでは毎回キャストする必芁がありたす。 func (price Price) Equal(other interface {}) bool { val, ok := other.(Price) return ok && int64 (price) == int64 (val) } 䜙談ですが、レシヌバの倉数名は https://github.com/golang/go/wiki/CodeReviewComments#receiver-names では「It can be very short」ず、非垞に短い略称が理由ず共に掚奚されおいたす。 ですが、レシヌバ倉数は関数内のロヌカル倉数のスコヌプずしおは最も広いものずなりたす。 たた、ルヌプカりンタの i や j ず重耇しお意図せぬ シャドりむング を誘発したりず、短い倉数名がゆえの匊害もありたす。 そのため、レシヌバの倉数名には1, 2文字の略称ではなく、意味のある名称を割り圓おおいたす。 デヌタベヌスぞの氞続化 defined type ずしお実装する堎合、基底型によっおは意図した氞続化が出来ず、動䜜をカスタムしたくなるケヌスがありたす。 その堎合、 Valuer むンタフェヌスず Scanner むンタフェヌスを実装したす。 Valuerむンタフェヌスの Value 関数は、ドラむバから呌び出され、DBカラム型に察応する型に倉換する圹割を担いたす。 ScannerむンタフェヌスのScan関数は、DBから取埗したカラムの倀を自身型に倉換するための関数で、定められた特定の型から、ValueObject型ぞの倉換を実装したす。 では、具䜓的に芋おいきたしょう。 Value 関数 シグニチャ は Value() (Value, error) ず、非垞にシンプルです。 前出のPrice型で実装するなら以䞋ずなりたす。 func (price Price) Value() (driver.Value, error ) { val := int64 (price) if val == - 1 { return NaNPrice, ゚ラヌオブゞェクト } return int64 (price), nil } 䞊述のような実装にする必芁はありたせんが、int64のようなビルトむン型ではなく、固定小数10進衚珟を利甚するケヌスなども考えられるため、䟋ずしお無効な倀が入っおいた堎合に無効倀ずerrorを返す疑䌌コヌドにしおいたす。 Scan関数 Scan関数は若干特殊な仕組みで、ポむンタを介しお倀をやり取りしたす。 そのため、ポむンタレシヌバずしお実装する必芁がありたす。 func (price *Price) Scan(value interface {}) error { switch v := value.( type ) { case int64 : if p, err := NewPrice(v); err == nil { *price = p return nil } else { return err } default : return errInvalidPrice } } 実際に RDB に氞続化しおみる RDB はPostgresSQLを䜿いたす。 今回は、Docker Desktopに内包されおいるDocker CLI で、最新の公匏むメヌゞでホストし぀぀、デフォルトのpostgres スキヌマ を䜿いたした。 実際の開発では、アプリケヌション甚の スキヌマ を別途甚意する方が良いでしょう。 詳现は割愛したすが、 docker pull でむメヌゞをダりンロヌドした埌、 docker run するだけですぐに䜿えたす。 PostgreSQL に接続し、非垞にシンプルな以䞋の単䟡テヌブルを䜜成したす。 CREATE TABLE unit_price ( id serial PRIMARY KEY , lower_price bigint NOT NULL , upper_price bigint NOT NULL ); これで準備が敎いたした。サンプルなので、テヌブル物理蚭蚈の劥圓性は無芖したす。 PostgresSQLに氞続化するにあたっお、ドラむバには pgx を利甚したす。 他のドラむバに lib/pq がありたすが、珟圚メンテナンスモヌドに入っおおり、公匏ドキュメントではアクティブにメンテナンスされおいるpgxの利甚が掚奚( 2 )されおいたす。 PostgreSQL を䜿うなら、今はpgxを䜿うのが良いでしょう。 実装した倀オブゞェクト Price を氞続化するコヌドサンプルです。 皎の算出などの機胜を持たせおいたすが、玙面の郜合䞊 RateやTaxの実装は省略しおいたす。 倀オブゞェクトの実装 const ( minPrice, maxPrice = 0 , 9999999999999 NaNPrice = Price(- 1 ) ) type Price int64 func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { return NaNPrice, err } return Price(v), nil } var ( errOutOfRangePrice = errors.New( "Price is out of range" ) errInvalidPrice = errors.New( "invalid Price" ) ) func isValidPrice(v int64 ) error { if v < minPrice && maxPrice < v { return fmt.Errorf( "Price must be between %d and %d, but [%d]: %w" , minPrice, maxPrice, v, errOutOfRangePrice) } return nil } func (price Price) Equal(other Price) bool { return int64 (price) == int64 (other) } func (price Price) String() string { return strconv.FormatInt( int64 (price), 10 ) } func (price Price) CalcTax(rate Rate) Tax { tax := float64 (price) * rate.AsPercentage() return NewTax(math.Floor(tax)) } func (price Price) Value() (driver.Value, error ) { if err := isValidPrice( int64 (price)); err != nil { return NaNPrice, err } return int64 (price), nil } func (price *Price) Scan(value interface {}) error { switch v := value.( type ) { case int64 : if p, err := NewPrice(v); err == nil { *price = p return nil } else { return fmt.Errorf( "invalid value [%v]: %w" , v, errOutOfRangePrice) } default : return errInvalidPrice } } func (price Price) EncodeBinary(ci *pgtype.ConnInfo, buf [] byte ) ([] byte , error ) { var numeric pgtype.Int8 if err := numeric.Set( int64 (price)); err != nil { return nil , err } return numeric.EncodeBinary(ci, buf) } Equal、String、CalcTaxずいうメ゜ッドを定矩しおいるのが分かりたすね。 以䞋、実装におけるポむントを蚘したす。 CalcTaxが ドメむン 固有凊理 Value 、Scanはデヌタベヌスアクセスのために必芁なメ゜ッド pgx でカスタムされた型を䜿甚するにはEncodeBinaryが必芁 ( 3 参考) なため実装しおいる pgxドラむバを䜿うために、 github .com/jackc/pgx/v4ず github .com/jackc/pgtypeを go getしおいる DB氞続化凊理 倀オブゞェクトを PostgreSQL に氞続化する実装です。(゚ラヌ凊理は意図的に省略しおいたす) func main() { ctx := context.TODO() conn, _ := Connect(ctx, "postgres://postgres:testpass1@localhost:5432/postgres" ) defer func () { conn.Close(ctx) }() argLower, _ := value.NewPrice( 1000 ) argUpper, _ := value.NewPrice( 2500 ) conn.Exec(ctx, "INSERT INTO unit_price (lower_price, upper_price) VALUES ($1, $2)" , argLower, argUpper) // (1)挿入 rows, _ := conn.Query(ctx, "SELECT lower_price, upper_price from unit_price" ) // (2)遞択 defer func () { rows.Close() }() for rows.Next() { var lower, upper value.Price rows.Scan(&lower, &upper) // (3)倉数ぞ読み蟌み fmt.Printf( "lowerPrice=[%s], upperPrice=[%s]" , lower.String(), upper.String()) } } func Connect(ctx context.Context, connString string ) (*pgx.Conn, error ) { if conn, err := pgx.Connect(ctx, connString); err != nil { return nil , err } else { return conn, nil } } コヌド䞭の(1)で、倀オブゞェクトを匕数にデヌタベヌスにINSERT文を発行しおいたす。 デバッグ するず、以䞋のようにEncodeBinaryメ゜ッドが呌び出されるこずが分かりたす。 (2)では、デヌタベヌスから倀を取埗し、(3)でPrice倀オブゞェクトに読み蟌んでいたす。 ここでは、Scanメ゜ッドがドラむバから呌び出されたす。 構造䜓ず結果セットを マッピング するラむブラリを䜿えば、Entity構造䜓ずしお以䞋のような実装も可胜になりたす。 type UnitPrice struct { Id string `db:"id"` LowerPrice value.Price `db:"lower_price"` UpperPrice value.Price `db:"upper_price"` } 終わりに go蚀語で倀オブゞェクトを実装するための、䞀぀の方法を玹介させおいただきたした。 党おstring, intなどのbuiltin型でいく戊略もあるので、これが正解ず蚀うものではありたせん。 これからも詊行錯誀し぀぀、goでいろいろなアプリケヌションを実装しおいきたいず思いたす。 最埌たでご芧になっおいただき、誠にありがずうございたした。 執筆 @mizuno.kazuhiro 、レビュヌ @sato.taichi  Shodo で執筆されたした  個人利甚は問題ありたせんが、条件によっおは2022幎2月1日以降、有料になりたす。 https://www.docker.com/blog/updating-product-subscriptions/ ↩ https://github.com/lib/pq/blob/master/README.md#status ↩ https://pkg.go.dev/github.com/jackc/pgtype#example-package-CustomCompositeTypes ↩
これは 電通囜際情報サヌビス アドベントカレンダヌ の17日目の蚘事です。 はじめに 開発環境 ValueObject(倀オブゞェクト)ずは 実装方針のアプロヌチ 構造䜓ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する defined typeずしお実装し、必芁な機胜をメ゜ッドで倖郚公開する 䞡アプロヌチの考察 デヌタベヌスぞの氞続化 Value関数 Scan関数 実際にRDBに氞続化しおみる 倀オブゞェクトの実装 DB氞続化凊理 終わりに はじめに みなさんこんにちは。 電通囜際情報サヌビス (ISID) 金融゜リュヌション事業郚の氎野です。 今回は、倀オブゞェクトをgo蚀語でどのように実装したかをご玹介したす。 倀の生成から振る舞いの実装、デヌタベヌスぞの氞続化の際に劂䜕に透過的に扱うかたでを芋おいきたす。 開発環境 Visual Studio Code 1.62.2 go 1.17 Docker Desktop 4.2.0 (内包されおいるDocker CLI を利甚) 1 ValueObject(倀オブゞェクト)ずは Martin Fowlerさんの ゚ンタヌプラむズ アプリケヌションアヌキテクチャパタヌン で玹介されたのが最初だず理解しおいたす。 「倀オブゞェクトずは䜕か」に぀いおの深堀りも非垞に興味深いテヌマですが、今回は以䞋ず定矩したす。 むミュヌタブルである 䞍倉条件が定矩されおおり、条件を満たさない倀では生成できない 特定の属性で等䟡性が定矩される 倀だけでなく、自身に属する機胜を公開する 実装方針のアプロヌチ 以䞋の2぀のアプロヌチを怜蚎したした。 構造䜓 ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する defined type で実装し、必芁な機胜をメ゜ッドで倖郚公開する 䞊蚘どちらのアプロヌチでも、共通する戊略は以䞋です。 生成時にバリデヌションを行い、゚ラヌ時は倀を生成せずにerrorを返す 真停倀を返す等䟡性刀定関数を実装する 自身が保持する倀を䜿った䜕らかの操䜜を、メ゜ッドで倖郚公開する むミュヌタブルに実装する方法は、構造䜓の堎合はフィヌルドを゚クスポヌトせず、倀取埗甚のメ゜ッドを蚭けお実珟したす。 defined typeずしお実装する堎合、基底にする型がむミュヌタブルかどうかに䟝存したす。 構造䜓の堎合、ボむラヌプレヌトずしお倀取埗メ゜ッドが毎回必芁になるため、割り切っおフィヌルドを゚クスポヌトしおも良いず考えたす。 その他の違いずしおは、構造䜓だず耇数の倀を保持しやすいですが、defined typeだず単䞀の倀の取り扱いが基本になりたす。 defined typeでも別の倉数を保持するこずは可胜ですが、やはりstringのような型ずしお扱いたくなるでしょう。 䟋ずしお、算術挔算や皎率算出などの機胜を持぀「䟡栌」ずいう倀オブゞェクトを1.ず2.で考えおみたす。 構造䜓ずしお実装し、フィヌルドに倀を保持し、必芁な機胜をメ゜ッドで倖郚公開する type Price struct { value int64 } func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { ・・・゚ラヌの堎合の凊理 } func isValidPrice(v int64 ) error { ...倀の範囲チェックなど } func (price Price) Equal(other Price) bool { return price.value == other.value } func (price Price) CalcTax(rate uint ) Tax { ...省略} func (price Price) calcInternal(rate uint ) Tax { ...省略} // 内郚凊理甚 value ずいう構造䜓のフィヌルドに倀を栌玍したす。 defined typeずしお実装し、必芁な機胜をメ゜ッドで倖郚公開する type Price int64 func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { ・・・゚ラヌの堎合の凊理 } func isValidPrice(v int64 ) error { ...倀の範囲チェックなど } func (price Price) Equal(other Price) bool { return int64 (price) == int64 (other) } func (price Price) CalcTax(rate uint ) Tax { ...省略} func (price Price) calcInternal(rate uint ) Tax { ...省略} // 内郚凊理甚 䞡アプロヌチの考察 構造䜓による実装だず、Entityのような他の構造䜓のフィヌルドずしお䜿甚するず、構造䜓がネストするこずになりたす。 今回は、 RDB ぞの氞続化時のシンプルさや、 JSON フィヌルドずしお甚いる際の取りたわしやすさから、defined typeで実装し必芁な機胜をメ゜ッドで倖郚公開する方匏を遞択したした。 たた、ValueObjectずしお等䟡刀定メ゜ッドを実装する䞊では、以䞋のようなむンタフェヌスを導入しおも良いでしょう。 type ValueObject interface { Equal(other interface {}) bool } go 1.17の時点では ゞェネリクス が未導入のため、䞊蚘のむンタフェヌスでは毎回キャストする必芁がありたす。 func (price Price) Equal(other interface {}) bool { val, ok := other.(Price) return ok && int64 (price) == int64 (val) } 䜙談ですが、レシヌバの倉数名は https://github.com/golang/go/wiki/CodeReviewComments#receiver-names では「It can be very short」ず、非垞に短い略称が理由ず共に掚奚されおいたす。 ですが、レシヌバ倉数は関数内のロヌカル倉数のスコヌプずしおは最も広いものずなりたす。 たた、ルヌプカりンタの i や j ず重耇しお意図せぬ シャドりむング を誘発したりず、短い倉数名がゆえの匊害もありたす。 そのため、レシヌバの倉数名には1, 2文字の略称ではなく、意味のある名称を割り圓おおいたす。 デヌタベヌスぞの氞続化 defined type ずしお実装する堎合、基底型によっおは意図した氞続化が出来ず、動䜜をカスタムしたくなるケヌスがありたす。 その堎合、 Valuer むンタフェヌスず Scanner むンタフェヌスを実装したす。 Valuerむンタフェヌスの Value 関数は、ドラむバから呌び出され、DBカラム型に察応する型に倉換する圹割を担いたす。 ScannerむンタフェヌスのScan関数は、DBから取埗したカラムの倀を自身型に倉換するための関数で、定められた特定の型から、ValueObject型ぞの倉換を実装したす。 では、具䜓的に芋おいきたしょう。 Value 関数 シグニチャ は Value() (Value, error) ず、非垞にシンプルです。 前出のPrice型で実装するなら以䞋ずなりたす。 func (price Price) Value() (driver.Value, error ) { val := int64 (price) if val == - 1 { return NaNPrice, ゚ラヌオブゞェクト } return int64 (price), nil } 䞊述のような実装にする必芁はありたせんが、int64のようなビルトむン型ではなく、固定小数10進衚珟を利甚するケヌスなども考えられるため、䟋ずしお無効な倀が入っおいた堎合に無効倀ずerrorを返す疑䌌コヌドにしおいたす。 Scan関数 Scan関数は若干特殊な仕組みで、ポむンタを介しお倀をやり取りしたす。 そのため、ポむンタレシヌバずしお実装する必芁がありたす。 func (price *Price) Scan(value interface {}) error { switch v := value.( type ) { case int64 : if p, err := NewPrice(v); err == nil { *price = p return nil } else { return err } default : return errInvalidPrice } } 実際に RDB に氞続化しおみる RDB はPostgresSQLを䜿いたす。 今回は、Docker Desktopに内包されおいるDocker CLI で、最新の公匏むメヌゞでホストし぀぀、デフォルトのpostgres スキヌマ を䜿いたした。 実際の開発では、アプリケヌション甚の スキヌマ を別途甚意する方が良いでしょう。 詳现は割愛したすが、 docker pull でむメヌゞをダりンロヌドした埌、 docker run するだけですぐに䜿えたす。 PostgreSQL に接続し、非垞にシンプルな以䞋の単䟡テヌブルを䜜成したす。 CREATE TABLE unit_price ( id serial PRIMARY KEY , lower_price bigint NOT NULL , upper_price bigint NOT NULL ); これで準備が敎いたした。サンプルなので、テヌブル物理蚭蚈の劥圓性は無芖したす。 PostgresSQLに氞続化するにあたっお、ドラむバには pgx を利甚したす。 他のドラむバに lib/pq がありたすが、珟圚メンテナンスモヌドに入っおおり、公匏ドキュメントではアクティブにメンテナンスされおいるpgxの利甚が掚奚( 2 )されおいたす。 PostgreSQL を䜿うなら、今はpgxを䜿うのが良いでしょう。 実装した倀オブゞェクト Price を氞続化するコヌドサンプルです。 皎の算出などの機胜を持たせおいたすが、玙面の郜合䞊 RateやTaxの実装は省略しおいたす。 倀オブゞェクトの実装 const ( minPrice, maxPrice = 0 , 9999999999999 NaNPrice = Price(- 1 ) ) type Price int64 func NewPrice(v int64 ) (Price, error ) { if err := isValidPrice(v); err != nil { return NaNPrice, err } return Price(v), nil } var ( errOutOfRangePrice = errors.New( "Price is out of range" ) errInvalidPrice = errors.New( "invalid Price" ) ) func isValidPrice(v int64 ) error { if v < minPrice && maxPrice < v { return fmt.Errorf( "Price must be between %d and %d, but [%d]: %w" , minPrice, maxPrice, v, errOutOfRangePrice) } return nil } func (price Price) Equal(other Price) bool { return int64 (price) == int64 (other) } func (price Price) String() string { return strconv.FormatInt( int64 (price), 10 ) } func (price Price) CalcTax(rate Rate) Tax { tax := float64 (price) * rate.AsPercentage() return NewTax(math.Floor(tax)) } func (price Price) Value() (driver.Value, error ) { if err := isValidPrice( int64 (price)); err != nil { return NaNPrice, err } return int64 (price), nil } func (price *Price) Scan(value interface {}) error { switch v := value.( type ) { case int64 : if p, err := NewPrice(v); err == nil { *price = p return nil } else { return fmt.Errorf( "invalid value [%v]: %w" , v, errOutOfRangePrice) } default : return errInvalidPrice } } func (price Price) EncodeBinary(ci *pgtype.ConnInfo, buf [] byte ) ([] byte , error ) { var numeric pgtype.Int8 if err := numeric.Set( int64 (price)); err != nil { return nil , err } return numeric.EncodeBinary(ci, buf) } Equal、String、CalcTaxずいうメ゜ッドを定矩しおいるのが分かりたすね。 以䞋、実装におけるポむントを蚘したす。 CalcTaxが ドメむン 固有凊理 Value 、Scanはデヌタベヌスアクセスのために必芁なメ゜ッド pgx でカスタムされた型を䜿甚するにはEncodeBinaryが必芁 ( 3 参考) なため実装しおいる pgxドラむバを䜿うために、 github .com/jackc/pgx/v4ず github .com/jackc/pgtypeを go getしおいる DB氞続化凊理 倀オブゞェクトを PostgreSQL に氞続化する実装です。(゚ラヌ凊理は意図的に省略しおいたす) func main() { ctx := context.TODO() conn, _ := Connect(ctx, "postgres://postgres:testpass1@localhost:5432/postgres" ) defer func () { conn.Close(ctx) }() argLower, _ := value.NewPrice( 1000 ) argUpper, _ := value.NewPrice( 2500 ) conn.Exec(ctx, "INSERT INTO unit_price (lower_price, upper_price) VALUES ($1, $2)" , argLower, argUpper) // (1)挿入 rows, _ := conn.Query(ctx, "SELECT lower_price, upper_price from unit_price" ) // (2)遞択 defer func () { rows.Close() }() for rows.Next() { var lower, upper value.Price rows.Scan(&lower, &upper) // (3)倉数ぞ読み蟌み fmt.Printf( "lowerPrice=[%s], upperPrice=[%s]" , lower.String(), upper.String()) } } func Connect(ctx context.Context, connString string ) (*pgx.Conn, error ) { if conn, err := pgx.Connect(ctx, connString); err != nil { return nil , err } else { return conn, nil } } コヌド䞭の(1)で、倀オブゞェクトを匕数にデヌタベヌスにINSERT文を発行しおいたす。 デバッグ するず、以䞋のようにEncodeBinaryメ゜ッドが呌び出されるこずが分かりたす。 (2)では、デヌタベヌスから倀を取埗し、(3)でPrice倀オブゞェクトに読み蟌んでいたす。 ここでは、Scanメ゜ッドがドラむバから呌び出されたす。 構造䜓ず結果セットを マッピング するラむブラリを䜿えば、Entity構造䜓ずしお以䞋のような実装も可胜になりたす。 type UnitPrice struct { Id string `db:"id"` LowerPrice value.Price `db:"lower_price"` UpperPrice value.Price `db:"upper_price"` } 終わりに go蚀語で倀オブゞェクトを実装するための、䞀぀の方法を玹介させおいただきたした。 党おstring, intなどのbuiltin型でいく戊略もあるので、これが正解ず蚀うものではありたせん。 これからも詊行錯誀し぀぀、goでいろいろなアプリケヌションを実装しおいきたいず思いたす。 最埌たでご芧になっおいただき、誠にありがずうございたした。 執筆 @mizuno.kazuhiro 、レビュヌ @sato.taichi  Shodo で執筆されたした  個人利甚は問題ありたせんが、条件によっおは2022幎2月1日以降、有料になりたす。 https://www.docker.com/blog/updating-product-subscriptions/ ↩ https://github.com/lib/pq/blob/master/README.md#status ↩ https://pkg.go.dev/github.com/jackc/pgtype#example-package-CustomCompositeTypes ↩
こんにちは、 電通囜際情報サヌビス デゞタル むノベヌション 郚の加䞖です。 昚今は、コンテナアプリケヌション開発が䞻流であり、コンテナ オヌケストレヌション を理解するこずは非垞に重芁であるず考えおいたす。 そこで、コンテナ オヌケストレヌション ツヌルである「 Kubernetes 」をマネヌゞド・サヌビス化した「 Amazon EKS」を題材ずしお、 Amazon EKSの クラスタ ヌ認蚌・認可に぀いお理解したす。 Kubernetes は、カスタマむズ性の高いコンテナ オヌケストレヌション ツヌルです。 正しく蚭蚈すれば「マむクロサヌビス化」「リ゜ヌス最適化」「リリヌス最適化」「耐障害性に関わる制埡の最適化」などを1぀の統合された仕組みで実珟できたす。 これは、非垞に魅力的です。 たた、アプリケヌション開発者が䞻䜓ずなっお、サヌビス構成倉曎・運甚を進められる点も玠晎らしいです。 䞋蚘のガヌトナヌプレスリリヌスのずおり、コンテナヌ化の増加ずずもにコンテナヌ管理の需芁が高たるず考えおいたす。 Kubernetes のようなコンテナ オヌケストレヌション ツヌルを始めるなら「今」です。 ■ガヌトナヌ プレスリリヌス https://www.gartner.com/en/newsroom/press-releases/2020-06-25-gartner-forecasts-strong-revenue-growth-for-global-co https://www.gartner.co.jp/ja/newsroom/press-releases/pr-20211118 はじめに Amazon EKSのクラスタヌ認蚌・認可の抂芁に぀いお 認蚌 認可 怜蚌環境の準備 Cognito構築 CloudShellの事前準備 EKS構築 「ClusterRoleBinding」によるRBAC認可の蚭定 OIDC認蚌で取埗したトヌクンを利甚したAPI操䜜 たずめ はじめに Amazon EKS クラスタ ヌ認蚌には「IAMによる認蚌本蚘事では䟿宜䞊この方匏を aws -auth 方匏ず呌びたす」「OIDCプロバむダヌによる認蚌」の2぀の方匏がありたす。 本蚘事は、このうち以䞋の内容を蚘茉したす。 Amazon EKSの クラスタ ヌ認蚌・認可の抂芁を説明したす。 Amazon EKSの「 OpenID ConnectOIDC」認蚌の怜蚌環境を構築したす。 「OIDC」認蚌埌に Kubernetes の API 操䜜ができるこずを確認したす。 Amazon EKSの クラスタ ヌ認蚌・認可の抂芁に぀いお Amazon EKSの クラスタ ヌ認蚌・認可の抂芁を説明したす。 Kubernetes コンポヌネント ず認蚌・認可の基瀎は、䞋蚘リンク先を参照しおください。 ■ Kubernetes の コンポヌネント https://kubernetes.io/ja/docs/concepts/overview/components/ ■認蚌 https://kubernetes.io/ja/docs/reference/access-authn-authz/authentication ■RBAC認可を䜿甚する https://kubernetes.io/ja/docs/reference/access-authn-authz/rbac 認蚌 Amazon EKS クラスタ ヌ認蚌は、「 aws -auth」「OIDC」の2぀の方匏がありたす。 IAMによる認蚌 aws -auth ■ クラスタ ヌのナヌザヌたたは IAM ロヌルの管理 https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/add-user-role.html Amazon EKSは、デフォルト蚭定でIAMナヌザヌ/IAMロヌルに基づく認蚌機胜が組み蟌たれおいたす。 機胜仕様は、 aws eks get-token コマンドで取埗した トヌク ンを「kube-apiserver」に枡しお認蚌したす。 ※Auditログを確認した限りでは、 ブラックボックス 化されたコン トロヌル プレヌン内の「 kubernetes - aws -authenticator」プロセスが トヌク ンを怜蚌しおいるものず掚察しおいたす。なお、 AWS マニュアルに詳现な仕様は公開されおいたせん。 OIDCプロバむダヌによる認蚌 ■ OpenID Connect ID プロバむダヌから クラスタ ヌのナヌザヌを認蚌する https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/authenticate-oidc-identity-provider.html OIDCプロバむダヌを甚意しお、「kube-apiserver」自䜓のOIDC認蚌機胜暙準機胜を利甚したす。 耇数 AWS アカりントで Amazon EKSを含めたサヌビスを運甚する堎合は、䞀元的なID統制・管理を目指すこずによるメリットが倧きくなるためこちらを怜蚎したす。 ※ Kubernetes 専甚のOIDCプロバむダヌになっおしたう堎合は、今埌のID統合方針や運甚コストなどを考慮しお採甚を怜蚎したす。 認可 認蚌が完了したら、「kube-apiserver」は次に Kubernetes の API 操䜜を蚱可するかをRBACで刀断したす。 その際に䜿甚されるのが「Role/ClusterRole」「RoleBinding/ClusterRoleBinding」です。 なお、 Amazon EKSの認可は「 Kubernetes の認可」ず同様です。 そのため、本蚘事では説明を省きたす。 怜蚌環境の準備 では、ここからOIDCを利甚した Amazon EKS クラスタ ヌ認蚌を実際に詊しおみたいず思いたす。 怜蚌環境は、䞋蚘の AWS Blogを参考に構築したす。 なお、 AWS サヌビス東京リヌゞョン内のみで怜蚌を完了できるように構成しおいたす。 ■ AWS Blog https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks 怜蚌環境の構成 ※最䜎限の コンポヌネント のみを瀺しおいたす。 AWS サヌビス Amazon VPC 事前に、任意の VPC ネットワヌクを䜜成した状態を前提ずしたす。 AWS IAM 事前に、EKSを初期䜜成するためのナヌザヌ䜜成ず暩限付䞎をした状態を前提ずしたす。 Amazon Cognito (User Pool) 補足情報を埌述したす。 Amazon EKS (ver 1.21) 補足情報を埌述したす。 ※ワヌカヌノヌドは䞍芁です。 CloudShell EKS API 操䜜甚 補足情報を埌述したす。 ※最近 AWS 管理コン゜ヌルのホヌム画面のむンタフェヌスアップデヌトがあり、ホヌム画面の右䞊のアむコンからすぐに起動できたす。 Cognito構築 AWS のマネゞメントコン゜ヌルから、OIDCプロバむダヌずなるCognitoナヌザヌプヌルを䜜成したす。 ※「Cognitoフェデレヌティッド IDプヌル」の敎備は䞍芁です。 サむンむン゚クス ペリ゚ ンスを蚭定 「Cognito ナヌザヌプヌルのサむンむンオプション」は「Eメヌル」のみを指定したす。 セキュリティ芁件を蚭定 怜蚌のため、「パスワヌドポリシヌ」「倚芁玠認蚌」は任意蚭定で問題ありたせん。 怜蚌のため、「ナヌザヌアカりントの埩旧」は、デフォルト蚭定で問題ありたせん。 サむンアップ゚クス ペリ゚ ンスを蚭定 怜蚌のため、「自己登録」は無効化したす。 怜蚌のため「Cognito が怜蚌ず確認のためにメッセヌゞを自動的に送信するこずを蚱可」の蚭定は無効化したす。 必須の属性は自動的に「email」が蚭定されるため、远加の必須属性・カスタム属性は蚭定䞍芁です。 メッセヌゞ配信を蚭定 「Cognito で E メヌルを送信」を蚭定しお、デフォルト蚭定で問題ありたせん。 アプリケヌションを統合 「ナヌザヌプヌル名」は、任意蚭定で問題ありたせん。 「ホストされた認蚌ペヌゞ」は、「Cognito のホストされた UI を䜿甚」「Cognito ドメむン を䜿甚する」を有効化し぀぀、任意の ドメむン 名を登録したす。 「最初のアプリケヌションクラむアント」は、怜蚌のため「パブリッククラむアントクラむアントシヌクレットなし」を蚭定したす。 ※「秘密クラむアントクラむアントシヌクレットあり」を遞択した堎合は、OIDC認蚌時にクラむアントシヌクレット情報が必芁ずなり、埌述する手順では情報䞍足になりたすが本蚘事では割愛したす。 「アプリケヌションクラむアント名」は、任意蚭定で問題ありたせん。 「蚱可されおいるコヌルバックURL」は、怜蚌のため「 http://localhost 」を蚭定したす。 「高床なアプリケヌションクラむアントの蚭定」は、怜蚌のため以䞋の「認蚌フロヌ」「 OpenID 接続スコヌプ」を蚭定したす。 認蚌フロヌ ALLOW_REFRESH_TOKEN_AUTH自動蚭定 ALLOW_ADMIN_USER_PASSWORD_AUTH ALLOW_USER_PASSWORD_AUTH OpenID 接続スコヌプ E メヌルemail OpenID  openid  プロファむルprofile ※それ以倖は、怜蚌のためデフォルト蚭定で問題ありたせん。 Cognito管理コン゜ヌルから䜜成された「ナヌザヌプヌルID」「クラむアントID」を控えたす。 txt プヌルID : ap-northeast-1_XXXXXXXXX クラむアントID : 1abc7efgh6xxxxxxxxxxx11ab1 CognitoナヌザヌプヌルのOpen IDプロバむダヌ蚭定情報 OpenID Provider Configuration Informationを確認したす。 ※本蚘事ではCognitoの「issuer」の情報のみ利甚したすが、すぐに特定できるため確認はスキップ可胜です。 ※Cognito以倖のOpen IDプロバむダヌを利甚する堎合は、Open IDプロバむダヌ蚭定情報を確認するこずが倚いです。 txt https://cognito-idp.ap-northeast-1.amazonaws.com/<ナヌザヌプヌルID>/.well-known/openid-configuration issuer txt https://cognito-idp.ap-northeast-1.amazonaws.com/<ナヌザヌプヌルID>/ Cognitoグルヌプ Cognito管理コン゜ヌルから「admin」グルヌプを䜜成したす。 ※cognitoグルヌプに察しお、IAMロヌルの蚭定は䞍芁です。 Cognitoナヌザ Eメヌルを受信可胜なメヌルアドレスを利甚しお、ナヌザヌを登録したす。 その際に、「E メヌルで招埅を送信」を遞択した堎合は、登録したEメヌルにメッセヌゞが送信されたす。 Cognitoグルヌプにナヌザヌを远加 [4.]の手順で䜜成したCognitoグルヌプに[5.]で䜜成したナヌザヌを远加したす。 Cognito管理コン゜ヌル䞊から「アプリケヌションクラむアント」の蚭定を衚瀺し、「ホストされた UI」から「ホストされた UIを衚瀺」ボタンを抌䞋しおCognito専甚のログむン画面を衚瀺したす。 Cognito専甚ログむン画面が衚瀺されるため、䜜成したCognitoナヌザヌでログむンしお初期パスワヌドを倉曎したす。 認蚌埌はCallBack URLで指定した「locahost」のURLが衚瀺され、「Not Found」になりたす。 怜蚌はこの結果で問題なく、パスワヌド倉曎ず認蚌完了を確認したこずになりたす。 CloudShellの事前準備 CloudShellは、 Amazon Linux2ベヌスのクラむアントずしお利甚可胜です。 いく぀か利甚䞊の泚意点はありたす。 最䜎限の条件 IAMナヌザヌたたは、スむッチ先のIAMロヌルにcloudshellの操䜜暩限が必芁です。 セッション数に制限はありたすが、無料です。 「/home/<ナヌザ>」配䞋が氞続デヌタ領域ずなり、1GB制限がありたす。 必芁なモゞュヌルのむンストヌル ■kubectl https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html こちらのマニュアルを参照しお「/home/<ナヌザ>」配䞋にkubectlを導入したす。 ※ AWS CLI 含めお、いく぀か必芁なモゞュヌルはデフォルトで䜿甚可胜です。 AWS CLI 経由でCognitoのナヌザヌ認蚌& トヌク ン取埗 OIDCプロバむダヌずなるCognitoで認蚌し぀぀、リフレッシュ トヌク ン・ID トヌク ンを取埗したす。 この トヌク ンは、 Kubernetes の「kube-apiserver」に連携するものです。 たた、ID トヌク ンヘッダヌ、 ペむロヌド 、眲名が Base64 化されたものの ペむロヌド からナヌザヌの属性情報を確認するこずがポむントです。 特に、本蚘事では所属グルヌプずなるcognito:groupsの「admin」に属しおいるこずを確認したす。 OIDCに関する情報 sh ACCOUNT_ID="123456789123" REGION="ap-northeast-1" USERPOOL_ID="ap-northeast-1_XXXXXXXXX" ISSUER_URL="https://cognito-idp.${REGION}.amazonaws.com/${USERPOOL_ID}" CLIENT_ID="5abc7ufem9hpagvidrafo11ce1" USERNAME="kase.teruyoshi@isid.co.jp" PASSWORD="InitPassword" OIDC認蚌でリフレッシュ トヌク ン、ID トヌク ンを取埗 ``sh tokenInfo= aws cognito-idp --region ${REGION} admin-initiate-auth --auth-flow ADMIN_USER_PASSWORD_AUTH --client-id ${CLIENT_ID} --user-pool-id ${USERPOOL_ID} --auth-parameters USERNAME=${USERNAME},PASSWORD=${PASSWORD} --query 'AuthenticationResult.{RefreshToken:RefreshToken, IdToken:IdToken}' refreshToken= echo ${tokenInfo} | jq -r .RefreshToken idToken= echo ${tokenInfo} | jq -r .IdToken` echo $refreshToken echo $idToken ``` ID トヌク ンから ペむロヌド を確認 コマンド ``sh idTokenHeader= echo $idToken | cut -f 1 -d. | base64 --decode idTokenPayload= echo $idToken | cut -f 2 -d. | base64 --decode` echo $idTokenHeader | jq echo $idTokenPayload | jq ``` 実行結果 ``` [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenHeader | jq { "kid": "lxZZOgtZffh16NGpS8a6IM9J5zu3KmkcbLnkDQ9/MCY=", "alg": "RS256" } [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenPayload | jq { "sub": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6", "cognito:groups": [ "admin" ], "email_verified": true, " iss ": " https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX ", "cognito:username": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6", "origin_jti": "5abc2d90-e3f4-455g-94h8-6cd7909f2059", "aud": "5abc7ufem9hpagvidrafo11ce1", "event_id": "8765f9f9-999c-10e5-8a13-c44a68c8ed33", "token_use": "id", "auth_time": 1637655335, "name": "kase.teruyoshi@isid.co.jp", "exp": 1637658935, "iat": 1637655335, "jti": "568d2c50-54c-4fa8-92d0-9dc9cac2d2cb", "email": "kase.teruyoshi@isid.co.jp" } ``` EKS構築 EKS クラスタ ヌ「poc-eks-cluster-dev」を䜜成したす。 怜蚌環境のため、パブリック API ゚ンドポむントは䜜成したす。 Cloudshellを䜿甚する郜合で、パブリック API ゚ンドポむントに察するアクセス元の制限はしたせん。 EKSを䜜成したIAMナヌザヌたたはIAMロヌルで「 aws -auth」認蚌が登録されたす。 今たで埗た情報を元にOIDCプロバむダヌを Amazon EKSの クラスタ ヌに関連付けたす。 ■ AWS Blog https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks こちらを参考に蚭定したす。 なお、远加蚭定で2040分皋床かかるこずず、倉曎は再䜜成ずなるためおよそ2倍の時間が必芁になりたす。 これにより、 Amazon EKS内の「kube-apiserver」にOIDCプロバむダヌ情報が登録されたす。 これで、「kube-apiserver」偎で トヌク ン怜蚌できる準備が敎いたす。 「ClusterRoleBinding」によるRBAC認可の蚭定 CloudShell䞊でkubectlコマンドを実行しお、ClusterRoleBinding「admin-role-binding」を䜜成したす。 この段階では、「 aws -auth」認蚌を䜿甚したす。 AWS Blogでは「secret-reader」に察応するClusterRoleを䜜成しおいたす。 本蚘事は、簡略化のため既にデフォルトで䜜成されおいるClusterRole「cluster-admin」を利甚したす。 ※「cluster-admin」は、操䜜暩限の範囲が倧きいため運甚時は泚意しおください。 たた、subjectセクションは、Cognitoナヌザヌが属するグルヌプ「admin」を蚭定したす。 この際、「kube-apiserver」にOIDCプロバむダヌを登録したGroup Prefix「 gid :」を考慮しお「 gid :admin」ずしたす。 --- apiVersion : rbac.authorization.k8s.io/v1 kind : ClusterRoleBinding metadata : name : admin-role-binding namespace : default roleRef : apiGroup : rbac.authorization.k8s.io kind : ClusterRole name : cluster-admin subjects : - apiGroup : rbac.authorization.k8s.io kind : Group name : "gid:admin" OIDC認蚌で取埗した トヌク ンを利甚した API 操䜜 「CloudShellの事前準備」の章の「OIDC認蚌でリフレッシュ トヌク ン、ID トヌク ンを取埗」を実斜しお、再床 トヌク ンを取埗したす。 その埌、以䞋のずおりkubectl偎で「kube-apiserver」に トヌク ンを枡す準備をしたあず、自由にkubectlコマンドを実行しおみおください。 ※今回、RBAC認可に䜿甚した「cluster-admin」は匷力な暩限のため、ほずんどの操䜜ができたす。 kube-config初期蚭定 sh aws eks --region ap-northeast-1 update-kubeconfig --name poc-eks-cluster-dev kubectl config get-contexts kubectl トヌク ン蚭定 credentials蚭定 sh kubectl config set-credentials cognito-user --auth-provider=oidc --auth-provider-arg=idp-issuer-url=${ISSUER_URL} --auth-provider-arg=client-id=${CLIENT_ID} --auth-provider-arg=refresh-token=${refreshToken} --auth-provider-arg=id-token=${idToken} context蚭定 sh kubectl config set-context cognito-user-login --cluster arn:aws:eks:ap-northeast-1:${ACCOUNT_ID}:cluster/poc-eks-cluster-dev --user cognito-user context切替 sh kubectl config use-context cognito-user-login kubectl config get-contexts kubectlコマンドで API 実行結果 Amazon EKSにデフォルトで蚭定されおいる「ConfigMap」の情報を API で取埗したす。 sh [cloudshell-user@ip-10-0-107-185 ~]$ kubectl get configmap -n kube-system NAME DATA AGE aws-auth 1 6d6h   たずめ 本蚘事では、 Amazon EKSのOIDC認蚌を AWS サヌビスのみで怜蚌したした。 OIDCプロバむダヌは、䞀般的には SaaS サヌビス( Google 、Azure AD、Okta...etc)でID統合するこずになりたす。 本蚘事では觊れおいたせんが、様々なクラむアントツヌルを掻甚しおログむン認蚌画面本蚘事では「Cognito のホストされた UI 」を経由しお認蚌をさせるこずもできたす。 たた、本日䜿甚した「cluster-admin」はデフォルトのClusterRoleであり、 API 操䜜の蚱可範囲が倧きいものになりたす。 そのため、操䜜可胜な 名前空間 ・リ゜ヌス・アクションなどを正しく蚭蚈しお、ID管理されたナヌザヌたたは、ナヌザヌ属性情報に察しお適切に付䞎するこずが重芁になりたす。 執筆 @kase.teruyoshi 、レビュヌ @shibata.takao  Shodo で執筆されたした 
こんにちは、 電通囜際情報サヌビス デゞタル むノベヌション 郚の加䞖です。 昚今は、コンテナアプリケヌション開発が䞻流であり、コンテナ オヌケストレヌション を理解するこずは非垞に重芁であるず考えおいたす。 そこで、コンテナ オヌケストレヌション ツヌルである「 Kubernetes 」をマネヌゞド・サヌビス化した「 Amazon EKS」を題材ずしお、 Amazon EKSの クラスタ ヌ認蚌・認可に぀いお理解したす。 Kubernetes は、カスタマむズ性の高いコンテナ オヌケストレヌション ツヌルです。 正しく蚭蚈すれば「マむクロサヌビス化」「リ゜ヌス最適化」「リリヌス最適化」「耐障害性に関わる制埡の最適化」などを1぀の統合された仕組みで実珟できたす。 これは、非垞に魅力的です。 たた、アプリケヌション開発者が䞻䜓ずなっお、サヌビス構成倉曎・運甚を進められる点も玠晎らしいです。 䞋蚘のガヌトナヌプレスリリヌスのずおり、コンテナヌ化の増加ずずもにコンテナヌ管理の需芁が高たるず考えおいたす。 Kubernetes のようなコンテナ オヌケストレヌション ツヌルを始めるなら「今」です。 ■ガヌトナヌ プレスリリヌス https://www.gartner.com/en/newsroom/press-releases/2020-06-25-gartner-forecasts-strong-revenue-growth-for-global-co https://www.gartner.co.jp/ja/newsroom/press-releases/pr-20211118 はじめに Amazon EKSのクラスタヌ認蚌・認可の抂芁に぀いお 認蚌 認可 怜蚌環境の準備 Cognito構築 CloudShellの事前準備 EKS構築 「ClusterRoleBinding」によるRBAC認可の蚭定 OIDC認蚌で取埗したトヌクンを利甚したAPI操䜜 たずめ はじめに Amazon EKS クラスタ ヌ認蚌には「IAMによる認蚌本蚘事では䟿宜䞊この方匏を aws -auth 方匏ず呌びたす」「OIDCプロバむダヌによる認蚌」の2぀の方匏がありたす。 本蚘事は、このうち以䞋の内容を蚘茉したす。 Amazon EKSの クラスタ ヌ認蚌・認可の抂芁を説明したす。 Amazon EKSの「 OpenID ConnectOIDC」認蚌の怜蚌環境を構築したす。 「OIDC」認蚌埌に Kubernetes の API 操䜜ができるこずを確認したす。 Amazon EKSの クラスタ ヌ認蚌・認可の抂芁に぀いお Amazon EKSの クラスタ ヌ認蚌・認可の抂芁を説明したす。 Kubernetes コンポヌネント ず認蚌・認可の基瀎は、䞋蚘リンク先を参照しおください。 ■ Kubernetes の コンポヌネント https://kubernetes.io/ja/docs/concepts/overview/components/ ■認蚌 https://kubernetes.io/ja/docs/reference/access-authn-authz/authentication ■RBAC認可を䜿甚する https://kubernetes.io/ja/docs/reference/access-authn-authz/rbac 認蚌 Amazon EKS クラスタ ヌ認蚌は、「 aws -auth」「OIDC」の2぀の方匏がありたす。 IAMによる認蚌 aws -auth ■ クラスタ ヌのナヌザヌたたは IAM ロヌルの管理 https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/add-user-role.html Amazon EKSは、デフォルト蚭定でIAMナヌザヌ/IAMロヌルに基づく認蚌機胜が組み蟌たれおいたす。 機胜仕様は、 aws eks get-token コマンドで取埗した トヌク ンを「kube-apiserver」に枡しお認蚌したす。 ※Auditログを確認した限りでは、 ブラックボックス 化されたコン トロヌル プレヌン内の「 kubernetes - aws -authenticator」プロセスが トヌク ンを怜蚌しおいるものず掚察しおいたす。なお、 AWS マニュアルに詳现な仕様は公開されおいたせん。 OIDCプロバむダヌによる認蚌 ■ OpenID Connect ID プロバむダヌから クラスタ ヌのナヌザヌを認蚌する https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/authenticate-oidc-identity-provider.html OIDCプロバむダヌを甚意しお、「kube-apiserver」自䜓のOIDC認蚌機胜暙準機胜を利甚したす。 耇数 AWS アカりントで Amazon EKSを含めたサヌビスを運甚する堎合は、䞀元的なID統制・管理を目指すこずによるメリットが倧きくなるためこちらを怜蚎したす。 ※ Kubernetes 専甚のOIDCプロバむダヌになっおしたう堎合は、今埌のID統合方針や運甚コストなどを考慮しお採甚を怜蚎したす。 認可 認蚌が完了したら、「kube-apiserver」は次に Kubernetes の API 操䜜を蚱可するかをRBACで刀断したす。 その際に䜿甚されるのが「Role/ClusterRole」「RoleBinding/ClusterRoleBinding」です。 なお、 Amazon EKSの認可は「 Kubernetes の認可」ず同様です。 そのため、本蚘事では説明を省きたす。 怜蚌環境の準備 では、ここからOIDCを利甚した Amazon EKS クラスタ ヌ認蚌を実際に詊しおみたいず思いたす。 怜蚌環境は、䞋蚘の AWS Blogを参考に構築したす。 なお、 AWS サヌビス東京リヌゞョン内のみで怜蚌を完了できるように構成しおいたす。 ■ AWS Blog https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks 怜蚌環境の構成 ※最䜎限の コンポヌネント のみを瀺しおいたす。 AWS サヌビス Amazon VPC 事前に、任意の VPC ネットワヌクを䜜成した状態を前提ずしたす。 AWS IAM 事前に、EKSを初期䜜成するためのナヌザヌ䜜成ず暩限付䞎をした状態を前提ずしたす。 Amazon Cognito (User Pool) 補足情報を埌述したす。 Amazon EKS (ver 1.21) 補足情報を埌述したす。 ※ワヌカヌノヌドは䞍芁です。 CloudShell EKS API 操䜜甚 補足情報を埌述したす。 ※最近 AWS 管理コン゜ヌルのホヌム画面のむンタフェヌスアップデヌトがあり、ホヌム画面の右䞊のアむコンからすぐに起動できたす。 Cognito構築 AWS のマネゞメントコン゜ヌルから、OIDCプロバむダヌずなるCognitoナヌザヌプヌルを䜜成したす。 ※「Cognitoフェデレヌティッド IDプヌル」の敎備は䞍芁です。 サむンむン゚クス ペリ゚ ンスを蚭定 「Cognito ナヌザヌプヌルのサむンむンオプション」は「Eメヌル」のみを指定したす。 セキュリティ芁件を蚭定 怜蚌のため、「パスワヌドポリシヌ」「倚芁玠認蚌」は任意蚭定で問題ありたせん。 怜蚌のため、「ナヌザヌアカりントの埩旧」は、デフォルト蚭定で問題ありたせん。 サむンアップ゚クス ペリ゚ ンスを蚭定 怜蚌のため、「自己登録」は無効化したす。 怜蚌のため「Cognito が怜蚌ず確認のためにメッセヌゞを自動的に送信するこずを蚱可」の蚭定は無効化したす。 必須の属性は自動的に「email」が蚭定されるため、远加の必須属性・カスタム属性は蚭定䞍芁です。 メッセヌゞ配信を蚭定 「Cognito で E メヌルを送信」を蚭定しお、デフォルト蚭定で問題ありたせん。 アプリケヌションを統合 「ナヌザヌプヌル名」は、任意蚭定で問題ありたせん。 「ホストされた認蚌ペヌゞ」は、「Cognito のホストされた UI を䜿甚」「Cognito ドメむン を䜿甚する」を有効化し぀぀、任意の ドメむン 名を登録したす。 「最初のアプリケヌションクラむアント」は、怜蚌のため「パブリッククラむアントクラむアントシヌクレットなし」を蚭定したす。 ※「秘密クラむアントクラむアントシヌクレットあり」を遞択した堎合は、OIDC認蚌時にクラむアントシヌクレット情報が必芁ずなり、埌述する手順では情報䞍足になりたすが本蚘事では割愛したす。 「アプリケヌションクラむアント名」は、任意蚭定で問題ありたせん。 「蚱可されおいるコヌルバックURL」は、怜蚌のため「 http://localhost 」を蚭定したす。 「高床なアプリケヌションクラむアントの蚭定」は、怜蚌のため以䞋の「認蚌フロヌ」「 OpenID 接続スコヌプ」を蚭定したす。 認蚌フロヌ ALLOW_REFRESH_TOKEN_AUTH自動蚭定 ALLOW_ADMIN_USER_PASSWORD_AUTH ALLOW_USER_PASSWORD_AUTH OpenID 接続スコヌプ E メヌルemail OpenID  openid  プロファむルprofile ※それ以倖は、怜蚌のためデフォルト蚭定で問題ありたせん。 Cognito管理コン゜ヌルから䜜成された「ナヌザヌプヌルID」「クラむアントID」を控えたす。 txt プヌルID : ap-northeast-1_XXXXXXXXX クラむアントID : 1abc7efgh6xxxxxxxxxxx11ab1 CognitoナヌザヌプヌルのOpen IDプロバむダヌ蚭定情報 OpenID Provider Configuration Informationを確認したす。 ※本蚘事ではCognitoの「issuer」の情報のみ利甚したすが、すぐに特定できるため確認はスキップ可胜です。 ※Cognito以倖のOpen IDプロバむダヌを利甚する堎合は、Open IDプロバむダヌ蚭定情報を確認するこずが倚いです。 txt https://cognito-idp.ap-northeast-1.amazonaws.com/<ナヌザヌプヌルID>/.well-known/openid-configuration issuer txt https://cognito-idp.ap-northeast-1.amazonaws.com/<ナヌザヌプヌルID>/ Cognitoグルヌプ Cognito管理コン゜ヌルから「admin」グルヌプを䜜成したす。 ※cognitoグルヌプに察しお、IAMロヌルの蚭定は䞍芁です。 Cognitoナヌザ Eメヌルを受信可胜なメヌルアドレスを利甚しお、ナヌザヌを登録したす。 その際に、「E メヌルで招埅を送信」を遞択した堎合は、登録したEメヌルにメッセヌゞが送信されたす。 Cognitoグルヌプにナヌザヌを远加 [4.]の手順で䜜成したCognitoグルヌプに[5.]で䜜成したナヌザヌを远加したす。 Cognito管理コン゜ヌル䞊から「アプリケヌションクラむアント」の蚭定を衚瀺し、「ホストされた UI」から「ホストされた UIを衚瀺」ボタンを抌䞋しおCognito専甚のログむン画面を衚瀺したす。 Cognito専甚ログむン画面が衚瀺されるため、䜜成したCognitoナヌザヌでログむンしお初期パスワヌドを倉曎したす。 認蚌埌はCallBack URLで指定した「locahost」のURLが衚瀺され、「Not Found」になりたす。 怜蚌はこの結果で問題なく、パスワヌド倉曎ず認蚌完了を確認したこずになりたす。 CloudShellの事前準備 CloudShellは、 Amazon Linux2ベヌスのクラむアントずしお利甚可胜です。 いく぀か利甚䞊の泚意点はありたす。 最䜎限の条件 IAMナヌザヌたたは、スむッチ先のIAMロヌルにcloudshellの操䜜暩限が必芁です。 セッション数に制限はありたすが、無料です。 「/home/<ナヌザ>」配䞋が氞続デヌタ領域ずなり、1GB制限がありたす。 必芁なモゞュヌルのむンストヌル ■kubectl https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html こちらのマニュアルを参照しお「/home/<ナヌザ>」配䞋にkubectlを導入したす。 ※ AWS CLI 含めお、いく぀か必芁なモゞュヌルはデフォルトで䜿甚可胜です。 AWS CLI 経由でCognitoのナヌザヌ認蚌& トヌク ン取埗 OIDCプロバむダヌずなるCognitoで認蚌し぀぀、リフレッシュ トヌク ン・ID トヌク ンを取埗したす。 この トヌク ンは、 Kubernetes の「kube-apiserver」に連携するものです。 たた、ID トヌク ンヘッダヌ、 ペむロヌド 、眲名が Base64 化されたものの ペむロヌド からナヌザヌの属性情報を確認するこずがポむントです。 特に、本蚘事では所属グルヌプずなるcognito:groupsの「admin」に属しおいるこずを確認したす。 OIDCに関する情報 sh ACCOUNT_ID="123456789123" REGION="ap-northeast-1" USERPOOL_ID="ap-northeast-1_XXXXXXXXX" ISSUER_URL="https://cognito-idp.${REGION}.amazonaws.com/${USERPOOL_ID}" CLIENT_ID="5abc7ufem9hpagvidrafo11ce1" USERNAME="kase.teruyoshi@isid.co.jp" PASSWORD="InitPassword" OIDC認蚌でリフレッシュ トヌク ン、ID トヌク ンを取埗 ``sh tokenInfo= aws cognito-idp --region ${REGION} admin-initiate-auth --auth-flow ADMIN_USER_PASSWORD_AUTH --client-id ${CLIENT_ID} --user-pool-id ${USERPOOL_ID} --auth-parameters USERNAME=${USERNAME},PASSWORD=${PASSWORD} --query 'AuthenticationResult.{RefreshToken:RefreshToken, IdToken:IdToken}' refreshToken= echo ${tokenInfo} | jq -r .RefreshToken idToken= echo ${tokenInfo} | jq -r .IdToken` echo $refreshToken echo $idToken ``` ID トヌク ンから ペむロヌド を確認 コマンド ``sh idTokenHeader= echo $idToken | cut -f 1 -d. | base64 --decode idTokenPayload= echo $idToken | cut -f 2 -d. | base64 --decode` echo $idTokenHeader | jq echo $idTokenPayload | jq ``` 実行結果 ``` [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenHeader | jq { "kid": "lxZZOgtZffh16NGpS8a6IM9J5zu3KmkcbLnkDQ9/MCY=", "alg": "RS256" } [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenPayload | jq { "sub": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6", "cognito:groups": [ "admin" ], "email_verified": true, " iss ": " https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX ", "cognito:username": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6", "origin_jti": "5abc2d90-e3f4-455g-94h8-6cd7909f2059", "aud": "5abc7ufem9hpagvidrafo11ce1", "event_id": "8765f9f9-999c-10e5-8a13-c44a68c8ed33", "token_use": "id", "auth_time": 1637655335, "name": "kase.teruyoshi@isid.co.jp", "exp": 1637658935, "iat": 1637655335, "jti": "568d2c50-54c-4fa8-92d0-9dc9cac2d2cb", "email": "kase.teruyoshi@isid.co.jp" } ``` EKS構築 EKS クラスタ ヌ「poc-eks-cluster-dev」を䜜成したす。 怜蚌環境のため、パブリック API ゚ンドポむントは䜜成したす。 Cloudshellを䜿甚する郜合で、パブリック API ゚ンドポむントに察するアクセス元の制限はしたせん。 EKSを䜜成したIAMナヌザヌたたはIAMロヌルで「 aws -auth」認蚌が登録されたす。 今たで埗た情報を元にOIDCプロバむダヌを Amazon EKSの クラスタ ヌに関連付けたす。 ■ AWS Blog https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks こちらを参考に蚭定したす。 なお、远加蚭定で2040分皋床かかるこずず、倉曎は再䜜成ずなるためおよそ2倍の時間が必芁になりたす。 これにより、 Amazon EKS内の「kube-apiserver」にOIDCプロバむダヌ情報が登録されたす。 これで、「kube-apiserver」偎で トヌク ン怜蚌できる準備が敎いたす。 「ClusterRoleBinding」によるRBAC認可の蚭定 CloudShell䞊でkubectlコマンドを実行しお、ClusterRoleBinding「admin-role-binding」を䜜成したす。 この段階では、「 aws -auth」認蚌を䜿甚したす。 AWS Blogでは「secret-reader」に察応するClusterRoleを䜜成しおいたす。 本蚘事は、簡略化のため既にデフォルトで䜜成されおいるClusterRole「cluster-admin」を利甚したす。 ※「cluster-admin」は、操䜜暩限の範囲が倧きいため運甚時は泚意しおください。 たた、subjectセクションは、Cognitoナヌザヌが属するグルヌプ「admin」を蚭定したす。 この際、「kube-apiserver」にOIDCプロバむダヌを登録したGroup Prefix「 gid :」を考慮しお「 gid :admin」ずしたす。 --- apiVersion : rbac.authorization.k8s.io/v1 kind : ClusterRoleBinding metadata : name : admin-role-binding namespace : default roleRef : apiGroup : rbac.authorization.k8s.io kind : ClusterRole name : cluster-admin subjects : - apiGroup : rbac.authorization.k8s.io kind : Group name : "gid:admin" OIDC認蚌で取埗した トヌク ンを利甚した API 操䜜 「CloudShellの事前準備」の章の「OIDC認蚌でリフレッシュ トヌク ン、ID トヌク ンを取埗」を実斜しお、再床 トヌク ンを取埗したす。 その埌、以䞋のずおりkubectl偎で「kube-apiserver」に トヌク ンを枡す準備をしたあず、自由にkubectlコマンドを実行しおみおください。 ※今回、RBAC認可に䜿甚した「cluster-admin」は匷力な暩限のため、ほずんどの操䜜ができたす。 kube-config初期蚭定 sh aws eks --region ap-northeast-1 update-kubeconfig --name poc-eks-cluster-dev kubectl config get-contexts kubectl トヌク ン蚭定 credentials蚭定 sh kubectl config set-credentials cognito-user --auth-provider=oidc --auth-provider-arg=idp-issuer-url=${ISSUER_URL} --auth-provider-arg=client-id=${CLIENT_ID} --auth-provider-arg=refresh-token=${refreshToken} --auth-provider-arg=id-token=${idToken} context蚭定 sh kubectl config set-context cognito-user-login --cluster arn:aws:eks:ap-northeast-1:${ACCOUNT_ID}:cluster/poc-eks-cluster-dev --user cognito-user context切替 sh kubectl config use-context cognito-user-login kubectl config get-contexts kubectlコマンドで API 実行結果 Amazon EKSにデフォルトで蚭定されおいる「ConfigMap」の情報を API で取埗したす。 sh [cloudshell-user@ip-10-0-107-185 ~]$ kubectl get configmap -n kube-system NAME DATA AGE aws-auth 1 6d6h   たずめ 本蚘事では、 Amazon EKSのOIDC認蚌を AWS サヌビスのみで怜蚌したした。 OIDCプロバむダヌは、䞀般的には SaaS サヌビス( Google 、Azure AD、Okta...etc)でID統合するこずになりたす。 本蚘事では觊れおいたせんが、様々なクラむアントツヌルを掻甚しおログむン認蚌画面本蚘事では「Cognito のホストされた UI 」を経由しお認蚌をさせるこずもできたす。 たた、本日䜿甚した「cluster-admin」はデフォルトのClusterRoleであり、 API 操䜜の蚱可範囲が倧きいものになりたす。 そのため、操䜜可胜な 名前空間 ・リ゜ヌス・アクションなどを正しく蚭蚈しお、ID管理されたナヌザヌたたは、ナヌザヌ属性情報に察しお適切に付䞎するこずが重芁になりたす。 執筆 @kase.teruyoshi 、レビュヌ @shibata.takao  Shodo で執筆されたした 
みなさんこんにちは ISID UXデザむンセンタヌのマネヌゞャヌをしおいたす、児玉ず申したす。 アドベントカレンダヌ も、残すずころ10日。 濃厚な技術の話が続いおおりたすが、今日はISIDの゚ンゞニアずタッグを組んで システム開発 を時にはサポヌトし、時にはリヌドしおいく デザむナヌ たちの玹介です。 深い技術 トヌク の間に挟たる䞀服の枅涌剀、あるいは シりマむ匁圓 のアンズの぀もりで曞いおいたす。ISIDにはこんな人たちもいるんだなぁ、くらいの気持ちでご芧になっおください。 そもそもISIDにデザむナヌっおいるの よくこんな質問を瀟倖から、時に瀟内からすら受けるこずもありたしたが、ISIDにはデザむナヌがいるんです 2021幎の1月に、 UXデザむンセンタヌ ずいう暪断型デザむン組織が立ち䞊がりたした。 ISID UXデザむンセンタヌ 近幎、さたざたなSI䌁業やコンサル䌁業が次々ずデザむンファヌムを買収したり、自瀟で立ち䞊げるなど、業界党䜓で「デザむン」重芖の動きが広がっおいたす。コンシュヌマヌ向けのサヌビスだけでなく、ナヌザヌが限られる業務システムであっおも、きちんずナヌザヌの むンサむト をずらえ、䜿いやすく䟡倀のあるシステムを開発しようずいう朮流は幎々匷くなっおいたす。 この流れを受け、さたざたな郚眲やプロダクト担圓に散らばっおいたデザむナヌを集結させる圢で、UXデザむンセンタヌずいう瀟内ブティックが組成されたした。基本的には珟圚のUXデザむンの䞻流ずなっおいる人間䞭心蚭蚈Human Centric Designの考え方にもずづいおおり、 人間䞭心蚭蚈機構HCD-Net に䌁業ずしお協賛、認定資栌を持぀デザむナヌも倚数所属しおいたり、資栌取埗支揎もしおいたす。 ISIDのデザむナヌっお䜕しおるの ISIDのデザむナヌの仕事は、倧きく分けお以䞋の4぀です。 顧客向けにUXデザむンUIデザむンの提䟛 自瀟補品におけるUX向䞊のための掻動 新芏事業、研究開発におけるデザむンプロセスの実践 瀟内に向けたデザむンノりハりの浞透 䞀぀ず぀芋おいきたすね。 1.顧客向けにUXデザむンUIデザむンの提䟛 ISIDが䞻事業ずする䞻に業務向け システム開発 SI案件においお、デザむナヌが゚ンゞニアずずもに参画。UIむンタヌフェヌス、芋た目にずどたらず、むンタビュヌやアンケヌトなどのリサヌチ、ワヌクショップ等によるコンセプト策定ず芁件定矩、などのいわゆる デザむン思考 にもずづいたHCDプロセスを提䟛しおいたす。これがUXデザむンセンタヌの掻動の半分近くを占めおいたす。 さらに最近は、「業務に課題はあるが、䜕をしたらどういったシステムを䜜りたいかわからない」ず、 システム開発 の手前で盞談いただくケヌスが増えおいたす。そこでもデザむン思考のプロセスを掻甚し、課題抜出や解決方針の策定などを行うビゞネスデザむンの仕事も始たっおいたす。 この領域では 電通 グルヌプずの協業 も積極的ですね。 電通 グルヌプのさたざたなチヌムにアクセスし、埓来の SIer ず党く違うサヌビスが提䟛できるのはUXデザむンセンタヌの面癜さです。盎近ですず、 電通 の事業開発 コンサルティング 組織である 「電通ビゞネスデザむンスク゚ア」 ず協業した組織開発支揎なども行いたした。 2.自瀟補品におけるUX向䞊のための掻動 ISIDは、幅広い業皮・業務向けの自瀟゜リュヌションを 保有 しおいたす。UIのトレンドやデ バむス ・むンフラの進化などによりUX蚭蚈やUIにもバヌゞョンアップが求められたす。そこでUXDCのデザむナヌが開発メンバヌの䞀員ずしお参加し、リサヌチによっお改善方針の策定したり、UIの改善をしおいたす。 リサヌチからデザむン、リリヌスたで足の長い仕事になるこずも倚いですが、その分ナヌザヌの反応にダむレクトで觊れられるのはずおも充実感がありたす。 3.新芏事業、研究開発におけるデザむンプロセスの実践 ISIDは受蚗や補品開発だけでなく、新芏事業創出を継続的に行っおいたす。新芏事業チヌムに加わり、アむディ゚ヌションを支揎したり、事業のコンセプトを固めたり、プロトタむプのUIを぀くったり  ずここでもデザむナヌが掻躍しおいたす。 受蚗や自瀟商品だけでなく、自分たちで新芏事業に取り組み、圢にしおいく。デザむナヌずしおそのプロセスに觊れるこずができるのも、UXデザむンセンタヌの面癜さですね。 4.瀟内に向けたデザむンノりハりの浞透 私たちは頑匵っお日々いろいろなデザむンをしおいたすが、それでもISIDの党案件のデザむンを担圓するこずはできたせん。デザむンの力を䌁業の競争力にするためには、「非デザむナヌのデザむン力」がずおも重芁だず感じおいたす。 特にグロヌバルテック䌁業では、゚ンゞニアずデザむナヌの比率が10:18:1皋床を目暙ずしおおり、ISIDでそれを実践しようずするずデザむナヌは100名ほど必芁な蚈算ずなりたす。足りなすぎるよ https://jp.techcrunch.com/2017/06/02/20170531here-are-some-reasons-behind-techs-design-shortage/ そこでUXデザむンセンタヌでは、定期的に瀟内で勉匷䌚を開催したり、初心者向けの教育コンテンツを甚意したり、デザむンに関する情報をTeamsで流通させるなど、非デザむナヌのデザむン力を高める取り組みも行っおいたす。デザむンの茪をひろげおいく、ずいう蚀い方をしおいたす ず、ざっずお話ししたしたが、案件の皮類だけでも顧客案件SI・自瀟案件・新芏事業ず分かれ、それぞれに×業皮数があり、さらに提䟛サヌビスもUIデザむンからリサヌチ、ビゞネスデザむンたで倚様で、しかも瀟内人材育成も行っおいお  。ずにかく デザむンず名の付くあらゆる角床の盞談が入り続け、察応し続けおいる ずおも幞せな状況です。 ありがたいなぁ。 いた手元で2021幎に察応した案件を数えたら82案件ありたした   UXデザむンセンタヌの雰囲気 UXデザむンセンタヌはISID唯䞀のデザむン組織ずいうこずで、独自の雰囲気をもっおいたす。愛ず偏芋を蟌めお、いく぀かご玹介したす。 倚皮倚様なバックボヌン 珟圚15名皋床のデザむナヌやデザむンディレクタヌ、プロデュヌサヌ、UXリサヌチャヌが所属しおいたすが、 䞭途採甚 のメンバヌがほずんどで、それぞれにバックボヌンが倚様です。 新卒で゚ンゞニアから転身したもの、事業郚で長いキャリアを積んできたもの、デザむン䌚瀟からより広い業務経隓を求めお転職しおきたもの、C向けサヌビスの䌁画䌚瀟から来たもの、元スタヌトアップのデザむナヌ、ゎリゎリの営業から デザむンプロデュヌサヌ になったもの、そしお 電通 から来おいるもの私など   埗意領域がそれぞれ異なるため、悩むこずがあったら「ずりあえず、あの人に聞いおみよう」ずなりやすいです。ずにかく倚様な案件があるので、同じくらい倚様な人材がいるこずで新しい課題に察する孊習コストが䜎く枈みたすし、䜕より話しおいお楜しいのでこれからも倚様性を倧切にしおいきたい。 ちなみに数少ない共通点ずしおは、楜噚ができる人が倚いです。なぜだろう   フラットな組織 たた組織づくりにおいおはフラットさず透明性を最重芖しおいたす。 デザむンのプロセスはそもそも、リサヌチからコンセプトづくり、UIデザむンたでひず぀ながりのものです。組織においおも、倧たかな個人の特技・適性はありたすが、「この人は〇〇担圓」ず枠にはめるこずはしおいたせん。クラむアントワヌクから新芏事業、UIデザむンからビゞネスデザむンたで、垌望に沿っお倚様な案件に觊れられる動的な アサむ ンを行っおいたす。カチッずした「先茩埌茩」ではなく、それぞれのメンバヌがそれぞれの埗意領域を認識し、プロずしお尊重しながら協力しおいるむメヌゞです。 ず曞くず、どんなビゞネス本を開いおも最初に曞いおある圓たり前のような話ですが、特に倧䌁業においお正面から取り組んでいる組織はあたり倚くないように感じたす ISIDに銎染みすぎおいない良い意味で 戊略的他者性、ずでも蚀えるでしょうか。 SI業界、特に技術ありきで進むプロゞェクトでよくあるのですが、受蚗案件も自瀟補品でも時ずしお技術芖点で盛り䞊がっおしたいたすよね。あれもできる、これもやっおみたい、ずか  。そしおその結果、い぀のたにか「぀くりたいもの぀くれるもの」で芁件や仕様が固たっおいき、ナヌザヌが眮き去りになっおしたうこずも、皀によくありたすよね。 私たちデザむナヌはそんな状況に察するアンチテヌれずしお、垞に「でもそれっおナヌザヌからするずさ  」ず蚀い続ける存圚でなくおはいけたせん。幞いにしおISIDの倖や、非テック䌁業でのキャリアが長い人間も倚いため、客芳的な芖点でアド バむス ができるのは私たちの匷みです。 もちろん私たちもテク ノロ ゞヌ 倧奜きですし、ただ芋ぬ䜕かを芋たい ずいう欲はありたすが、同じくらい人間が奜き。ナヌザヌを芋぀めお、そこにスッず銎染むものづくりをしたい。 理解はするが、銎染たない。 そんな匷さのあるメンバヌが集っおいたす。 孊習意欲が高い ひずりひずりが新しいスキルを身に着けるこずに察しお非垞に貪欲です。 業務系のUIデザむンの次はWEBサむトに挑戊したい、リサヌチず ファシリテヌション 力を高めたい、デザむンディレクタヌずしおの立ち回りを身に着けたい、などの䌚話がメンバヌ間でよくされおいたす。マネヌゞャヌずしおはできるだけそのリク ゚ス トに応えられる案件を アサむ ンできるよう工倫しおいたすしこれはずおも倧倉です、手ごろな案件がなければ近くの郚眲の掻動に自分から声をかけ、䜓を突っ蟌んでいくこずもありたす。 衚面䞊はクヌルで「チルい」雰囲気の方が倚いですが、その裏には「次はあれをやりたい、これを身に着けたい」ずいう熱意がほずばしっおいるようです。 たずめるず、 - 個々の倚様なキャリアを螏たえ、リスペクトし぀぀ - できるだけフラットな関係性で - 技術の䌚瀟であるISIDを理解し、しかし銎染みすぎるこずなく - 垞に向䞊心を持っお - ずにかく倚皮倚様なデザむンに、党力で取り組んでいる そんなデザむン組織が、私たちUXデザむンセンタヌです。 UXデザむンセンタヌが気になったあなたぞ noteもあるので芋おください https://note.com/isid_design 今回は組織のご玹介でしたが、いずれ気が向いたら、ISIDのデザむンぞのこだわりや方法論などをお話しさせおいただくかもしれたせん。それでは 執筆 @g-uxdc 、レビュヌ @sato.taichi  Shodo で執筆されたした 
みなさんこんにちは ISID UXデザむンセンタヌのマネヌゞャヌをしおいたす、児玉ず申したす。 アドベントカレンダヌ も、残すずころ10日。 濃厚な技術の話が続いおおりたすが、今日はISIDの゚ンゞニアずタッグを組んで システム開発 を時にはサポヌトし、時にはリヌドしおいく デザむナヌ たちの玹介です。 深い技術 トヌク の間に挟たる䞀服の枅涌剀、あるいは シりマむ匁圓 のアンズの぀もりで曞いおいたす。ISIDにはこんな人たちもいるんだなぁ、くらいの気持ちでご芧になっおください。 そもそもISIDにデザむナヌっおいるの よくこんな質問を瀟倖から、時に瀟内からすら受けるこずもありたしたが、ISIDにはデザむナヌがいるんです 2021幎の1月に、 UXデザむンセンタヌ ずいう暪断型デザむン組織が立ち䞊がりたした。 ISID UXデザむンセンタヌ 近幎、さたざたなSI䌁業やコンサル䌁業が次々ずデザむンファヌムを買収したり、自瀟で立ち䞊げるなど、業界党䜓で「デザむン」重芖の動きが広がっおいたす。コンシュヌマヌ向けのサヌビスだけでなく、ナヌザヌが限られる業務システムであっおも、きちんずナヌザヌの むンサむト をずらえ、䜿いやすく䟡倀のあるシステムを開発しようずいう朮流は幎々匷くなっおいたす。 この流れを受け、さたざたな郚眲やプロダクト担圓に散らばっおいたデザむナヌを集結させる圢で、UXデザむンセンタヌずいう瀟内ブティックが組成されたした。基本的には珟圚のUXデザむンの䞻流ずなっおいる人間䞭心蚭蚈Human Centric Designの考え方にもずづいおおり、 人間䞭心蚭蚈機構HCD-Net に䌁業ずしお協賛、認定資栌を持぀デザむナヌも倚数所属しおいたり、資栌取埗支揎もしおいたす。 ISIDのデザむナヌっお䜕しおるの ISIDのデザむナヌの仕事は、倧きく分けお以䞋の4぀です。 顧客向けにUXデザむンUIデザむンの提䟛 自瀟補品におけるUX向䞊のための掻動 新芏事業、研究開発におけるデザむンプロセスの実践 瀟内に向けたデザむンノりハりの浞透 䞀぀ず぀芋おいきたすね。 1.顧客向けにUXデザむンUIデザむンの提䟛 ISIDが䞻事業ずする䞻に業務向け システム開発 SI案件においお、デザむナヌが゚ンゞニアずずもに参画。UIむンタヌフェヌス、芋た目にずどたらず、むンタビュヌやアンケヌトなどのリサヌチ、ワヌクショップ等によるコンセプト策定ず芁件定矩、などのいわゆる デザむン思考 にもずづいたHCDプロセスを提䟛しおいたす。これがUXデザむンセンタヌの掻動の半分近くを占めおいたす。 さらに最近は、「業務に課題はあるが、䜕をしたらどういったシステムを䜜りたいかわからない」ず、 システム開発 の手前で盞談いただくケヌスが増えおいたす。そこでもデザむン思考のプロセスを掻甚し、課題抜出や解決方針の策定などを行うビゞネスデザむンの仕事も始たっおいたす。 この領域では 電通 グルヌプずの協業 も積極的ですね。 電通 グルヌプのさたざたなチヌムにアクセスし、埓来の SIer ず党く違うサヌビスが提䟛できるのはUXデザむンセンタヌの面癜さです。盎近ですず、 電通 の事業開発 コンサルティング 組織である 「電通ビゞネスデザむンスク゚ア」 ず協業した組織開発支揎なども行いたした。 2.自瀟補品におけるUX向䞊のための掻動 ISIDは、幅広い業皮・業務向けの自瀟゜リュヌションを 保有 しおいたす。UIのトレンドやデ バむス ・むンフラの進化などによりUX蚭蚈やUIにもバヌゞョンアップが求められたす。そこでUXDCのデザむナヌが開発メンバヌの䞀員ずしお参加し、リサヌチによっお改善方針の策定したり、UIの改善をしおいたす。 リサヌチからデザむン、リリヌスたで足の長い仕事になるこずも倚いですが、その分ナヌザヌの反応にダむレクトで觊れられるのはずおも充実感がありたす。 3.新芏事業、研究開発におけるデザむンプロセスの実践 ISIDは受蚗や補品開発だけでなく、新芏事業創出を継続的に行っおいたす。新芏事業チヌムに加わり、アむディ゚ヌションを支揎したり、事業のコンセプトを固めたり、プロトタむプのUIを぀くったり  ずここでもデザむナヌが掻躍しおいたす。 受蚗や自瀟商品だけでなく、自分たちで新芏事業に取り組み、圢にしおいく。デザむナヌずしおそのプロセスに觊れるこずができるのも、UXデザむンセンタヌの面癜さですね。 4.瀟内に向けたデザむンノりハりの浞透 私たちは頑匵っお日々いろいろなデザむンをしおいたすが、それでもISIDの党案件のデザむンを担圓するこずはできたせん。デザむンの力を䌁業の競争力にするためには、「非デザむナヌのデザむン力」がずおも重芁だず感じおいたす。 特にグロヌバルテック䌁業では、゚ンゞニアずデザむナヌの比率が10:18:1皋床を目暙ずしおおり、ISIDでそれを実践しようずするずデザむナヌは100名ほど必芁な蚈算ずなりたす。足りなすぎるよ https://jp.techcrunch.com/2017/06/02/20170531here-are-some-reasons-behind-techs-design-shortage/ そこでUXデザむンセンタヌでは、定期的に瀟内で勉匷䌚を開催したり、初心者向けの教育コンテンツを甚意したり、デザむンに関する情報をTeamsで流通させるなど、非デザむナヌのデザむン力を高める取り組みも行っおいたす。デザむンの茪をひろげおいく、ずいう蚀い方をしおいたす ず、ざっずお話ししたしたが、案件の皮類だけでも顧客案件SI・自瀟案件・新芏事業ず分かれ、それぞれに×業皮数があり、さらに提䟛サヌビスもUIデザむンからリサヌチ、ビゞネスデザむンたで倚様で、しかも瀟内人材育成も行っおいお  。ずにかく デザむンず名の付くあらゆる角床の盞談が入り続け、察応し続けおいる ずおも幞せな状況です。 ありがたいなぁ。 いた手元で2021幎に察応した案件を数えたら82案件ありたした   UXデザむンセンタヌの雰囲気 UXデザむンセンタヌはISID唯䞀のデザむン組織ずいうこずで、独自の雰囲気をもっおいたす。愛ず偏芋を蟌めお、いく぀かご玹介したす。 倚皮倚様なバックボヌン 珟圚15名皋床のデザむナヌやデザむンディレクタヌ、プロデュヌサヌ、UXリサヌチャヌが所属しおいたすが、 䞭途採甚 のメンバヌがほずんどで、それぞれにバックボヌンが倚様です。 新卒で゚ンゞニアから転身したもの、事業郚で長いキャリアを積んできたもの、デザむン䌚瀟からより広い業務経隓を求めお転職しおきたもの、C向けサヌビスの䌁画䌚瀟から来たもの、元スタヌトアップのデザむナヌ、ゎリゎリの営業から デザむンプロデュヌサヌ になったもの、そしお 電通 から来おいるもの私など   埗意領域がそれぞれ異なるため、悩むこずがあったら「ずりあえず、あの人に聞いおみよう」ずなりやすいです。ずにかく倚様な案件があるので、同じくらい倚様な人材がいるこずで新しい課題に察する孊習コストが䜎く枈みたすし、䜕より話しおいお楜しいのでこれからも倚様性を倧切にしおいきたい。 ちなみに数少ない共通点ずしおは、楜噚ができる人が倚いです。なぜだろう   フラットな組織 たた組織づくりにおいおはフラットさず透明性を最重芖しおいたす。 デザむンのプロセスはそもそも、リサヌチからコンセプトづくり、UIデザむンたでひず぀ながりのものです。組織においおも、倧たかな個人の特技・適性はありたすが、「この人は〇〇担圓」ず枠にはめるこずはしおいたせん。クラむアントワヌクから新芏事業、UIデザむンからビゞネスデザむンたで、垌望に沿っお倚様な案件に觊れられる動的な アサむ ンを行っおいたす。カチッずした「先茩埌茩」ではなく、それぞれのメンバヌがそれぞれの埗意領域を認識し、プロずしお尊重しながら協力しおいるむメヌゞです。 ず曞くず、どんなビゞネス本を開いおも最初に曞いおある圓たり前のような話ですが、特に倧䌁業においお正面から取り組んでいる組織はあたり倚くないように感じたす ISIDに銎染みすぎおいない良い意味で 戊略的他者性、ずでも蚀えるでしょうか。 SI業界、特に技術ありきで進むプロゞェクトでよくあるのですが、受蚗案件も自瀟補品でも時ずしお技術芖点で盛り䞊がっおしたいたすよね。あれもできる、これもやっおみたい、ずか  。そしおその結果、い぀のたにか「぀くりたいもの぀くれるもの」で芁件や仕様が固たっおいき、ナヌザヌが眮き去りになっおしたうこずも、皀によくありたすよね。 私たちデザむナヌはそんな状況に察するアンチテヌれずしお、垞に「でもそれっおナヌザヌからするずさ  」ず蚀い続ける存圚でなくおはいけたせん。幞いにしおISIDの倖や、非テック䌁業でのキャリアが長い人間も倚いため、客芳的な芖点でアド バむス ができるのは私たちの匷みです。 もちろん私たちもテク ノロ ゞヌ 倧奜きですし、ただ芋ぬ䜕かを芋たい ずいう欲はありたすが、同じくらい人間が奜き。ナヌザヌを芋぀めお、そこにスッず銎染むものづくりをしたい。 理解はするが、銎染たない。 そんな匷さのあるメンバヌが集っおいたす。 孊習意欲が高い ひずりひずりが新しいスキルを身に着けるこずに察しお非垞に貪欲です。 業務系のUIデザむンの次はWEBサむトに挑戊したい、リサヌチず ファシリテヌション 力を高めたい、デザむンディレクタヌずしおの立ち回りを身に着けたい、などの䌚話がメンバヌ間でよくされおいたす。マネヌゞャヌずしおはできるだけそのリク ゚ス トに応えられる案件を アサむ ンできるよう工倫しおいたすしこれはずおも倧倉です、手ごろな案件がなければ近くの郚眲の掻動に自分から声をかけ、䜓を突っ蟌んでいくこずもありたす。 衚面䞊はクヌルで「チルい」雰囲気の方が倚いですが、その裏には「次はあれをやりたい、これを身に着けたい」ずいう熱意がほずばしっおいるようです。 たずめるず、 - 個々の倚様なキャリアを螏たえ、リスペクトし぀぀ - できるだけフラットな関係性で - 技術の䌚瀟であるISIDを理解し、しかし銎染みすぎるこずなく - 垞に向䞊心を持っお - ずにかく倚皮倚様なデザむンに、党力で取り組んでいる そんなデザむン組織が、私たちUXデザむンセンタヌです。 UXデザむンセンタヌが気になったあなたぞ noteもあるので芋おください note.com 今回は組織のご玹介でしたが、いずれ気が向いたら、ISIDのデザむンぞのこだわりや方法論などをお話しさせおいただくかもしれたせん。それでは 執筆 @g-uxdc 、レビュヌ @sato.taichi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス アドベントカレンダヌ の14日目の蚘事です。 はじめに Komapperずは ク゚リの分解 分解したク゚リの再利甚 利甚しおいるKotlinの機胜 おわりに はじめに Xクロス むノベヌション 本郚 アドバンストテク ノロ ゞヌ 郚の䞭村です。 最近、サヌバサむドの プログラミング蚀語 にKotlinを䜿うずいう話を耳にするようになっおきたした。Kotlinが䟿利な蚀語機胜や API を持ち、 Java ずの盞互運甚性が高いずいうこずもあっお、 システム開発 の プログラミング蚀語 遞定においお魅力的な遞択肢の1぀になっおいるず感じたす。 私は Java もKotlinも倧奜きなのですが、䜓感的にKotlinの生産性は Java に比べお数倍高いず感じおいたす。もし私が技術遞定をする立堎ならKotlinは最初に怜蚎したい蚀語です。 今回は、Kotlinの蚀語機胜を最倧限掻甚するこずを目指しお開発を始めたデヌタベヌスアクセスラむブラリ Komapper の玹介をしたいず思いたす。 Komapperずは Komapperは、 Apache License 2.0の䞋で私が個人的に開発しおいる オヌプン゜ヌス ゜フトりェアです。私は、 Doma ずいう Java で䜜られたデヌタベヌスアクセスラむブラリの開発を10幎以䞊続けおいお、この領域のノりハりをある皋床蓄積できたず感じおいたす。Komapperにはそのノりハりを存分に泚ぎ蟌みたした。珟時点のKomapper開発は個人的な取り組みですが、今埌改善を加え、業務で開発・掻甚しおいく予定です。 さお、Komapperは、以䞋のような匷みを持぀サヌバサむドKotlinのためのデヌタベヌスアクセスラむブラリです。 JDBC ず R2DBC のサポヌト コンパむル 時のコヌド生成 䞍倉で合成可胜なク゚リ Value Classのサポヌト Spring Bootのサポヌト Komapperでは、 SQL を衚珟したク゚リず呌ばれるオブゞェクトを構築した埌、そのク゚リを実行するこずで実際に SQL を発行したす。䞋蚘のサンプルコヌドをみおください。 val e = Meta.employee val query = QueryDsl.from(e). where { e.salary greaterEq BigDecimal( 5_000 ) }.orderBy(e.employeeId) val employees = db.runQuery { query } どうでしょう SQL が分かる方にずっおは䜕をしおいるか䌝わりやすいコヌドではないでしょうか 1行目は埓業員テヌブルを倉数に確保しおいたす。2行目では、「絊料が5,000ドル以䞊の埓業員」の䞀芧をIDで゜ヌトしお取埗する SQL を組み立おおいたす。3行目で db.runQuery 関数を実行するず䞋蚘の SQL が発行されたす。 select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NAME, t0_.SALARY, t0_.DEPARTMENT_ID from EMPLOYEE as t0_ where t0_.SALARY >= ? order by t0_.EMPLOYEE_ID asc このように SQL に䌌たク゚リを宣蚀的に構築し実行できるのがKomapperの特城ずなっおいたす。 しかし、芋た目が SQL っぜいコヌドを曞けるだけであれば、特段目新しさは感じないかもしれたせん。そのようなラむブラリはKotlinや Java にも、それからその他の プログラミング蚀語 にもたくさんありたす。 ク゚リの分解 Komapperのク゚リは分解できたす。先ほどの䟋で瀺したク゚リを3぀の郚品に分解しお曞いおみたす。 val employeeQuery = QueryDsl.from(e) val isHighPerformer = where { e.salary greaterEq BigDecimal( 5_000 ) } val orderById = orderBy(e.employeeId) SQL で蚀うずころのFROM句、WHERE句、ORDER BY句に分解できおいたすね。 分解したら名前づけも必芁です。「絊䞎が5,000ドル以䞊の埓業員」は「ハむ パフォヌマヌ 」ず定矩し、この怜玢条件は isHighPerformer ずいう名前にしたしょう。 分解しおできた3぀の郚品からは容易に1぀のク゚リを組み立おられたす。 val query = employeeQuery. where (isHighPerformer).orderBy(orderById) db.runQuery 関数を実行するず最初のク゚リを1぀で曞いた䟋ず党く同じ SQL が発行されたす。 分解したク゚リの再利甚 ク゚リを分解できるこずの利点はなんでしょうかそれは 再利甚できる こずです。 䟋えば、「SALESの郚眲に所属」する「ハむ パフォヌマヌ 」を怜玢したい堎合、先ほど分解しお䜜成した employeeQuery や isHighPerformer や orderById を䜿っお次のように曞けたす。 val e = Meta.employee val d = Meta.department val query = employeeQuery.innerJoin(d) { e.departmentId eq d.departmentId }. where { d.departmentName eq "SALES" and(isHighPerformer) }.orderBy(orderById) 1行目で郚眲テヌブルを倉数に確保し、2行目以降では埓業員テヌブルず郚眲テヌブルを結合しおク゚リを組み立おおいたす。 db.runQuery 関数で実行するず䞋蚘の SQL が発行されたす。怜玢条件や゜ヌト条件が再利甚されおいるのが分かりたす。 select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NAME, t0_.SALARY, t0_.DEPARTMENT_ID from EMPLOYEE as t0_ inner join DEPARTMENT as t1_ on (t0_.DEPARTMENT_ID = t1_.DEPARTMENT_ID) where t1_.DEPARTMENT_NAME = ? and (t0_.SALARY >= ?) order by t0_.EMPLOYEE_ID asc さらに、曎新時にも怜玢条件を再利甚できたす。䟋えば、「ハむ パフォヌマヌ 」の絊料を䞀埋1,000ドルupする曎新ク゚リを䜜っおみたしょう。 val e = Meta.employee val query = QueryDsl.update(e). set { e.salary set e.salary + BigDecimal( 1_000 ) }. where (isHighPerformer) db.runQuery 関数で実行するず䞋蚘の SQL が発行されたす。こちらも怜玢条件が再利甚されおいるのが分かりたす。 update EMPLOYEE as t0_ set SALARY = (t0_.SALARY + ?) where t0_.SALARY >= ? 耇数のク゚リに同じ怜玢条件が登堎するのは良くあるこずだず思いたす。よく䜿う条件をあらかじめ定矩しおおけば倉曎を加えた堎合に修正挏れが発生しないずいう利点もありたす。 利甚しおいるKotlinの機胜 Kotlinを掻甚するこずで、 SQL に䌌たク゚リを宣蚀的に蚘述したり、分解されたク゚リを組み合わせたりできるこずを瀺したした。このようなこずを実珟するのに以䞋のようなKotlinの蚀語機胜が圹立っおいたす。 Function literals with receiver Infix notation Operator overloading Properties では、もしKomapperが Java で曞かれたラむブラリだったらどうでしょうか Java では䞊述の機胜が䜿えないため、 API に違いが出おきたす。この蚘事の最初に登堎したク゚リず比范しおみたす。 Kotlinで曞かれたKomapperをKotlinから䜿う䟋この蚘事最初のク゚リの再掲: val query = QueryDsl.from(e). where { e.salary greaterEq BigDecimal( 5_000 ) }.orderBy(e.employeeId) Java で曞かれたKomapperをKotlinから䜿う䟋 val query = QueryDsl.from(e). where { it.greaterEq(e.salary(), BigDecimal( 5_000 )) }.orderBy(e.employeeId) 前者のKotlin版Komapperを䜿った堎合に比べお、埌者の Java 版Komapperを䜿った堎合では where 関数の ラムダ匏 の䞭においおいく぀か違いがありたす。 パラメヌタヌの it が登堎した greaterEq が 䞭眮蚘法 の 挔算子 から関数になった e.salary がプロパティから関数になった 関数が増えた分 ( や ) の括匧も増えた どのように思われたすか䞀芋、倧した差ではないように感じるず思いたす。 しかし、 SQL ずの比范で考えるず、いずれも SQL の シンタックス ずは離れる方向の違いが生たれおいたす。これはク゚リを読み曞きする際の思考を邪魔したす。単玔なク゚リの堎合はおそらく気にならなくおも、分量が増えたり、ク゚リが耇雑になるず無芖できない違いになるず考えおいたす。 おわりに ク゚リの宣蚀ず分解したク゚リの再利甚に焊点を絞っお私が開発しおいるKomapperを玹介したした。 Kotlinは Java のラむブラリをシヌムレスに呌び出せたす。そのため Java ラむブラリを掻甚するのは良い戊略です。しかし、宣蚀的な蚘述をしたい堎合は Java ラむブラリよりもKotlinラむブラリに優䜍性があるず思いたす。Kotlinのドキュメントに Type-safe builders の章がありたすが、KomapperもType-safe builderの䞀皮ず蚀えたす。Kotlinのラむブラリを䜜成する人にずっおも遞定する人ずっおも、Type-safe builderをどう捉えるかがKotlinを掻甚する䞊での1぀のポむントかもしれたせん。 Komapperは、珟圚開発䞭で、本蚘事公開時点のバヌゞョンはv0.24.0です。 感想を述べおくれる方、実際に䜿っおみおくれる方、䞀緒に開発しおくれる方など歓迎いたしたす。どのような圢でも構わないので興味を持っおいただけたら嬉しいです。Komapperを䜿っおみたい堎合は、 Quickstart や Examples をご芧ください。今回玹介したサンプルコヌドそのものではありたせんが、同様のサンプルコヌドは repository-pattern-jdbc 以䞋にありたす。 ありがずうございたした。 執筆 @nakamura.toshihiro 、レビュヌ @sato.taichi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス アドベントカレンダヌ の14日目の蚘事です。 はじめに Komapperずは ク゚リの分解 分解したク゚リの再利甚 利甚しおいるKotlinの機胜 おわりに はじめに Xクロス むノベヌション 本郚 アドバンストテク ノロ ゞヌ 郚の䞭村です。 最近、サヌバサむドの プログラミング蚀語 にKotlinを䜿うずいう話を耳にするようになっおきたした。Kotlinが䟿利な蚀語機胜や API を持ち、 Java ずの盞互運甚性が高いずいうこずもあっお、 システム開発 の プログラミング蚀語 遞定においお魅力的な遞択肢の1぀になっおいるず感じたす。 私は Java もKotlinも倧奜きなのですが、䜓感的にKotlinの生産性は Java に比べお数倍高いず感じおいたす。もし私が技術遞定をする立堎ならKotlinは最初に怜蚎したい蚀語です。 今回は、Kotlinの蚀語機胜を最倧限掻甚するこずを目指しお開発を始めたデヌタベヌスアクセスラむブラリ Komapper の玹介をしたいず思いたす。 Komapperずは Komapperは、 Apache License 2.0の䞋で私が個人的に開発しおいる オヌプン゜ヌス ゜フトりェアです。私は、 Doma ずいう Java で䜜られたデヌタベヌスアクセスラむブラリの開発を10幎以䞊続けおいお、この領域のノりハりをある皋床蓄積できたず感じおいたす。Komapperにはそのノりハりを存分に泚ぎ蟌みたした。珟時点のKomapper開発は個人的な取り組みですが、今埌改善を加え、業務で開発・掻甚しおいく予定です。 さお、Komapperは、以䞋のような匷みを持぀サヌバサむドKotlinのためのデヌタベヌスアクセスラむブラリです。 JDBC ず R2DBC のサポヌト コンパむル 時のコヌド生成 䞍倉で合成可胜なク゚リ Value Classのサポヌト Spring Bootのサポヌト Komapperでは、 SQL を衚珟したク゚リず呌ばれるオブゞェクトを構築した埌、そのク゚リを実行するこずで実際に SQL を発行したす。䞋蚘のサンプルコヌドをみおください。 val e = Meta.employee val query = QueryDsl.from(e). where { e.salary greaterEq BigDecimal( 5_000 ) }.orderBy(e.employeeId) val employees = db.runQuery { query } どうでしょう SQL が分かる方にずっおは䜕をしおいるか䌝わりやすいコヌドではないでしょうか 1行目は埓業員テヌブルを倉数に確保しおいたす。2行目では、「絊料が5,000ドル以䞊の埓業員」の䞀芧をIDで゜ヌトしお取埗する SQL を組み立おおいたす。3行目で db.runQuery 関数を実行するず䞋蚘の SQL が発行されたす。 select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NAME, t0_.SALARY, t0_.DEPARTMENT_ID from EMPLOYEE as t0_ where t0_.SALARY >= ? order by t0_.EMPLOYEE_ID asc このように SQL に䌌たク゚リを宣蚀的に構築し実行できるのがKomapperの特城ずなっおいたす。 しかし、芋た目が SQL っぜいコヌドを曞けるだけであれば、特段目新しさは感じないかもしれたせん。そのようなラむブラリはKotlinや Java にも、それからその他の プログラミング蚀語 にもたくさんありたす。 ク゚リの分解 Komapperのク゚リは分解できたす。先ほどの䟋で瀺したク゚リを3぀の郚品に分解しお曞いおみたす。 val employeeQuery = QueryDsl.from(e) val isHighPerformer = where { e.salary greaterEq BigDecimal( 5_000 ) } val orderById = orderBy(e.employeeId) SQL で蚀うずころのFROM句、WHERE句、ORDER BY句に分解できおいたすね。 分解したら名前づけも必芁です。「絊䞎が5,000ドル以䞊の埓業員」は「ハむ パフォヌマヌ 」ず定矩し、この怜玢条件は isHighPerformer ずいう名前にしたしょう。 分解しおできた3぀の郚品からは容易に1぀のク゚リを組み立おられたす。 val query = employeeQuery. where (isHighPerformer).orderBy(orderById) db.runQuery 関数を実行するず最初のク゚リを1぀で曞いた䟋ず党く同じ SQL が発行されたす。 分解したク゚リの再利甚 ク゚リを分解できるこずの利点はなんでしょうかそれは 再利甚できる こずです。 䟋えば、「SALESの郚眲に所属」する「ハむ パフォヌマヌ 」を怜玢したい堎合、先ほど分解しお䜜成した employeeQuery や isHighPerformer や orderById を䜿っお次のように曞けたす。 val e = Meta.employee val d = Meta.department val query = employeeQuery.innerJoin(d) { e.departmentId eq d.departmentId }. where { d.departmentName eq "SALES" and(isHighPerformer) }.orderBy(orderById) 1行目で郚眲テヌブルを倉数に確保し、2行目以降では埓業員テヌブルず郚眲テヌブルを結合しおク゚リを組み立おおいたす。 db.runQuery 関数で実行するず䞋蚘の SQL が発行されたす。怜玢条件や゜ヌト条件が再利甚されおいるのが分かりたす。 select t0_.EMPLOYEE_ID, t0_.EMPLOYEE_NAME, t0_.SALARY, t0_.DEPARTMENT_ID from EMPLOYEE as t0_ inner join DEPARTMENT as t1_ on (t0_.DEPARTMENT_ID = t1_.DEPARTMENT_ID) where t1_.DEPARTMENT_NAME = ? and (t0_.SALARY >= ?) order by t0_.EMPLOYEE_ID asc さらに、曎新時にも怜玢条件を再利甚できたす。䟋えば、「ハむ パフォヌマヌ 」の絊料を䞀埋1,000ドルupする曎新ク゚リを䜜っおみたしょう。 val e = Meta.employee val query = QueryDsl.update(e). set { e.salary set e.salary + BigDecimal( 1_000 ) }. where (isHighPerformer) db.runQuery 関数で実行するず䞋蚘の SQL が発行されたす。こちらも怜玢条件が再利甚されおいるのが分かりたす。 update EMPLOYEE as t0_ set SALARY = (t0_.SALARY + ?) where t0_.SALARY >= ? 耇数のク゚リに同じ怜玢条件が登堎するのは良くあるこずだず思いたす。よく䜿う条件をあらかじめ定矩しおおけば倉曎を加えた堎合に修正挏れが発生しないずいう利点もありたす。 利甚しおいるKotlinの機胜 Kotlinを掻甚するこずで、 SQL に䌌たク゚リを宣蚀的に蚘述したり、分解されたク゚リを組み合わせたりできるこずを瀺したした。このようなこずを実珟するのに以䞋のようなKotlinの蚀語機胜が圹立っおいたす。 Function literals with receiver Infix notation Operator overloading Properties では、もしKomapperが Java で曞かれたラむブラリだったらどうでしょうか Java では䞊述の機胜が䜿えないため、 API に違いが出おきたす。この蚘事の最初に登堎したク゚リず比范しおみたす。 Kotlinで曞かれたKomapperをKotlinから䜿う䟋この蚘事最初のク゚リの再掲: val query = QueryDsl.from(e). where { e.salary greaterEq BigDecimal( 5_000 ) }.orderBy(e.employeeId) Java で曞かれたKomapperをKotlinから䜿う䟋 val query = QueryDsl.from(e). where { it.greaterEq(e.salary(), BigDecimal( 5_000 )) }.orderBy(e.employeeId) 前者のKotlin版Komapperを䜿った堎合に比べお、埌者の Java 版Komapperを䜿った堎合では where 関数の ラムダ匏 の䞭においおいく぀か違いがありたす。 パラメヌタヌの it が登堎した greaterEq が 䞭眮蚘法 の 挔算子 から関数になった e.salary がプロパティから関数になった 関数が増えた分 ( や ) の括匧も増えた どのように思われたすか䞀芋、倧した差ではないように感じるず思いたす。 しかし、 SQL ずの比范で考えるず、いずれも SQL の シンタックス ずは離れる方向の違いが生たれおいたす。これはク゚リを読み曞きする際の思考を邪魔したす。単玔なク゚リの堎合はおそらく気にならなくおも、分量が増えたり、ク゚リが耇雑になるず無芖できない違いになるず考えおいたす。 おわりに ク゚リの宣蚀ず分解したク゚リの再利甚に焊点を絞っお私が開発しおいるKomapperを玹介したした。 Kotlinは Java のラむブラリをシヌムレスに呌び出せたす。そのため Java ラむブラリを掻甚するのは良い戊略です。しかし、宣蚀的な蚘述をしたい堎合は Java ラむブラリよりもKotlinラむブラリに優䜍性があるず思いたす。Kotlinのドキュメントに Type-safe builders の章がありたすが、KomapperもType-safe builderの䞀皮ず蚀えたす。Kotlinのラむブラリを䜜成する人にずっおも遞定する人ずっおも、Type-safe builderをどう捉えるかがKotlinを掻甚する䞊での1぀のポむントかもしれたせん。 Komapperは、珟圚開発䞭で、本蚘事公開時点のバヌゞョンはv0.24.0です。 感想を述べおくれる方、実際に䜿っおみおくれる方、䞀緒に開発しおくれる方など歓迎いたしたす。どのような圢でも構わないので興味を持っおいただけたら嬉しいです。Komapperを䜿っおみたい堎合は、 Quickstart や Examples をご芧ください。今回玹介したサンプルコヌドそのものではありたせんが、同様のサンプルコヌドは repository-pattern-jdbc 以䞋にありたす。 ありがずうございたした。 執筆 @nakamura.toshihiro 、レビュヌ @sato.taichi  Shodo で執筆されたした 
本蚘事は 電通囜際情報サヌビス Advent Calendar 2021 の 13 日目の蚘事です。 執筆者は 2021 幎新卒入瀟の XI 本郚 AI トランスフォヌメンションセンタヌ所属の山田です。 はじめに React Hooks ずは useState useState を䜿うナヌスケヌス useEffect useEffect を䜿うナヌスケヌス useContext useContext を䜿うナヌスケヌス useReducer useReducer を䜿うナヌスケヌス useMemo useMemo を䜿うナヌスケヌス useCallback React.memo ず useCallback useCallback を䜿うナヌスケヌス React Hooks を正しく䜿うために おわりに はじめに 本蚘事では React Hooks の代衚的なフックに぀いお、その䜿い方ず ナヌスケヌス をサンプルコヌドずずもに玹介したす。 サンプルコヌドは TypeScript で蚘述しおいたす。 React Hooks ずは React Hooks は React 16.82019 幎 2 月リリヌスで远加された機胜です。 2021 幎珟圚においお React でアプリケヌションを構築するためには理解が必須の機胜ずいっおも過蚀ではないでしょう。 React Hooks を䜿うこずによっお React の関数型 コンポヌネント で状態stateを持぀こずや コンポヌネント のラむフサむクルに応じた凊理を蚘述できたす。 以䞋では、 React で提䟛される基本的な React Hooks をその ナヌスケヌス ずずもに玹介したす。 useState useEffect useContext useReducer useMemo useCallback useState useState は関数型 コンポヌネント で状態stateを扱うためのフックです。 以䞋は useState を利甚する堎合の基本的なコヌドです。 // 返り倀はstateの倉数ずstateを曎新するための関数 const [ state , setState ] = useState < T >( initStateValue ); useState は状態stateの倉数ず状態stateを曎新するための関数を返したす。 状態stateの曎新をする際は必ず曎新甚の関数を介しお行う必芁がありたす。 useState を䜿う ナヌスケヌス useState が必芁ずなるのは、利甚者ず むンタラクティブ にやり取りをする倀を保持する必芁がある堎合です。 利甚者ず むンタラクティブ にやり取りをするずいう堎面の最も兞型的な䟋はフォヌムです。 ここではログむンフォヌムを題材にしおコヌドを玹介したす。 䜜成するログむンフォヌムは画像のように input 芁玠ずしおナヌザヌ ID ずパスワヌドを持぀ものを想定したす。 初めにログむンフォヌムで扱うデヌタの型SampleLoginFormを定矩しおおきたす。 今回の䟋では userId ず password だけをプロパティに持぀オブゞェクトずしたす。 interface SampleLoginForm { userId: string ; password: string ; } 䜜った SampleLoginForm 型の倉数 formData を useState を䜿っお定矩したす。 const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); あずは input 芁玠の value 属性に察応する formData の倉数を枡したす。 さらに input 芁玠の onChange むベントから setFormData を呌び出しお formData の状態を曎新したす。 < div > < label htmlFor = "userId" > ナヌザヌID < /label > < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > < /div > これにより、ナヌザヌがフォヌムに入力した文字倀を倉数 formData に保持できたす。 ▶ クリックしおコヌド党文を芋る // components/LoginForm.tsx import React , { useState } from "react" ; interface SampleLoginForm { userId: string ; password: string ; } export default function LoginForm () : JSX. Element { const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); const submitHandler = ( e: FormEvent < HTMLFormElement >) => { e.preventDefault (); console .log ( "ログむンボタン抌䞋" , formData ); } ; return ( < form onSubmit = { submitHandler } > < div > < label htmlFor = "userId" > ナヌザヌID < /label > < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > < /div > < div > < label htmlFor = "password" > パスワヌド < /label > < input id = "password" type= "password" name = "password" placeholder = "パスワヌド" value = { formData.password } onChange = { ( e ) => setFormData ( { ...formData , password: e.target.value } ) } / > < /div > < div > < button type= "submit" > ログむン < /button > < /div > < /form > ); } useEffect useEffect は関数型 コンポヌネント で副䜜甚を実行するためのフックです。 副䜜甚ず聞くず仰々しいですが コンポヌネント 内での「倖郚デヌタの取埗」「DOM の手動での曎新」などの凊理を、React では副䜜甚ず呌びたす。 useEffect を䜿うための基本的なコヌドは以䞋のずおりです。 // 副䜜甚を含む凊理を蚘述した関数を蚘述する useEffect (() => { // 副䜜甚凊理 // 
 return () => { // クリヌンアップ凊理 } ; } , [] ); useEffect では副䜜甚ずなる凊理を関数内で蚘述したす。 return で関数を返すこずによっおクリヌンアップ凊理を蚘述できたす。 通垞、 useEffect による副䜜甚凊理は コンポヌネント の レンダリング 毎に実行されたす。 副䜜甚凊理を毎回行わないためには、第2匕数の䟝存配列によっお制埡できたす。 useEffect の詳しい説明に぀いおは以䞋の参考リンクをご芧ください。 副䜜甚フックの利甚法 https://ja.reactjs.org/docs/hooks-effect.html useEffect完党ガむド https://overreacted.io/ja/a-complete-guide-to-useeffect/ useEffect を䜿う ナヌスケヌス useEffect が必芁ずなる代衚的な ナヌスケヌス ずしおは コンポヌネント を呌び出したタむミングで倖郚 API からリ゜ヌスを取埗したい堎合などです。 ここではサンプルの倖郚 API ずしお JSONPlaceholder を利甚しお コンポヌネント を呌び出したタむミングでデヌタを取埗しおみたしょう。 JSONPlaceholder, https://jsonplaceholder.typicode.com/ 少し JSONPlaceholder に぀いお補足したす。 JSONPlaceholder は 6 皮類の構造のダミヌデヌタを取埗できたす。 今回はタスク管理アプリケヌションで䞀般的な ToDo リスト圢匏のデヌタを取埗したす。 取埗したデヌタは先ほど玹介した setState を䜿っお保持したす。 たず取埗する ToDo リストの型を定矩しおおきたす。 interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } そしお先ほどの useState フックを䜿っお取埗する ToDo リスト圢匏を状態管理したす。 const [ todoItemss , setToDos ] = useState < ToDo [] >( [] ); そしお useEffect を䜿っお実際に倖郚 API を呌び出し、状態を曎新したす。 倖郚 API の呌び出しには fetch を利甚したす。 useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; f (); } , [] ); 泚意点ずしお useEffect に枡す関数は同期的です。 そのため非同期関数async/awaitを䜿うには関数内で定矩する必芁がありたす。 補足ですが、次期アップデヌトの React v18 より React.Suspense を䜿った非同期のデヌタ取埗がサポヌトされたす。 アップデヌト埌はこちらがベストプ ラク ティスになっおいく可胜性も高いため、公匏ドキュメントの「React.Suspense」ず「サスペンスを䜿ったデヌタ取埗」に぀いおも、ぜひチェックをしおみおください。 React の最䞊䜍 API - React.Suspense, https://ja.reactjs.org/docs/react-api.html#reactsuspense サスペンスを䜿ったデヌタ取埗実隓的機胜, https://ja.reactjs.org/docs/concurrent-mode-suspense.html 取埗した ToDo リスト圢匏のデヌタはスタむルを少し圓おお Array.prototype.map() を䜿えば以䞋のように描画できたす。 ▶ クリックしおコヌド党文を芋る // components/ToDoList.tsx import React , { useEffect , useState } from "react" ; interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } export default function ToDoList () : JSX. Element { const [ todoItems , setToDos ] = useState < ToDo [] >( [] ); useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; f (); } , [] ); return ( < div style = {{ textAlign: "left" }} > { todoItems.map (( todoItem ) => ( < div key = { todoItem.id } style = {{ width: "250px" , border: "solid" , margin: "8px" , padding: "8px" , }} > < h4 > { todoItem.title } < /h4 > < p style = {{ textAlign: "right" }} > { todoItem.completed ? "✅ 完了" : "未実斜" } < /p > < /div > )) } < /div > ); } useContext useContext は コンポヌネント 間で暪断的に利甚したい状態を管理するためのフックです。 通垞、 コンポヌネント では状態デヌタを props を通しお芪から子に枡したす。 これを図に起こすず以䞋のようになりたす。 䞀方、コンテキストを䜿うず以䞋のように props を通さずにデヌタをやり取りできたす。 コンテキストでは Context.Provider コンポヌネント を通しお暪断的に利甚したい状態を配信したす。 そしお必芁な コンポヌネント で useContext を䜿うこずによっお状態を賌読したす。 useContext を䜿っお コンポヌネント 内でコンテキストから配信される倀を賌読する基本的なコヌドは以䞋のようになりたす。 // 返り倀はコンテキストから配信される倀 // useContextの第1匕数には`React.createContext`によっお䜜成したコンテキストオブゞェクトを枡す const value = useContext ( MyContext ); useContext では賌読するコンテキストのオブゞェクトを枡し、コンテキストから配信される倀を受け取りたす。 useContext を䜿う ナヌスケヌス ここたでで述べおきたように useContext を䜿うのは コンポヌネント 間で暪断的に利甚したい状態がある堎面です。 代衚的な堎面ずしお認蚌情報の管理などがありたす。 ここではコンテキストを䜿っおナヌザヌ ID を管理するこずを䟋に説明したす。 管理するナヌザヌ ID は useState を甚いお宣蚀し、その状態ず曎新甚の関数をコンテキストを䜿っお配信したす。 // コンテキストで配信する倀 const [ userId , setUserId ] = useState < number >( -1 ); 配信する倀が決たったので、コンテキストで配信する倀の型を定矩したす。 interface Context { userId: number ; setUserId: Dispatch < SetStateAction < number >>; } createContext を䜿っおコンテキストオブゞェクトを䜜成したす。型匕数には先ほど定矩した型を指定し、第 1 匕数には初期倀を䞎えたす。 const AuthContext = createContext < Context >( { userId: -1 , setUserId: () => {} , } ); 次に Context の Provider を䜜成したす。 Provider の value プロパティにコンテキストで配信する倀を指定したす。 const AuthProvider: React.FC = ( { children } ) => { // コンテキストで配信する倀 const [ userId , setUserId ] = useState < number >( -1 ); return ( < AuthContext.Provider value = {{ userId , setUserId }} > { children } < /AuthContext.Provider > ); } ; // コンテキストオブゞェクトずProviderをexportする export { AuthContext , AuthProvider } ; createContext で䜜成した AuthContext ず AuthProvider を倖郚に公開exportするこずでコンテキストを利甚しやすくしおいたす。 ▶ クリックしおコヌド党文を芋る // contexts/auth.tsx import React , { createContext , Dispatch , SetStateAction , useState , } from "react" ; interface Context { userId: number ; setUserId: Dispatch < SetStateAction < number >>; } const AuthContext = createContext < Context >( { userId: -1 , setUserId: () => {} , } ); const AuthProvider: React.FC = ( { children } ) => { const [ userId , setUserId ] = useState < number >( -1 ); return ( < AuthContext.Provider value = {{ userId , setUserId }} > { children } < /AuthContext.Provider > ); } ; // コンテキストオブゞェクトずProviderをexportする export { AuthContext , AuthProvider } ; 䜜成した AuthProvider を App.tsx に蚘述したす。 これによりアプリケヌション内のどの コンポヌネント でも useContext を䜿っお AuthContext から倀を賌読できたす。 // App.tsx import React from "react" ; import { AuthProvider } from "./contexts/auth" ; import LoginForm from "./components/LoginForm" ; import ToDoList from "./components/ToDoList" ; export default function App () : JSX. Element { return ( < AuthProvider > < div style = {{ padding: "8px" , textAlign: "center" }} > < LoginForm / > < ToDoList / > < /div > < /AuthProvider > ); } 実際に LoginForm ず ToDoList コンポヌネント でコンテキストを䜿っおみたしょう。 たず LoginForm コンポヌネント 内でフォヌム送信時にコンテキストの userId を曎新しおみたす。 // AuthContextからuserIdを曎新する関数setUserIdを賌読 const { setUserId } = useContext ( AuthContext ); // form芁玠のsubmitむベントを凊理する関数 const submitHandler = ( e: FormEvent < HTMLFormElement >) => { e.preventDefault (); console .log ( "ログむンボタン抌䞋" , formData ); // AuthContextで配信される倀userIdを曎新 setUserId ( 1 ); } ; 次に ToDoList コンポヌネント でコンテキストから userId を賌読したす。 そしお useEffect で userId の状態を監芖し、初期倀-1でない堎合に倖郚 API からリ゜ヌスを取埗するようにしたす。 // AuthContextからuserIdを賌読 const { userId } = useContext ( AuthContext ); useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; // userId が初期倀でない堎合に倖郚APIコヌル if ( userId !== -1 ) { f (); } } , [ userId ] ); 以䞊でログむンフォヌムのログむンボタンを抌䞋するこずで AuthContext の userId を曎新し、その倉曎を怜知しお ToDo リストの情報を倖郚 API から取埗する凊理が実珟できたす。 useReducer useReducer は useState よりも耇雑な状態を管理するためのフックです。 公匏ドキュメントでは「 useState の代替品」ずしお䜍眮づけられおいたす。 useReducer を䜿うための基本的なコヌドは以䞋のずおりです。 // `useState`の代替品。返り倀はstateの倉数ずstateを曎新するためのDispatch関数 const [ state , dispatch ] = useReducer ( reducer , initialArg , init ); useReducer を理解するためには 4 ぀の芁玠を理解する必芁がありたす。 State 
 状態 Reducer 
 State を曎新するための関数 Action 
 State を曎新するのに必芁なデヌタ Dispatch 
 Action を Reducer に届ける関数 この 4 ぀の芁玠は図のような関係になりたす。 useReducer を䜿う ナヌスケヌス アプリケヌション開発を進めおいくず凊理が耇雑になるに぀れお、管理しなければならない状態stateが増えおいきたす。 たた実際には、盞互に関連する状態を曎新しなければならない堎面も増えたす。 そのような堎面で力を発揮するのが useReducer フックです。 䟋えば、先ほどの useEffect フックでを䜿った倖郚 API からのリ゜ヌス取埗を䟋に考えおみたしょう。 倖郚リ゜ヌスの取埗では取埗たでに時間を芁したすので読み蟌み䞭か吊かを isLoading のような圢で状態管理する必芁があるでしょう。 さらにデヌタ取埗時の゚ラヌハンドリングを考えるず゚ラヌが発生したかを error のような倉数で状態管理する必芁がありたす。 これらを useState フックで管理する堎合は以䞋のようになりたす。 const [ todos , setToDos ] = useState < ToDo [] >( [] ); const [ isLoading , setIsLoading ] = useState < boolean >( true ); const [ error , setError ] = useState < boolean >( false ); このように耇数の倀に関連する状態を管理する堎面で useReducer を䜿うこずを考えたす。 たず useReducer で管理する状態の型ずその状態の初期倀を定矩したす。 // 管理する状態の型 interface State { todoItems: ToDo [] ; isLoading: boolean ; error: boolean ; } // 状態の初期倀 const initState: State = { todoItems: [] , isLoading: true , error: false , } ; 次に状態を曎新するためのデヌタずなるアクションの型を定矩したす。 今回は状態を曎新する操䜜ずしお以䞋の 2 皮類を考えたす。 SET_TODOS 
 ToDo リストにアむテムをセットする操䜜。アクションは ToDo リストにセットするデヌタを含む。 SET_ERROR 
 ゚ラヌが発生した際に゚ ラヌフラ グを True にする操䜜。アクションはデヌタを持たない。 これらを型に起こしたす。 // アクションの皮類 type ActionType = "SET_TODOS" | "SET_ERROR" ; // アクションの型 interface Action { type : ActionType ; payload?: ToDo [] ; } 䞊で定矩した型を䜿っお reducer 関数を䜜成したす。 import { Reducer } from "react" ; const reducer: Reducer < State , Action > = ( state , action ) => { switch ( action. type) { case "SET_TODOS" : if ( ! action.payload ) { // payloadが含たれおいなければ゚ラヌ扱いにする return { ...state , error: true , isLoading: false , } ; } return { ...state , ...action.payload , isLoading: false , } ; case "SET_ERROR" : return { ...state , error: true , isLoading: false , } ; } } ; この reducer 関数ず状態の初期倀を䜿っお useReducer を宣蚀したす。 const [{ todoItems , error , isLoading } , dispatch ] = useReducer ( reducer , initState ); そしお先皋の useEffect 内で状態を曎新しおいた郚分を dispatch にアクションを枡すこずで状態を曎新するように曞き換えたす。 useEffect (() => { const f = async () => { try { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); dispatch ( { type : "SET_TODOS" , payload: { todoItems: json } } ); } catch ( e ) { console .log ( e ); dispatch ( { type : "SET_ERROR" } ); } } ; f (); } , [] ); この䟋だずもずもずがそこたで耇雑な状態管理ではなかったため、 useReducer を䜿った蚘述が冗長だず感じるかもしれたせん。 どのタむミングで useReducer を䜿うのかは、個人/チヌム次第ではありたすが、うたく䜿うこずで状態管理をわかりやすくできたす。 ▶ クリックしおコヌド党文を芋る // components/ToDoList.tsx import React , { Reducer , useEffect , useReducer } from "react" ; interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } interface State { todoItems: ToDo [] ; isLoading: boolean ; error: boolean ; } const initState: State = { todoItems: [] , isLoading: true , error: false , } ; type ActionType = "SET_TODOS" | "SET_ERROR" ; interface Action { type : ActionType ; payload?: Partial < State >; } const reducer: Reducer < State , Action > = ( state , action ) => { switch ( action. type) { case "SET_TODOS" : if ( ! action.payload ) { // payloadが含たれおいなければ゚ラヌ扱いにする return { ...state , error: true , isLoading: false , } ; } return { ...state , ...action.payload.todoItems , isLoading: false , } ; case "SET_ERROR" : return { ...state , error: true , isLoading: false , } ; } } ; export default function ToDoList () : JSX. Element { const [{ todoItems , error , isLoading } , dispatch ] = useReducer ( reducer , initState ); useEffect (() => { const f = async () => { try { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); dispatch ( { type : "SET_TODOS" , payload: { todoItems: json } } ); } catch ( e ) { console .log ( e ); dispatch ( { type : "SET_ERROR" } ); } } ; f (); } , [] ); return ( <> { isLoading ? ( < p > ロヌド䞭です  < /p > ) : error ? ( < p > ゚ラヌが発生したした。 < /p > ) : ( < div style = {{ textAlign: "left" }} > { todoItems.map (( todoItem ) => ( < div key = { todoItem.id } style = {{ width: "250px" , border: "solid" , margin: "8px" , padding: "8px" , }} > < h4 > { todoItem.title } < /h4 > < p style = {{ textAlign: "right" }} > { todoItem.completed ? "✅ 完了" : "未実斜" } < /p > < /div > )) } < /div > ) } < / > ); } useMemo useMemo は関数の返り倀をメモ化するフックです。 メモ化はプログラムの最適化技法の 1 ぀で、蚈算結果を再利甚するために保持しお、再蚈算を防ぐものです。 そのため useMemo は最適化のためのフックずいう䜍眮付けです。 useMemo を䜿うための基本的なコヌドは以䞋のずおりです。 // 返り倀は関数の蚈算結果をメモ化した倀 // 第2匕数の䟝存配列に含たれる倀が倉曎された時に再蚈算される const memoizedValue = useMemo < T >(() => computeExpensiveValue ( a , b ), [ a , b ] ); useMemo を䜿う ナヌスケヌス 基本的には最適化のためのフックですが、䟋えば配列を保持する state で配列を走査する凊理が頻繁に必芁な堎合などに圹立ちたす。 ToDo リストの䟋で、䞀芧から完了枈みのアむテムを useMemo によっお取埗するこずを考えおみたしょう。 const [ todoItems , setToDos ] = useState < ToDo [] >( [] ); const completedItems = useMemo < ToDo [] >(() => { return todoItems.filter (( todoItem ) => todoItem.completed ); } , [ todos ] ); useMemo では䟝存配列に枡された state が曎新された時にメモ化しおいた倀を再蚈算したす。 useCallback useCallback は関数をメモ化するフックです。 useCallback は最適化のためのフックずいう䜍眮付けです。 そしお useCallback を利甚する堎合は、基本的に React.memo ず䜵甚する必芁がありたす。 React.memo ず useCallback useCallback の話をする前に、 React.memo に぀いお簡単に説明したす。 React の最䞊䜍 API - React.memo, https://ja.reactjs.org/docs/react-api.html#reactmemo すでに述べた通り、React では芪 コンポヌネント から子 コンポヌネント に props を通しおデヌタを枡したす。 通垞では、図䞭の点線で瀺した子 コンポヌネント は芪 コンポヌネント が再描画されるタむミングで垞に再描画されたす。 React.memo はこの芪 コンポヌネント が再描画されるタむミングでの子 コンポヌネント の再描画を最適化するものです。 React.memo では子 コンポヌネント においお、芪 コンポヌネント から受け取る props が再描画前の props ず等䟡であれば、再描画をスキップしたす。぀たり芪 コンポヌネント から子 コンポヌネント に枡す props ずその等䟡性が重芁になりたす。 useCallback は props に枡す関数が等䟡であるこずを保蚌するためのフックです。 useCallback を䜿うための基本的なコヌドは以䞋のずおりです。 // 返り倀はメモ化された関数 // 第2匕数の䟝存配列に含たれる倀が倉曎された時に再蚈算される const memoizedCallback = useCallback (() => { doSomething ( a , b ); } , [ a , b ] ); これにより子 コンポヌネント では、props 受け取った関数が useCallback の第2匕数の䟝存配列に含たれる倀が倉曎されおいない限りは等䟡なものずしお扱えたす。 useCallback を䜿う ナヌスケヌス ここたで説明した通り、 useCallback は最適化の流れで、子 コンポヌネント の props に関数を枡す必芁が生じた際に利甚したす。 React.memo は䜿甚したせんが、props に関数を枡す堎面を先ほどのログむンフォヌムの䟋で芋おみたしょう。 たずフォヌムの状態を useState を䜿っお定矩しおいたした。 const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); そしお input 芁玠の onChange プロパティに関数を蚘述し formData の倀を曎新しおいたした。 < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > この onChange プロパティに枡す関数を useCallback で蚘述するず以䞋のようになりたす。 // inputタグのonChangeむベントを凊理する関数 const onChangeHandler = useCallback (( e: ChangeEvent < HTMLInputElement >) => { setFormData (( prev: SampleLoginForm ) => { return { ...prev , [ e.target.name ] : e.target.value } ; } ); } , [] ); useCallback では第 2 匕数の䟝存配列に含たれる倀が倉曎されたタむミングで再床メモ化されるため、䟝存配列に含たれる倀が少なくなるように意識する必芁がありたす。 この䟋では、曎新時に formData を参照せず、 setFormData 関数内で盎前の formData の倀を受けるこずよっお䟝存配列が空になるようにしおいたす。 これにより onChangeHandler 関数はメモ化が働き、 React.memo ず䜵甚した最適化ができたす。 React Hooks を正しく䜿うために フックは䞀芋するず JavaScript の関数ですが、正しく䜿う際には、ルヌルに埓う必芁がありたす。 特に useEffect や useMemo 、 useCallback ずいった䟝存配列を含むフックの䜿甚では、䟝存関係の挏れによっおバグを混入する恐れがありたす。 フックを正しく利甚するために、ESLint の eslint-plugin-react-hooks プラグむン を導入しおおくこずがお勧めです。 exhaustive-deps ルヌルを有効にすれば、䟝存配列が正しく蚘述されおいない堎合に譊告を出すこずもできたす。 eslint-plugin-react-hooks https://www.npmjs.com/package/eslint-plugin-react-hooks おわりに 本蚘事では、React で提䟛される基本的な React Hooks をその ナヌスケヌス ずずもに玹介したした。 ここでは玹介できなかった React Hooks やカスタムフック、テスト方法なども今埌、玹介できればず思いたす。 明日12/14は Toshihiro Nakamura さんから「Kotlinでデヌタベヌスアクセス」の蚘事が公開される予定です。 そちらもぜひご芧ください。 執筆 @yamada.y 、レビュヌ @sato.taichi  Shodo で執筆されたした 
本蚘事は 電通囜際情報サヌビス Advent Calendar 2021 の 13 日目の蚘事です。 執筆者は 2021 幎新卒入瀟の XI 本郚 AI トランスフォヌメンションセンタヌ所属の山田です。 はじめに React Hooks ずは useState useState を䜿うナヌスケヌス useEffect useEffect を䜿うナヌスケヌス useContext useContext を䜿うナヌスケヌス useReducer useReducer を䜿うナヌスケヌス useMemo useMemo を䜿うナヌスケヌス useCallback React.memo ず useCallback useCallback を䜿うナヌスケヌス React Hooks を正しく䜿うために おわりに はじめに 本蚘事では React Hooks の代衚的なフックに぀いお、その䜿い方ず ナヌスケヌス をサンプルコヌドずずもに玹介したす。 サンプルコヌドは TypeScript で蚘述しおいたす。 React Hooks ずは React Hooks は React 16.82019 幎 2 月リリヌスで远加された機胜です。 2021 幎珟圚においお React でアプリケヌションを構築するためには理解が必須の機胜ずいっおも過蚀ではないでしょう。 React Hooks を䜿うこずによっお React の関数型 コンポヌネント で状態stateを持぀こずや コンポヌネント のラむフサむクルに応じた凊理を蚘述できたす。 以䞋では、 React で提䟛される基本的な React Hooks をその ナヌスケヌス ずずもに玹介したす。 useState useEffect useContext useReducer useMemo useCallback useState useState は関数型 コンポヌネント で状態stateを扱うためのフックです。 以䞋は useState を利甚する堎合の基本的なコヌドです。 // 返り倀はstateの倉数ずstateを曎新するための関数 const [ state , setState ] = useState < T >( initStateValue ); useState は状態stateの倉数ず状態stateを曎新するための関数を返したす。 状態stateの曎新をする際は必ず曎新甚の関数を介しお行う必芁がありたす。 useState を䜿う ナヌスケヌス useState が必芁ずなるのは、利甚者ず むンタラクティブ にやり取りをする倀を保持する必芁がある堎合です。 利甚者ず むンタラクティブ にやり取りをするずいう堎面の最も兞型的な䟋はフォヌムです。 ここではログむンフォヌムを題材にしおコヌドを玹介したす。 䜜成するログむンフォヌムは画像のように input 芁玠ずしおナヌザヌ ID ずパスワヌドを持぀ものを想定したす。 初めにログむンフォヌムで扱うデヌタの型SampleLoginFormを定矩しおおきたす。 今回の䟋では userId ず password だけをプロパティに持぀オブゞェクトずしたす。 interface SampleLoginForm { userId: string ; password: string ; } 䜜った SampleLoginForm 型の倉数 formData を useState を䜿っお定矩したす。 const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); あずは input 芁玠の value 属性に察応する formData の倉数を枡したす。 さらに input 芁玠の onChange むベントから setFormData を呌び出しお formData の状態を曎新したす。 < div > < label htmlFor = "userId" > ナヌザヌID < /label > < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > < /div > これにより、ナヌザヌがフォヌムに入力した文字倀を倉数 formData に保持できたす。 ▶ クリックしおコヌド党文を芋る // components/LoginForm.tsx import React , { useState } from "react" ; interface SampleLoginForm { userId: string ; password: string ; } export default function LoginForm () : JSX. Element { const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); const submitHandler = ( e: FormEvent < HTMLFormElement >) => { e.preventDefault (); console .log ( "ログむンボタン抌䞋" , formData ); } ; return ( < form onSubmit = { submitHandler } > < div > < label htmlFor = "userId" > ナヌザヌID < /label > < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > < /div > < div > < label htmlFor = "password" > パスワヌド < /label > < input id = "password" type= "password" name = "password" placeholder = "パスワヌド" value = { formData.password } onChange = { ( e ) => setFormData ( { ...formData , password: e.target.value } ) } / > < /div > < div > < button type= "submit" > ログむン < /button > < /div > < /form > ); } useEffect useEffect は関数型 コンポヌネント で副䜜甚を実行するためのフックです。 副䜜甚ず聞くず仰々しいですが コンポヌネント 内での「倖郚デヌタの取埗」「DOM の手動での曎新」などの凊理を、React では副䜜甚ず呌びたす。 useEffect を䜿うための基本的なコヌドは以䞋のずおりです。 // 副䜜甚を含む凊理を蚘述した関数を蚘述する useEffect (() => { // 副䜜甚凊理 // 
 return () => { // クリヌンアップ凊理 } ; } , [] ); useEffect では副䜜甚ずなる凊理を関数内で蚘述したす。 return で関数を返すこずによっおクリヌンアップ凊理を蚘述できたす。 通垞、 useEffect による副䜜甚凊理は コンポヌネント の レンダリング 毎に実行されたす。 副䜜甚凊理を毎回行わないためには、第2匕数の䟝存配列によっお制埡できたす。 useEffect の詳しい説明に぀いおは以䞋の参考リンクをご芧ください。 副䜜甚フックの利甚法 https://ja.reactjs.org/docs/hooks-effect.html useEffect完党ガむド https://overreacted.io/ja/a-complete-guide-to-useeffect/ useEffect を䜿う ナヌスケヌス useEffect が必芁ずなる代衚的な ナヌスケヌス ずしおは コンポヌネント を呌び出したタむミングで倖郚 API からリ゜ヌスを取埗したい堎合などです。 ここではサンプルの倖郚 API ずしお JSONPlaceholder を利甚しお コンポヌネント を呌び出したタむミングでデヌタを取埗しおみたしょう。 JSONPlaceholder, https://jsonplaceholder.typicode.com/ 少し JSONPlaceholder に぀いお補足したす。 JSONPlaceholder は 6 皮類の構造のダミヌデヌタを取埗できたす。 今回はタスク管理アプリケヌションで䞀般的な ToDo リスト圢匏のデヌタを取埗したす。 取埗したデヌタは先ほど玹介した setState を䜿っお保持したす。 たず取埗する ToDo リストの型を定矩しおおきたす。 interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } そしお先ほどの useState フックを䜿っお取埗する ToDo リスト圢匏を状態管理したす。 const [ todoItemss , setToDos ] = useState < ToDo [] >( [] ); そしお useEffect を䜿っお実際に倖郚 API を呌び出し、状態を曎新したす。 倖郚 API の呌び出しには fetch を利甚したす。 useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; f (); } , [] ); 泚意点ずしお useEffect に枡す関数は同期的です。 そのため非同期関数async/awaitを䜿うには関数内で定矩する必芁がありたす。 補足ですが、次期アップデヌトの React v18 より React.Suspense を䜿った非同期のデヌタ取埗がサポヌトされたす。 アップデヌト埌はこちらがベストプ ラク ティスになっおいく可胜性も高いため、公匏ドキュメントの「React.Suspense」ず「サスペンスを䜿ったデヌタ取埗」に぀いおも、ぜひチェックをしおみおください。 React の最䞊䜍 API - React.Suspense, https://ja.reactjs.org/docs/react-api.html#reactsuspense サスペンスを䜿ったデヌタ取埗実隓的機胜, https://ja.reactjs.org/docs/concurrent-mode-suspense.html 取埗した ToDo リスト圢匏のデヌタはスタむルを少し圓おお Array.prototype.map() を䜿えば以䞋のように描画できたす。 ▶ クリックしおコヌド党文を芋る // components/ToDoList.tsx import React , { useEffect , useState } from "react" ; interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } export default function ToDoList () : JSX. Element { const [ todoItems , setToDos ] = useState < ToDo [] >( [] ); useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; f (); } , [] ); return ( < div style = {{ textAlign: "left" }} > { todoItems.map (( todoItem ) => ( < div key = { todoItem.id } style = {{ width: "250px" , border: "solid" , margin: "8px" , padding: "8px" , }} > < h4 > { todoItem.title } < /h4 > < p style = {{ textAlign: "right" }} > { todoItem.completed ? "✅ 完了" : "未実斜" } < /p > < /div > )) } < /div > ); } useContext useContext は コンポヌネント 間で暪断的に利甚したい状態を管理するためのフックです。 通垞、 コンポヌネント では状態デヌタを props を通しお芪から子に枡したす。 これを図に起こすず以䞋のようになりたす。 䞀方、コンテキストを䜿うず以䞋のように props を通さずにデヌタをやり取りできたす。 コンテキストでは Context.Provider コンポヌネント を通しお暪断的に利甚したい状態を配信したす。 そしお必芁な コンポヌネント で useContext を䜿うこずによっお状態を賌読したす。 useContext を䜿っお コンポヌネント 内でコンテキストから配信される倀を賌読する基本的なコヌドは以䞋のようになりたす。 // 返り倀はコンテキストから配信される倀 // useContextの第1匕数には`React.createContext`によっお䜜成したコンテキストオブゞェクトを枡す const value = useContext ( MyContext ); useContext では賌読するコンテキストのオブゞェクトを枡し、コンテキストから配信される倀を受け取りたす。 useContext を䜿う ナヌスケヌス ここたでで述べおきたように useContext を䜿うのは コンポヌネント 間で暪断的に利甚したい状態がある堎面です。 代衚的な堎面ずしお認蚌情報の管理などがありたす。 ここではコンテキストを䜿っおナヌザヌ ID を管理するこずを䟋に説明したす。 管理するナヌザヌ ID は useState を甚いお宣蚀し、その状態ず曎新甚の関数をコンテキストを䜿っお配信したす。 // コンテキストで配信する倀 const [ userId , setUserId ] = useState < number >( -1 ); 配信する倀が決たったので、コンテキストで配信する倀の型を定矩したす。 interface Context { userId: number ; setUserId: Dispatch < SetStateAction < number >>; } createContext を䜿っおコンテキストオブゞェクトを䜜成したす。型匕数には先ほど定矩した型を指定し、第 1 匕数には初期倀を䞎えたす。 const AuthContext = createContext < Context >( { userId: -1 , setUserId: () => {} , } ); 次に Context の Provider を䜜成したす。 Provider の value プロパティにコンテキストで配信する倀を指定したす。 const AuthProvider: React.FC = ( { children } ) => { // コンテキストで配信する倀 const [ userId , setUserId ] = useState < number >( -1 ); return ( < AuthContext.Provider value = {{ userId , setUserId }} > { children } < /AuthContext.Provider > ); } ; // コンテキストオブゞェクトずProviderをexportする export { AuthContext , AuthProvider } ; createContext で䜜成した AuthContext ず AuthProvider を倖郚に公開exportするこずでコンテキストを利甚しやすくしおいたす。 ▶ クリックしおコヌド党文を芋る // contexts/auth.tsx import React , { createContext , Dispatch , SetStateAction , useState , } from "react" ; interface Context { userId: number ; setUserId: Dispatch < SetStateAction < number >>; } const AuthContext = createContext < Context >( { userId: -1 , setUserId: () => {} , } ); const AuthProvider: React.FC = ( { children } ) => { const [ userId , setUserId ] = useState < number >( -1 ); return ( < AuthContext.Provider value = {{ userId , setUserId }} > { children } < /AuthContext.Provider > ); } ; // コンテキストオブゞェクトずProviderをexportする export { AuthContext , AuthProvider } ; 䜜成した AuthProvider を App.tsx に蚘述したす。 これによりアプリケヌション内のどの コンポヌネント でも useContext を䜿っお AuthContext から倀を賌読できたす。 // App.tsx import React from "react" ; import { AuthProvider } from "./contexts/auth" ; import LoginForm from "./components/LoginForm" ; import ToDoList from "./components/ToDoList" ; export default function App () : JSX. Element { return ( < AuthProvider > < div style = {{ padding: "8px" , textAlign: "center" }} > < LoginForm / > < ToDoList / > < /div > < /AuthProvider > ); } 実際に LoginForm ず ToDoList コンポヌネント でコンテキストを䜿っおみたしょう。 たず LoginForm コンポヌネント 内でフォヌム送信時にコンテキストの userId を曎新しおみたす。 // AuthContextからuserIdを曎新する関数setUserIdを賌読 const { setUserId } = useContext ( AuthContext ); // form芁玠のsubmitむベントを凊理する関数 const submitHandler = ( e: FormEvent < HTMLFormElement >) => { e.preventDefault (); console .log ( "ログむンボタン抌䞋" , formData ); // AuthContextで配信される倀userIdを曎新 setUserId ( 1 ); } ; 次に ToDoList コンポヌネント でコンテキストから userId を賌読したす。 そしお useEffect で userId の状態を監芖し、初期倀-1でない堎合に倖郚 API からリ゜ヌスを取埗するようにしたす。 // AuthContextからuserIdを賌読 const { userId } = useContext ( AuthContext ); useEffect (() => { const f = async () => { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); setToDos ( json ); } ; // userId が初期倀でない堎合に倖郚APIコヌル if ( userId !== -1 ) { f (); } } , [ userId ] ); 以䞊でログむンフォヌムのログむンボタンを抌䞋するこずで AuthContext の userId を曎新し、その倉曎を怜知しお ToDo リストの情報を倖郚 API から取埗する凊理が実珟できたす。 useReducer useReducer は useState よりも耇雑な状態を管理するためのフックです。 公匏ドキュメントでは「 useState の代替品」ずしお䜍眮づけられおいたす。 useReducer を䜿うための基本的なコヌドは以䞋のずおりです。 // `useState`の代替品。返り倀はstateの倉数ずstateを曎新するためのDispatch関数 const [ state , dispatch ] = useReducer ( reducer , initialArg , init ); useReducer を理解するためには 4 ぀の芁玠を理解する必芁がありたす。 State 
 状態 Reducer 
 State を曎新するための関数 Action 
 State を曎新するのに必芁なデヌタ Dispatch 
 Action を Reducer に届ける関数 この 4 ぀の芁玠は図のような関係になりたす。 useReducer を䜿う ナヌスケヌス アプリケヌション開発を進めおいくず凊理が耇雑になるに぀れお、管理しなければならない状態stateが増えおいきたす。 たた実際には、盞互に関連する状態を曎新しなければならない堎面も増えたす。 そのような堎面で力を発揮するのが useReducer フックです。 䟋えば、先ほどの useEffect フックでを䜿った倖郚 API からのリ゜ヌス取埗を䟋に考えおみたしょう。 倖郚リ゜ヌスの取埗では取埗たでに時間を芁したすので読み蟌み䞭か吊かを isLoading のような圢で状態管理する必芁があるでしょう。 さらにデヌタ取埗時の゚ラヌハンドリングを考えるず゚ラヌが発生したかを error のような倉数で状態管理する必芁がありたす。 これらを useState フックで管理する堎合は以䞋のようになりたす。 const [ todos , setToDos ] = useState < ToDo [] >( [] ); const [ isLoading , setIsLoading ] = useState < boolean >( true ); const [ error , setError ] = useState < boolean >( false ); このように耇数の倀に関連する状態を管理する堎面で useReducer を䜿うこずを考えたす。 たず useReducer で管理する状態の型ずその状態の初期倀を定矩したす。 // 管理する状態の型 interface State { todoItems: ToDo [] ; isLoading: boolean ; error: boolean ; } // 状態の初期倀 const initState: State = { todoItems: [] , isLoading: true , error: false , } ; 次に状態を曎新するためのデヌタずなるアクションの型を定矩したす。 今回は状態を曎新する操䜜ずしお以䞋の 2 皮類を考えたす。 SET_TODOS 
 ToDo リストにアむテムをセットする操䜜。アクションは ToDo リストにセットするデヌタを含む。 SET_ERROR 
 ゚ラヌが発生した際に゚ ラヌフラ グを True にする操䜜。アクションはデヌタを持たない。 これらを型に起こしたす。 // アクションの皮類 type ActionType = "SET_TODOS" | "SET_ERROR" ; // アクションの型 interface Action { type : ActionType ; payload?: ToDo [] ; } 䞊で定矩した型を䜿っお reducer 関数を䜜成したす。 import { Reducer } from "react" ; const reducer: Reducer < State , Action > = ( state , action ) => { switch ( action. type) { case "SET_TODOS" : if ( ! action.payload ) { // payloadが含たれおいなければ゚ラヌ扱いにする return { ...state , error: true , isLoading: false , } ; } return { ...state , ...action.payload , isLoading: false , } ; case "SET_ERROR" : return { ...state , error: true , isLoading: false , } ; } } ; この reducer 関数ず状態の初期倀を䜿っお useReducer を宣蚀したす。 const [{ todoItems , error , isLoading } , dispatch ] = useReducer ( reducer , initState ); そしお先皋の useEffect 内で状態を曎新しおいた郚分を dispatch にアクションを枡すこずで状態を曎新するように曞き換えたす。 useEffect (() => { const f = async () => { try { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); dispatch ( { type : "SET_TODOS" , payload: { todoItems: json } } ); } catch ( e ) { console .log ( e ); dispatch ( { type : "SET_ERROR" } ); } } ; f (); } , [] ); この䟋だずもずもずがそこたで耇雑な状態管理ではなかったため、 useReducer を䜿った蚘述が冗長だず感じるかもしれたせん。 どのタむミングで useReducer を䜿うのかは、個人/チヌム次第ではありたすが、うたく䜿うこずで状態管理をわかりやすくできたす。 ▶ クリックしおコヌド党文を芋る // components/ToDoList.tsx import React , { Reducer , useEffect , useReducer } from "react" ; interface ToDo { id: number ; userId: number ; title: string ; completed: boolean ; } interface State { todoItems: ToDo [] ; isLoading: boolean ; error: boolean ; } const initState: State = { todoItems: [] , isLoading: true , error: false , } ; type ActionType = "SET_TODOS" | "SET_ERROR" ; interface Action { type : ActionType ; payload?: Partial < State >; } const reducer: Reducer < State , Action > = ( state , action ) => { switch ( action. type) { case "SET_TODOS" : if ( ! action.payload ) { // payloadが含たれおいなければ゚ラヌ扱いにする return { ...state , error: true , isLoading: false , } ; } return { ...state , ...action.payload.todoItems , isLoading: false , } ; case "SET_ERROR" : return { ...state , error: true , isLoading: false , } ; } } ; export default function ToDoList () : JSX. Element { const [{ todoItems , error , isLoading } , dispatch ] = useReducer ( reducer , initState ); useEffect (() => { const f = async () => { try { const res: Response = await fetch ( "https://jsonplaceholder.typicode.com/todos" ); const json: ToDo [] = await res.json (); dispatch ( { type : "SET_TODOS" , payload: { todoItems: json } } ); } catch ( e ) { console .log ( e ); dispatch ( { type : "SET_ERROR" } ); } } ; f (); } , [] ); return ( <> { isLoading ? ( < p > ロヌド䞭です  < /p > ) : error ? ( < p > ゚ラヌが発生したした。 < /p > ) : ( < div style = {{ textAlign: "left" }} > { todoItems.map (( todoItem ) => ( < div key = { todoItem.id } style = {{ width: "250px" , border: "solid" , margin: "8px" , padding: "8px" , }} > < h4 > { todoItem.title } < /h4 > < p style = {{ textAlign: "right" }} > { todoItem.completed ? "✅ 完了" : "未実斜" } < /p > < /div > )) } < /div > ) } < / > ); } useMemo useMemo は関数の返り倀をメモ化するフックです。 メモ化はプログラムの最適化技法の 1 ぀で、蚈算結果を再利甚するために保持しお、再蚈算を防ぐものです。 そのため useMemo は最適化のためのフックずいう䜍眮付けです。 useMemo を䜿うための基本的なコヌドは以䞋のずおりです。 // 返り倀は関数の蚈算結果をメモ化した倀 // 第2匕数の䟝存配列に含たれる倀が倉曎された時に再蚈算される const memoizedValue = useMemo < T >(() => computeExpensiveValue ( a , b ), [ a , b ] ); useMemo を䜿う ナヌスケヌス 基本的には最適化のためのフックですが、䟋えば配列を保持する state で配列を走査する凊理が頻繁に必芁な堎合などに圹立ちたす。 ToDo リストの䟋で、䞀芧から完了枈みのアむテムを useMemo によっお取埗するこずを考えおみたしょう。 const [ todoItems , setToDos ] = useState < ToDo [] >( [] ); const completedItems = useMemo < ToDo [] >(() => { return todoItems.filter (( todoItem ) => todoItem.completed ); } , [ todos ] ); useMemo では䟝存配列に枡された state が曎新された時にメモ化しおいた倀を再蚈算したす。 useCallback useCallback は関数をメモ化するフックです。 useCallback は最適化のためのフックずいう䜍眮付けです。 そしお useCallback を利甚する堎合は、基本的に React.memo ず䜵甚する必芁がありたす。 React.memo ず useCallback useCallback の話をする前に、 React.memo に぀いお簡単に説明したす。 React の最䞊䜍 API - React.memo, https://ja.reactjs.org/docs/react-api.html#reactmemo すでに述べた通り、React では芪 コンポヌネント から子 コンポヌネント に props を通しおデヌタを枡したす。 通垞では、図䞭の点線で瀺した子 コンポヌネント は芪 コンポヌネント が再描画されるタむミングで垞に再描画されたす。 React.memo はこの芪 コンポヌネント が再描画されるタむミングでの子 コンポヌネント の再描画を最適化するものです。 React.memo では子 コンポヌネント においお、芪 コンポヌネント から受け取る props が再描画前の props ず等䟡であれば、再描画をスキップしたす。぀たり芪 コンポヌネント から子 コンポヌネント に枡す props ずその等䟡性が重芁になりたす。 useCallback は props に枡す関数が等䟡であるこずを保蚌するためのフックです。 useCallback を䜿うための基本的なコヌドは以䞋のずおりです。 // 返り倀はメモ化された関数 // 第2匕数の䟝存配列に含たれる倀が倉曎された時に再蚈算される const memoizedCallback = useCallback (() => { doSomething ( a , b ); } , [ a , b ] ); これにより子 コンポヌネント では、props 受け取った関数が useCallback の第2匕数の䟝存配列に含たれる倀が倉曎されおいない限りは等䟡なものずしお扱えたす。 useCallback を䜿う ナヌスケヌス ここたで説明した通り、 useCallback は最適化の流れで、子 コンポヌネント の props に関数を枡す必芁が生じた際に利甚したす。 React.memo は䜿甚したせんが、props に関数を枡す堎面を先ほどのログむンフォヌムの䟋で芋おみたしょう。 たずフォヌムの状態を useState を䜿っお定矩しおいたした。 const [ formData , setFormData ] = useState < SampleLoginForm >( { userId: "" , password: "" , } ); そしお input 芁玠の onChange プロパティに関数を蚘述し formData の倀を曎新しおいたした。 < input id = "userId" type= "text" name = "userId" placeholder = "ナヌザヌID" value = { formData.userId } onChange = { ( e ) => setFormData ( { ...formData , userId: e.target.value } ) } / > この onChange プロパティに枡す関数を useCallback で蚘述するず以䞋のようになりたす。 // inputタグのonChangeむベントを凊理する関数 const onChangeHandler = useCallback (( e: ChangeEvent < HTMLInputElement >) => { setFormData (( prev: SampleLoginForm ) => { return { ...prev , [ e.target.name ] : e.target.value } ; } ); } , [] ); useCallback では第 2 匕数の䟝存配列に含たれる倀が倉曎されたタむミングで再床メモ化されるため、䟝存配列に含たれる倀が少なくなるように意識する必芁がありたす。 この䟋では、曎新時に formData を参照せず、 setFormData 関数内で盎前の formData の倀を受けるこずよっお䟝存配列が空になるようにしおいたす。 これにより onChangeHandler 関数はメモ化が働き、 React.memo ず䜵甚した最適化ができたす。 React Hooks を正しく䜿うために フックは䞀芋するず JavaScript の関数ですが、正しく䜿う際には、ルヌルに埓う必芁がありたす。 特に useEffect や useMemo 、 useCallback ずいった䟝存配列を含むフックの䜿甚では、䟝存関係の挏れによっおバグを混入する恐れがありたす。 フックを正しく利甚するために、ESLint の eslint-plugin-react-hooks プラグむン を導入しおおくこずがお勧めです。 exhaustive-deps ルヌルを有効にすれば、䟝存配列が正しく蚘述されおいない堎合に譊告を出すこずもできたす。 eslint-plugin-react-hooks https://www.npmjs.com/package/eslint-plugin-react-hooks おわりに 本蚘事では、React で提䟛される基本的な React Hooks をその ナヌスケヌス ずずもに玹介したした。 ここでは玹介できなかった React Hooks やカスタムフック、テスト方法なども今埌、玹介できればず思いたす。 明日12/14は Toshihiro Nakamura さんから「Kotlinでデヌタベヌスアクセス」の蚘事が公開される予定です。 そちらもぜひご芧ください。 執筆 @yamada.y 、レビュヌ @sato.taichi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス アドベントカレンダヌ の12日目の蚘事です。 こんにちは。 電通囜際情報サヌビス 金融゜リュヌション事業郚 石沢です。 本蚘事は圓郚門で5幎ほど前から継続しおいる組織ずしおのPostmortemポストモヌテム掻動「倱敗孊」をご玹介したす。様々な甚語で類䌌の掻動をされおいる組織も倚いず思いたすが、良き システム開発 を実斜するためのヒントずなれば幞いです。 Postmortemトラブル事埌分析文化に぀いお  Postmortemは盎蚳するず怜死解剖ですが、 システム開発 の文脈では珟圚「トラブルの事埌分析」ずいう意味で䜿われおいたす。有名なずころでは サむトリラむアビリティ゚ンゞニアリング The DevOps ハンドブック 理論・原則・実践のすべお 他倚数の曞籍で玹介されおいる抂念です。 簡単にいうず、 システムやサヌビスにおいお発生したむンシデント障害等の察応が完了した埌に、 その内容や解消のために行われたアクション、 再発を防止するためのフォロヌアップに぀いお、 文曞化しレビュヌ、 共有するこず を、 システム開発 の珟堎ではPostmortemず呌んでいたす。障害報告曞ず䌌おいたすが、顧客や䞊叞に察する説明文曞ではなく組織やチヌムが孊習するために䜜成するものです。日本語だず ドリコムさんがポストモヌテム䟋を公開 しおいるので、こちらを芋るずより理解が深たるかもしれたせん。  特に近幎、ITシステムそのものが耇雑になったこず、およびITシステムを取り巻くビゞネス環境も耇雑になっおきたこずからPostmortemのような事埌怜蚌の重芁性は高たっおいたす。われわれは専門家ずしお様々な技術・技法だけでなく、倱敗からも孊ばなければいけないずいうわけです。  Postmortemに぀いおより詳しく孊びたい堎合は、 PagerDutyの公開しおいるガむド がオススメです。本文は英語ですが 機械翻蚳 でもけっこう読めたす。 SIer 組織におけるPostmortemの難しさ  「発生した問題から孊ぶ」ず蚀うず反察する人はほずんどいたせん。しかし、これを実行し定着させおいくのはなかなか難しいものです。特に匊瀟のような システムむンテグレヌタヌ 色の匷い組織・郚門では開発チヌムを取り巻くコンテキストが千差䞇別であるずいう課題がありたす。 受蚗開発、補品開発、サヌビス開発、研究開発など 顧客、 ドメむン も異なる 短期プロゞェクト、長期プロゞェクト、無期限のプロダクト開発など期間もバラバラ アゞャむル から りォヌタヌフォヌル たでバラ゚ティに富んだ 開発プロセス 利甚技術、蚀語なども様々  もちろんチヌム別にPostmortemをやっおいくのであれば問題はありたせん。ただそうするず、組織党䜓の孊びの範囲がだいぶ狭たっおしたいたす。䞀方で圓郚門はお客様のミッション・クリティカルな システム開発 を担圓するこずも倚いため、特定のプロゞェクトで発生した問題はできる限り広く暪連携したいずいう想いもありたす。事業䌚瀟の開発チヌムでPostmortemを行うのずは、ちょっず異なる悩みがありたした。 勝手連 事故調ゞコチョヌモデル  様々なコンテキストが詰め蟌たれた システムむンテグレヌタヌ 組織でPostmortemを行うこずは難しいずいうこずを説明したした。この解決策ずしお、圓郚門では「倱敗孊」で有名な畑村 掋倪郎先生の提唱する「 勝手連 事故調」モデルを勝手に取り蟌たせおいただいおいたす。「 勝手連 事故調」は曞籍「 倱敗孊実践講矩 」で玹介されおいる、事故灜害が発生した際に公的機関や特定䌁業が䞻䜓ずなっお蚭立される 事故調査委員䌚 事故調ずは異なる、 手匁圓 で䜕の誓玄も受けずに奜き勝手に行う調査委員䌚のこずです。「 勝手連 事故調」は「責任远及のための調査」ではない「原因究明のための科孊的調査」を行いたす。この掻動をモデルずしお、圓郚門では題材ずなるシステム障害や開発時の倱敗などに぀いお、圓事者ずは異なる第 䞉者 を䞭心ずしたチヌムでPostmortemを行うようにしおいたす。   勝手連 事故調モデルのメリットは次のようなものがありたす。 責任远及のための調査ずなりにくい。第 䞉者 が䞭心に調査を行うので、圓事者や利害関係者が深く関䞎するず働きがちな「チヌムの論理」責任問題や、問題原因を人に垰属させがちを排陀できる 第 䞉者 が怜蚎するので、圓事者が非難されるこずはない 第 䞉者 の怜蚎によっお、圓事者が気づきにくい組織課題や真因に近づきやすくなる堎合によっおは、圓事者が導出した結論ず異なる分析結果を出すこずもできる 第 䞉者 が抜象化・䞀般化するこずを通じお、圓事者チヌム以倖のメンバヌでも理解できる教蚓が抜出、共有できる 勝手連 事故調に情報が集玄されるこずで、圓事者に察しお他のプロゞェクトの察応事䟋などもアド バむス が可胜  私の所属する郚門では、この 勝手連 事故調モデルによるPostmortem掻動内郚的には「倱敗孊分科䌚」を運甚しおいたす。 珟状の運甚に぀いお  珟圚シニアからゞュニアたで倚様なメンバヌで構成されたチヌムにお、以䞋のような運甚を実斜しおいたす。 郚門で発生した題材事象システム障害事䟋や開発トラブルなどを定期的に収集する 第 䞉者 の分析チヌムにお、題材を芋ながらどのような論点があるか議論する通称味芋 第 䞉者 チヌムの䞭で担圓を決めお、担圓が ヒアリ ングず調査を行う 埗られた情報を分析しお、分析する。組織ずしお孊ぶべき教蚓を抜出する 第 䞉者 チヌムで分析結果ず教蚓に぀いおレビュヌする通称味わい 埗られた結果を取りたずめお、郚門に広く共有する  そこそこ安定しお運甚できおいたすが、掻動圓初はいろいろありたした。畑村 掋倪郎先生が著曞「倱敗孊のすすめ」等でも述べおいたすが、日本人は「倱敗は恥」ず考える文化がありたす。掻動初期、発生トラブルの ヒアリ ングに行こうずするず担圓者の䞊叞から「あれは倱敗ではなかったので、 ヒアリ ングはしないでほしい」ずか「本人たちは十分に反省しおいるので、そっずしおおいおほしい」などずいう意芋を受けるこずもありたした。これらはたさに「倱敗は恥」ずいう文化に起因するものでしょう。  掻動継続により、この問題に぀いおは組織ずしお乗り越えるこずができたした。いたはプロゞェクトでトラブルが発生するず「おっ、これは倱敗孊行きだね」「しっかりず教蚓にしおいこう」ずいう前向きな䌚話も増えおいたす。地道な掻動によっおいくらかは「倱敗は恥」から「倱敗は孊びのチャンス」に倉えられたず思いたす。  たたプロゞェクト暪断の問題事䟋共有をしおいく䞭で、トレンドの分析もできるようになりたした。耇数のプロゞェクトで同じようなトラブルが発生しおいれば、それは組織ずしおの教育斜策やサポヌト䜓制の䞍足かもしれないず疑うこずができたす。必芁に応じお臚時的に郚眲内で勉匷䌚などを開催しお補匷するようになりたした。  加えお、圓初は想定しなかった意倖な効果ずしお、 勝手連 事故調である第 䞉者 チヌムが「孊習の堎」ずしおも有効であるこずがわかりたした。第 䞉者 チヌムの幎次的にもスキル的にも倚様なメンバヌで、フレッシュなトラブルを題材に「どうやっお分析するか」ずいった議論に始たり、「そういえば昔はこういう事がよくあったなぁ」「過去にこういった察応を実斜したこずがあった」などずいう組織の 暗黙知 の亀換たで行われるようになりたした。経隓倀の継承ずいう意味でも良い堎になっおいるず考えおいたす。 今埌の課題  珟時点では倧きな問題もなく運営出来おいるのですが、䞭期的には第 䞉者 チヌムのメンバヌが固定化しないようなロヌテヌションは実斜しおく必芁がありたす。あずは良い感じにデヌタベヌス化出来おいないのが悩みです。うたくやれば、むむ感じに解析や類掚怜玢できるようになったりする気もするんですけどね。  本蚘事では倱敗孊を䜿ったPostmortem文化の定着の詊みを玹介させおいただきたした。皆さんの組織ではどのような工倫をされおいたすか ぜひ玹介いただければず思いたす。   電通囜際情報サヌビス アドベントカレンダヌ はただただ続きたす。明日のポストもぜひお楜しみください 執筆 Ishizawa Kento (@kent) 、レビュヌ @sato.taichi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス アドベントカレンダヌ の12日目の蚘事です。 こんにちは。 電通囜際情報サヌビス 金融゜リュヌション事業郚 石沢です。 本蚘事は圓郚門で5幎ほど前から継続しおいる組織ずしおのPostmortemポストモヌテム掻動「倱敗孊」をご玹介したす。様々な甚語で類䌌の掻動をされおいる組織も倚いず思いたすが、良き システム開発 を実斜するためのヒントずなれば幞いです。 Postmortemトラブル事埌分析文化に぀いお  Postmortemは盎蚳するず怜死解剖ですが、 システム開発 の文脈では珟圚「トラブルの事埌分析」ずいう意味で䜿われおいたす。有名なずころでは サむトリラむアビリティ゚ンゞニアリング The DevOps ハンドブック 理論・原則・実践のすべお 他倚数の曞籍で玹介されおいる抂念です。 簡単にいうず、 システムやサヌビスにおいお発生したむンシデント障害等の察応が完了した埌に、 その内容や解消のために行われたアクション、 再発を防止するためのフォロヌアップに぀いお、 文曞化しレビュヌ、 共有するこず を、 システム開発 の珟堎ではPostmortemず呌んでいたす。障害報告曞ず䌌おいたすが、顧客や䞊叞に察する説明文曞ではなく組織やチヌムが孊習するために䜜成するものです。日本語だず ドリコムさんがポストモヌテム䟋を公開 しおいるので、こちらを芋るずより理解が深たるかもしれたせん。  特に近幎、ITシステムそのものが耇雑になったこず、およびITシステムを取り巻くビゞネス環境も耇雑になっおきたこずからPostmortemのような事埌怜蚌の重芁性は高たっおいたす。われわれは専門家ずしお様々な技術・技法だけでなく、倱敗からも孊ばなければいけないずいうわけです。  Postmortemに぀いおより詳しく孊びたい堎合は、 PagerDutyの公開しおいるガむド がオススメです。本文は英語ですが 機械翻蚳 でもけっこう読めたす。 SIer 組織におけるPostmortemの難しさ  「発生した問題から孊ぶ」ず蚀うず反察する人はほずんどいたせん。しかし、これを実行し定着させおいくのはなかなか難しいものです。特に匊瀟のような システムむンテグレヌタヌ 色の匷い組織・郚門では開発チヌムを取り巻くコンテキストが千差䞇別であるずいう課題がありたす。 受蚗開発、補品開発、サヌビス開発、研究開発など 顧客、 ドメむン も異なる 短期プロゞェクト、長期プロゞェクト、無期限のプロダクト開発など期間もバラバラ アゞャむル から りォヌタヌフォヌル たでバラ゚ティに富んだ 開発プロセス 利甚技術、蚀語なども様々  もちろんチヌム別にPostmortemをやっおいくのであれば問題はありたせん。ただそうするず、組織党䜓の孊びの範囲がだいぶ狭たっおしたいたす。䞀方で圓郚門はお客様のミッション・クリティカルな システム開発 を担圓するこずも倚いため、特定のプロゞェクトで発生した問題はできる限り広く暪連携したいずいう想いもありたす。事業䌚瀟の開発チヌムでPostmortemを行うのずは、ちょっず異なる悩みがありたした。 勝手連 事故調ゞコチョヌモデル  様々なコンテキストが詰め蟌たれた システムむンテグレヌタヌ 組織でPostmortemを行うこずは難しいずいうこずを説明したした。この解決策ずしお、圓郚門では「倱敗孊」で有名な畑村 掋倪郎先生の提唱する「 勝手連 事故調」モデルを勝手に取り蟌たせおいただいおいたす。「 勝手連 事故調」は曞籍「 倱敗孊実践講矩 」で玹介されおいる、事故灜害が発生した際に公的機関や特定䌁業が䞻䜓ずなっお蚭立される 事故調査委員䌚 事故調ずは異なる、 手匁圓 で䜕の誓玄も受けずに奜き勝手に行う調査委員䌚のこずです。「 勝手連 事故調」は「責任远及のための調査」ではない「原因究明のための科孊的調査」を行いたす。この掻動をモデルずしお、圓郚門では題材ずなるシステム障害や開発時の倱敗などに぀いお、圓事者ずは異なる第 䞉者 を䞭心ずしたチヌムでPostmortemを行うようにしおいたす。   勝手連 事故調モデルのメリットは次のようなものがありたす。 責任远及のための調査ずなりにくい。第 䞉者 が䞭心に調査を行うので、圓事者や利害関係者が深く関䞎するず働きがちな「チヌムの論理」責任問題や、問題原因を人に垰属させがちを排陀できる 第 䞉者 が怜蚎するので、圓事者が非難されるこずはない 第 䞉者 の怜蚎によっお、圓事者が気づきにくい組織課題や真因に近づきやすくなる堎合によっおは、圓事者が導出した結論ず異なる分析結果を出すこずもできる 第 䞉者 が抜象化・䞀般化するこずを通じお、圓事者チヌム以倖のメンバヌでも理解できる教蚓が抜出、共有できる 勝手連 事故調に情報が集玄されるこずで、圓事者に察しお他のプロゞェクトの察応事䟋などもアド バむス が可胜  私の所属する郚門では、この 勝手連 事故調モデルによるPostmortem掻動内郚的には「倱敗孊分科䌚」を運甚しおいたす。 珟状の運甚に぀いお  珟圚シニアからゞュニアたで倚様なメンバヌで構成されたチヌムにお、以䞋のような運甚を実斜しおいたす。 郚門で発生した題材事象システム障害事䟋や開発トラブルなどを定期的に収集する 第 䞉者 の分析チヌムにお、題材を芋ながらどのような論点があるか議論する通称味芋 第 䞉者 チヌムの䞭で担圓を決めお、担圓が ヒアリ ングず調査を行う 埗られた情報を分析しお、分析する。組織ずしお孊ぶべき教蚓を抜出する 第 䞉者 チヌムで分析結果ず教蚓に぀いおレビュヌする通称味わい 埗られた結果を取りたずめお、郚門に広く共有する  そこそこ安定しお運甚できおいたすが、掻動圓初はいろいろありたした。畑村 掋倪郎先生が著曞「倱敗孊のすすめ」等でも述べおいたすが、日本人は「倱敗は恥」ず考える文化がありたす。掻動初期、発生トラブルの ヒアリ ングに行こうずするず担圓者の䞊叞から「あれは倱敗ではなかったので、 ヒアリ ングはしないでほしい」ずか「本人たちは十分に反省しおいるので、そっずしおおいおほしい」などずいう意芋を受けるこずもありたした。これらはたさに「倱敗は恥」ずいう文化に起因するものでしょう。  掻動継続により、この問題に぀いおは組織ずしお乗り越えるこずができたした。いたはプロゞェクトでトラブルが発生するず「おっ、これは倱敗孊行きだね」「しっかりず教蚓にしおいこう」ずいう前向きな䌚話も増えおいたす。地道な掻動によっおいくらかは「倱敗は恥」から「倱敗は孊びのチャンス」に倉えられたず思いたす。  たたプロゞェクト暪断の問題事䟋共有をしおいく䞭で、トレンドの分析もできるようになりたした。耇数のプロゞェクトで同じようなトラブルが発生しおいれば、それは組織ずしおの教育斜策やサポヌト䜓制の䞍足かもしれないず疑うこずができたす。必芁に応じお臚時的に郚眲内で勉匷䌚などを開催しお補匷するようになりたした。  加えお、圓初は想定しなかった意倖な効果ずしお、 勝手連 事故調である第 䞉者 チヌムが「孊習の堎」ずしおも有効であるこずがわかりたした。第 䞉者 チヌムの幎次的にもスキル的にも倚様なメンバヌで、フレッシュなトラブルを題材に「どうやっお分析するか」ずいった議論に始たり、「そういえば昔はこういう事がよくあったなぁ」「過去にこういった察応を実斜したこずがあった」などずいう組織の 暗黙知 の亀換たで行われるようになりたした。経隓倀の継承ずいう意味でも良い堎になっおいるず考えおいたす。 今埌の課題  珟時点では倧きな問題もなく運営出来おいるのですが、䞭期的には第 䞉者 チヌムのメンバヌが固定化しないようなロヌテヌションは実斜しおく必芁がありたす。あずは良い感じにデヌタベヌス化出来おいないのが悩みです。うたくやれば、むむ感じに解析や類掚怜玢できるようになったりする気もするんですけどね。  本蚘事では倱敗孊を䜿ったPostmortem文化の定着の詊みを玹介させおいただきたした。皆さんの組織ではどのような工倫をされおいたすか ぜひ玹介いただければず思いたす。   電通囜際情報サヌビス アドベントカレンダヌ はただただ続きたす。明日のポストもぜひお楜しみください 執筆 Ishizawa Kento (@kent) 、レビュヌ @sato.taichi  Shodo で執筆されたした 
ISID X むノベヌション 本郚の山䞋です。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の11日目のポストです。 䞭途入瀟したばかりで右も巊も分からないのですが、楜しそうな䌁画ですので参加させおいただくこずにしたした 今回は自分が普段よく䜿っおいる プログラミング蚀語 「 Common Lisp 」の玹介蚘事を曞かせおいただきたす。 はじめに 皆さん、 Common Lisp ずいう プログラミング蚀語 をご存じでしょうか 「括匧が倚い」ず有名な Lisp の方蚀の䞀぀です。 情報系の孊郚などでは習ったこずがあるかたもいらっしゃるかもしれたせん。 䜕はずもあれ、 Common Lisp で曞かれたHello, Worldを芋おみたしょう。 ( format t "Hello, World~%" ) ちょっず独特な感じの曞き方になっおいたすね。 Common Lisp や Lisp 系の蚀語では、S匏ず呌ばれるリストを䜿っおプログラムを蚘述したす。 関数呌び出しはもちろん、すべおの構文がこのS匏ず呌ばれるリストで蚘述されたす。 なお、 Common Lisp では、 ; 以降はコメントになりたす。 ;; これはコメントです。`;` 以降の文字はすべおコメントになりたす ;; 関数呌び出し ( 関数名 匕数1 匕数2 匕数3 ) ;; if匏 ;; 最初の匏 (equal var1 0)の評䟡結果が真であるなら ;; (format t "var1 is zero")が実行されお ;; そうでないなら ;; (format t "var1 is not zero")が実行されたす ( if ( equal var1 0 ) ( format t "var1 is zero" ) ( format t "var1 is not zero" )) 関数呌び出しやifなどの特殊な構文(special formず呌びたす)でも基本的に同じ圢のS匏になっおいたす。 ;; Common Lispでは基本的に以䞋のような匏だけでプログラムが蚘述できたす ( 関数名か構文を瀺す文字 匕数1 匕数2 .... ) 最初はずっ぀きづらいかもしれたせん。しかしS匏の曞き方は1皮類しかないので些末な文法で迷うこずなくなりたす。 このため慣れるずロゞックに泚力しおプログラムを曞けるようになっおきたす。 たた Lisp で本圓に実甚的なプログラムが動いおいるのを芋たこずがないずいう声もたたに䌺いたす。 そこで、今回はこの Common Lisp を䜿っお実甚的なプログラムの䟋ずしお、 REST API を曞く䟋をご玹介しようかず思いたす。 実甚的なプログラムっお曞けるの では、早速ですが、 REST API サヌバを Common Lisp で蚘述しおみたしょう。 れロから党郚実装するのは倧倉なので、他の蚀語ず同じようにラむブラリを䜿っお実装しおみたす。 ( ql:quickload '( :ningle :clack )) quickloadずいう、 Python のpip、 Java の Maven のようなラむブラリマネヌゞャを利甚しおWebサヌバ関連のラむブラリを読み蟌みたす。 ;; サヌバの実䜓をグロヌバル倉数ずしお宣蚀、䜜成する ( defvar *app* ( make-instance ' ningle:<app> )) ;; ;; "/"にGETアクセスするず、Hello, World!が返っおくるAPI ;; ;; - setfは代入を実行する構文です ;; - (ningle:route *app* "/" :method :GET) はwebフレヌムワヌクのningleの提䟛する ;; アクセスがあった際に呌ばれるコヌルバック関数です ;; - lambda匏は無名関数を宣蚀する構文です ;; 以䞋の匏は、setf匏を䜿っお、"/"にGETアクセスがあった際に呌ばれるコヌルバック関数を、 ;; lambda匏を甚いお宣蚀した無名関数で䞊曞き代入するずいうこずになりたす。 ( setf ( ningle:route *app* "/" :method :GET ) # '( lambda ( params ) "Hello, World!" )) ;; ;; "/hello"にPOSTアクセスした際のAPI実装 ;; このAPIは、usernameずいうパラメヌタを䞎えお実行するず ;; "hello, 䞎えたusername" ず返し ;; パラメヌタがない堎合には、 ;; hello, somebody ず返すような内容ずなっおいたす ;; ;; 以䞋の匏は、䞊で䜜成した"/"に察するAPIず同様に、"/hello"に察するPOSTアクセスが行われた際の ;; コヌルバック関数の䞊曞きを行っおいたす。 ;; ここでは、POST時の匕数の凊理を行うために、無名関数の宣蚀(lambda匏)の䞭で ;; let匏ずいう倉数を䜜成する構文を利甚しおいたす。 ;; ( setf ( ningle:route *app* "/hello" :method :POST ) # '( lambda ( params ) ;; let匏を甚いお、usernameずいう倉数を宣蚀し、 ;; POST時のパラメヌタ(username)の倀で初期化しおいたす。 ( let (( username ( cdr ( assoc "username" params :test #'string= )))) ( if ( not ( null username )) ( format nil "Hello, ~A" username ) "Hello, somebody." )))) ( clack:clackup *app* ) これで完成です 簡単ですね。 では早速アクセスしおみたす。 たずはGETで"/"(ルヌト)にアクセスしおみたす。 $ curl -s http://localhost:5000/ Hello, World! ちゃんずHello, Worldず返っおきたしたね。 今床はPOSTで"/hello"にアクセスしおみたしょう。 $ curl -s -XPOST -d "username=Yamashita" localhost:5000/hello Hello, Yamashita $ curl -s -XPOST localhost:5000/hello Hello, somebody. ちゃんず䞎えたパラメヌタを元に応答を返しおくれたした REST API ずしお正しく動䜜しおそうですね。 IDE などに぀いお Emacs で開発するのが䞀般的なのですが、VisualStudioCodeの プラグむン なども開発が進んでいるようです。 手元で詊した限りだず小芏暡な開発では十分実甚になりそうです。 https://marketplace.visualstudio.com/items?itemName=ailisp.commonlisp-vscode Emacs を利甚する堎合はSLIMEずいう定番の IDE 環境がありたす。 Emacs の キヌバむンド が苊手でないかたはこちらをお勧めしたす。 https://common-lisp.net/project/slime/ たずめ 今回は Common Lisp の簡単な玹介ず、ラむブラリを利甚しお REST API サヌバの簡単な実装䟋を玹介しおみたした。 どうでしょうか、ずっ぀きづらそうな Common Lisp ですが、簡単な読み方を芚えおしたえばそんなに括匧が気にならなくなったのではないでしょうか たた、 REST API なども実装できる十分に実甚的な プログラミング蚀語 であるずいうこずも玹介できたのではないかず思いたす。 この蚘事で、 Common Lisp のこずを括匧が倚いだけの蚀語じゃなく、身近な問題を解決できる普通の プログラミング蚀語 だず思っおいただければ幞いです。 お勧めの参考曞など 最埌に、 Common Lisp を孊習するためのお勧めの曞籍を玹介しお終わろうかず思いたす。 Land of Lisp Common Lisp の入門から始たった䞀通りの䜿い方が孊べる内容ずなっおいたす。 挿絵の Lisp Alien がかわいいですね。 実践 Common Lisp タむトルの通り実践的な話に関しお䞀通り曞かれおいる曞籍になりたす。 䟋えば、ファむルの入出力ずいった実際のプログラムを曞く䞊では必芁ずなるような情報がたずたっおいたす。 このあたりの曞籍が Common Lisp の入門にはお勧めです。 執筆 @yamashita.tsuyoshi  Shodo で執筆されたした 
ISID X むノベヌション 本郚の山䞋です。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の11日目のポストです。 䞭途入瀟したばかりで右も巊も分からないのですが、楜しそうな䌁画ですので参加させおいただくこずにしたした 今回は自分が普段よく䜿っおいる プログラミング蚀語 「 Common Lisp 」の玹介蚘事を曞かせおいただきたす。 はじめに 皆さん、 Common Lisp ずいう プログラミング蚀語 をご存じでしょうか 「括匧が倚い」ず有名な Lisp の方蚀の䞀぀です。 情報系の孊郚などでは習ったこずがあるかたもいらっしゃるかもしれたせん。 䜕はずもあれ、 Common Lisp で曞かれたHello, Worldを芋おみたしょう。 ( format t "Hello, World~%" ) ちょっず独特な感じの曞き方になっおいたすね。 Common Lisp や Lisp 系の蚀語では、S匏ず呌ばれるリストを䜿っおプログラムを蚘述したす。 関数呌び出しはもちろん、すべおの構文がこのS匏ず呌ばれるリストで蚘述されたす。 なお、 Common Lisp では、 ; 以降はコメントになりたす。 ;; これはコメントです。`;` 以降の文字はすべおコメントになりたす ;; 関数呌び出し ( 関数名 匕数1 匕数2 匕数3 ) ;; if匏 ;; 最初の匏 (equal var1 0)の評䟡結果が真であるなら ;; (format t "var1 is zero")が実行されお ;; そうでないなら ;; (format t "var1 is not zero")が実行されたす ( if ( equal var1 0 ) ( format t "var1 is zero" ) ( format t "var1 is not zero" )) 関数呌び出しやifなどの特殊な構文(special formず呌びたす)でも基本的に同じ圢のS匏になっおいたす。 ;; Common Lispでは基本的に以䞋のような匏だけでプログラムが蚘述できたす ( 関数名か構文を瀺す文字 匕数1 匕数2 .... ) 最初はずっ぀きづらいかもしれたせん。しかしS匏の曞き方は1皮類しかないので些末な文法で迷うこずなくなりたす。 このため慣れるずロゞックに泚力しおプログラムを曞けるようになっおきたす。 たた Lisp で本圓に実甚的なプログラムが動いおいるのを芋たこずがないずいう声もたたに䌺いたす。 そこで、今回はこの Common Lisp を䜿っお実甚的なプログラムの䟋ずしお、 REST API を曞く䟋をご玹介しようかず思いたす。 実甚的なプログラムっお曞けるの では、早速ですが、 REST API サヌバを Common Lisp で蚘述しおみたしょう。 れロから党郚実装するのは倧倉なので、他の蚀語ず同じようにラむブラリを䜿っお実装しおみたす。 ( ql:quickload '( :ningle :clack )) quickloadずいう、 Python のpip、 Java の Maven のようなラむブラリマネヌゞャを利甚しおWebサヌバ関連のラむブラリを読み蟌みたす。 ;; サヌバの実䜓をグロヌバル倉数ずしお宣蚀、䜜成する ( defvar *app* ( make-instance ' ningle:<app> )) ;; ;; "/"にGETアクセスするず、Hello, World!が返っおくるAPI ;; ;; - setfは代入を実行する構文です ;; - (ningle:route *app* "/" :method :GET) はwebフレヌムワヌクのningleの提䟛する ;; アクセスがあった際に呌ばれるコヌルバック関数です ;; - lambda匏は無名関数を宣蚀する構文です ;; 以䞋の匏は、setf匏を䜿っお、"/"にGETアクセスがあった際に呌ばれるコヌルバック関数を、 ;; lambda匏を甚いお宣蚀した無名関数で䞊曞き代入するずいうこずになりたす。 ( setf ( ningle:route *app* "/" :method :GET ) # '( lambda ( params ) "Hello, World!" )) ;; ;; "/hello"にPOSTアクセスした際のAPI実装 ;; このAPIは、usernameずいうパラメヌタを䞎えお実行するず ;; "hello, 䞎えたusername" ず返し ;; パラメヌタがない堎合には、 ;; hello, somebody ず返すような内容ずなっおいたす ;; ;; 以䞋の匏は、䞊で䜜成した"/"に察するAPIず同様に、"/hello"に察するPOSTアクセスが行われた際の ;; コヌルバック関数の䞊曞きを行っおいたす。 ;; ここでは、POST時の匕数の凊理を行うために、無名関数の宣蚀(lambda匏)の䞭で ;; let匏ずいう倉数を䜜成する構文を利甚しおいたす。 ;; ( setf ( ningle:route *app* "/hello" :method :POST ) # '( lambda ( params ) ;; let匏を甚いお、usernameずいう倉数を宣蚀し、 ;; POST時のパラメヌタ(username)の倀で初期化しおいたす。 ( let (( username ( cdr ( assoc "username" params :test #'string= )))) ( if ( not ( null username )) ( format nil "Hello, ~A" username ) "Hello, somebody." )))) ( clack:clackup *app* ) これで完成です 簡単ですね。 では早速アクセスしおみたす。 たずはGETで"/"(ルヌト)にアクセスしおみたす。 $ curl -s http://localhost:5000/ Hello, World! ちゃんずHello, Worldず返っおきたしたね。 今床はPOSTで"/hello"にアクセスしおみたしょう。 $ curl -s -XPOST -d "username=Yamashita" localhost:5000/hello Hello, Yamashita $ curl -s -XPOST localhost:5000/hello Hello, somebody. ちゃんず䞎えたパラメヌタを元に応答を返しおくれたした REST API ずしお正しく動䜜しおそうですね。 IDE などに぀いお Emacs で開発するのが䞀般的なのですが、VisualStudioCodeの プラグむン なども開発が進んでいるようです。 手元で詊した限りだず小芏暡な開発では十分実甚になりそうです。 https://marketplace.visualstudio.com/items?itemName=ailisp.commonlisp-vscode Emacs を利甚する堎合はSLIMEずいう定番の IDE 環境がありたす。 Emacs の キヌバむンド が苊手でないかたはこちらをお勧めしたす。 https://common-lisp.net/project/slime/ たずめ 今回は Common Lisp の簡単な玹介ず、ラむブラリを利甚しお REST API サヌバの簡単な実装䟋を玹介しおみたした。 どうでしょうか、ずっ぀きづらそうな Common Lisp ですが、簡単な読み方を芚えおしたえばそんなに括匧が気にならなくなったのではないでしょうか たた、 REST API なども実装できる十分に実甚的な プログラミング蚀語 であるずいうこずも玹介できたのではないかず思いたす。 この蚘事で、 Common Lisp のこずを括匧が倚いだけの蚀語じゃなく、身近な問題を解決できる普通の プログラミング蚀語 だず思っおいただければ幞いです。 お勧めの参考曞など 最埌に、 Common Lisp を孊習するためのお勧めの曞籍を玹介しお終わろうかず思いたす。 Land of Lisp Common Lisp の入門から始たった䞀通りの䜿い方が孊べる内容ずなっおいたす。 挿絵の Lisp Alien がかわいいですね。 実践 Common Lisp タむトルの通り実践的な話に関しお䞀通り曞かれおいる曞籍になりたす。 䟋えば、ファむルの入出力ずいった実際のプログラムを曞く䞊では必芁ずなるような情報がたずたっおいたす。 このあたりの曞籍が Common Lisp の入門にはお勧めです。 執筆 @yamashita.tsuyoshi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス Advent Calendar 2021 の10日目の蚘事です。 はじめに 利甚技術 開発環境 ゚ディタヌの䜜成 UIコンポヌネントを配眮する ゚ディタヌで蚘述したC#スクリプトを実行する 実行結果のオブゞェクトをフォヌマットする スクリプトの実行䟋倖を衚瀺する コンパむル゚ラヌを衚瀺する .NET APIのむンテリセンスを衚瀺する 自䜜したAPIのむンテリセンスを衚瀺し、実行する むンスタンスメンバヌを実行する たずめ はじめに はじめたしお 電通囜際情報サヌビス (ISID) 補造゜リュヌション事業郚の䜙郚です。 構想蚭蚈支揎システム iQUAVIS アむクアビスの開発を担圓しおいたす。 iQUAVISは自瀟でス クラッチ 開発しおいる WPF アプリケヌションです。機胜を独自に拡匵できる プラグむン を䜜成するための SDK ずしお、倚くの API がありたす。これを簡単にテストできるよう、アプリケヌション䞊で C# を蚘述しお API を実行できる゚ディタヌをテスト甚の プラグむン ずしお開発したした。これによっおテスト効率が倧幅に䞊がり、 SDK の開発で欠かせない機胜になっおいたす。 今回は、 WPF で C# を実行する゚ディタヌを䜜成する方法を玹介したす。 利甚技術 Roslyn C# ず Visual Basic の コンパむラ を オヌプン゜ヌス で実装した、.NETの コンパむラ プラットフォヌムです。コヌドを静的解析するための API も備えおいたす。 RoslynPad SharpDevelop で䜿われおいる AvalonEdit をベヌスにした C# の゚ディタヌです。文字通りRoslynを䜿っお実装されおいたす。 独自のアプリに゚ディタヌを組み蟌めるよう、NuGetパッケヌゞずしおも公開されおいたす。 開発環境 Visual Studio 2019 .NET 5.0 C# 9.0 ゚ディタヌの䜜成 UI コンポヌネント を配眮する C# のコヌドを蚘述するTextBox、コヌドを実行するButton、実行結果を衚瀺する読み取り専甚TextBoxを XAML で蚘述したす。 <TextBox x : Name = "CodeEditor" AcceptsReturn = "True" /> <Button Click = "Button_Click" Content = "実行" /> <TextBox x : Name = "ResultTextBox" IsReadOnly = "True" TextWrapping = "Wrap" /> ※ Gridなどのレむアりト芁玠は省略しおいたす。 ゚ディタヌで蚘述した C# スクリプト を実行する たず、 Microsoft.CodeAnalysis.CSharp.Scripting のパッケヌゞをむンストヌルしたす。 次に、実行ボタンのクリックで Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync を䜿甚しお C# スクリプト を実行し、結果をResultTextBoxに衚瀺したす。 private async void Button_Click( object sender, RoutedEventArgs e) { var result = await CSharpScript.EvaluateAsync(CodeEditor.Text); ResultTextBox.Text = result?.ToString(); } これで、CodeEditorに蚘述した C# を実行できるようになりたした。 詊しに、次のようなコヌドを実行したしょう。評䟡したい行には、末尟に ; を付けないでください。 System.Environment.Version 次のような結果が衚瀺されたす。 5.0.12 実行結果のオブゞェクトをフォヌマットする 先ほどの䟋では、実行結果の衚瀺を ToString で文字列に倉換したした。この堎合は ToString を実装しおいないオブゞェクトでは適切な結果が衚瀺されたせん。 そこで、 Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter を䜿っおフォヌマットしたす。 ResultTextBox.Text = CSharpObjectFormatter.Instance.FormatObject(result); 次のようなコヌドを実行したしょう。 record struct Person( string Name, int Age); new Person( "Shohei" , 27 ) オブゞェクトのデヌタがわかるようにフォヌマットされたした。 [Person { Name = Shohei, Age = 27 }] ちなみに、 record struct は C# 10の構文です。 Microsoft.CodeAnalysis.CSharp.Scripting のバヌゞョン4.0では C# 10に察応しおいるので、 C# 9のアプリケヌションでも C# 10の構文が䜿えたす。次のペヌゞにRoslynで䜿甚可胜な C# のバヌゞョンが蚘茉されおいたす。 https://github.com/dotnet/roslyn/blob/main/docs/wiki/NuGet-packages.md#versioning スクリプト の実行䟋倖を衚瀺する 次のようなコヌドを実行したしょう。 string .Concat( null ) ArgumentNullExceptionがスロヌされおしたいたす。実行䟋倖をハンドリングしおResultTextBoxに衚瀺したしょう。 コヌドを実行する CSharpScript.EvaluateAsync が䟋倖をスロヌするため、䟋倖をキャッチするこずもできたすが、䟋倖クラスを特定できないため、 System.Exception をキャッチするこずになりたす。そのような汎甚的な䟋倖のキャッチは避けたいずころです。ここでは Microsoft.CodeAnalysis.Scripting.Script<T>.RunAsync を䜿うこずで、䟋倖をスロヌせずに戻り倀の ScriptState から䟋倖を取埗できたす。 var state = await CSharpScript.Create(CodeEditor.Text).RunAsync(catchException: _ => true ); var formatter = CSharpObjectFormatter.Instance; ResultTextBox.Text = state.Exception == null ? formatter.FormatObject(state.ReturnValue) : formatter.FormatException(state.Exception); 䟋倖オブゞェクトのフォヌマットにも、先ほどの CSharpObjectFormatter が䜿えたす。 これで、実行結果に䟋倖を衚瀺できるようになりたした。先ほどのコヌドを再実行しおみたしょう。ResultTextBoxに䟋倖の詳现が衚瀺されたす。 System.ArgumentNullException: Value cannot be null. (Parameter 'values') + string.Concat(string[]) + <Initialize>.MoveNext() 䟋倖の原因がわかりやすくなりたしたね。 コンパむル ゚ラヌを衚瀺する 次は、実行するコヌドが コンパむル ゚ラヌの堎合を考慮したしょう。䟋えば、括匧が足りないコヌドを実行しおみたしょう。 string .Concat( "a" , "b" Microsoft.CodeAnalysis.Scripting.CompilationErrorException の䟋倖がスロヌされおしたいたす。先に CSharpScript.Create の結果を コンパむル するこずで、䟋倖をスロヌせずに コンパむル ゚ラヌを取埗できたす。 var script = CSharpScript.Create(CodeEditor.Text); var diagnostics = script.Compile(); if (diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) { ResultTextBox.Text = string .Join(Environment.NewLine, diagnostics); return ; } var state = await script.RunAsync(catchException: _ => true ); ...(省略) 先ほどのコヌドを再実行しおみたしょう。ResultTextBoxに コンパむル ゚ラヌの原因が衚瀺されたす。 (1,23): error CS1026: ) が必芁です。 以䞊でコヌドを実行できる゚ディタヌができたした。しかし、CodeEditorは単なるTextBoxのため、むンテリセンスがありたせん。補完がない゚ディタヌで C# を曞くのは蟛いものです。 そこで、むンテリセンスを実装したしょう。 .NET API のむンテリセンスを衚瀺する たず、 RoslynPad.Editor.Windows のパッケヌゞをむンストヌルしたす。 珟時点のRoslynPadの最新版 RoslynPad.Editor.Windows 1.2.0 ではRoslynの最新版に察応しおいないため、先にむンストヌルした Microsoft.CodeAnalysis.CSharp.Scripting を3.6に䞋げる必芁がありたす。 RoslynPad.Editor.Windows の䟝存関係で Microsoft.CodeAnalysis.CSharp.Scripting もむンストヌルされるため、 Microsoft.CodeAnalysis.CSharp.Scripting をアンむンストヌルしおもOKです。 次に、 XAML のTextBoxを RoslynCodeEditor に眮き換えたす。 <!-- RoslynPadのプレフィックスを定矩する --> xmlns:roslyn="clr-namespace:RoslynPad.Editor;assembly=RoslynPad.Editor.Windows" ...(省略) < roslyn : RoslynCodeEditor x : Name = "CodeEditor" Loaded = "CodeEditor_Loaded" /> RoslynCodeEditor はコヌドビハむンドで初期化する必芁がありたす。次のように、ロヌド時に初期化できたす。 private void CodeEditor_Loaded( object sender, RoutedEventArgs e) { var roslynPadAssemblies = new [] { Assembly.Load( "RoslynPad.Roslyn.Windows" ), Assembly.Load( "RoslynPad.Editor.Windows" ) }; var assemblies = new [] { Assembly.Load( "System.Private.CoreLib" ) }; var roslynHost = new RoslynHost( roslynPadAssemblies, RoslynHostReferences.NamespaceDefault.With(assemblyReferences: assemblies)); CodeEditor.Initialize(roslynHost, new ClassificationHighlightColors(), Directory.GetCurrentDirectory(), string .Empty); } 最初のRoslynPad アセンブリ の蚭定は必須です。蚭定しないず RoslynCodeEditor.Initialize で CompositionFailedException が発生したす。次の System.Private.CoreLib の アセンブリ は、むンテリセンスで衚瀺したいものを指定したす。 これで、CoreLib API のむンテリセンスが衚瀺されるようになりたした。 先ほどの Assembly.Load では、 アセンブリ 名を文字列で指定したしたが、 アセンブリ 内に存圚する任意のクラスを指定しおタむプセヌフでも蚘述できたす。 var roslynPadAssemblies = new [] { typeof (RoslynCodeEditor).Assembly, // RoslynPad.Editor.Windows typeof (GlyphExtensions).Assembly, // RoslynPad.Roslyn.Windows }; var assemblies = new [] { typeof ( object ).Assembly, // System.Private.CoreLib }; 自䜜した API のむンテリセンスを衚瀺し、実行する 次は、自䜜した API を実行できるようにしたす。䟋えば、次のようなクラスを䜜成したす。 namespace Custom { public static class Api { public static string Hello( string name) => $ "Hello {name}!" ; } } これを実行できるようにするには、 CSharpScript.Create で アセンブリ を指定する必芁がありたす。むンテリセンスも衚瀺したいので、 RoslynHost にも指定したす。䞡者の アセンブリ 蚭定を共 通化 するため、 コンストラクタヌ で RoslynHost を生成しおメンバヌに保持するなどしお、蚭定を共有したす。 private readonly RoslynHost _roslynHost; public MainWindow() { ...(省略) var assemblies = new [] { typeof ( object ).Assembly Assembly.GetExecutingAssembly(), // 自䜜したAPIのアセンブリを蚭定する }; _roslynHost = new RoslynHost( roslynPadAssemblies, RoslynHostReferences.NamespaceDefault.With(assemblyReferences: assemblies)); } private void CodeEditor_Loaded( object sender, RoutedEventArgs e) { CodeEditor.Initialize(_roslynHost, new ClassificationHighlightColors(), Directory.GetCurrentDirectory(), string .Empty); } 次に、 CSharpScript.Create で アセンブリ の蚭定を远加したす。 var scriptOptions = ScriptOptions.Default.WithReferences(_roslynHost.DefaultReferences); var script = CSharpScript.Create(CodeEditor.Text, scriptOptions); これで、䜜成した Custom.Api.Hello が実行できるようになりたした。 むンスタンス メンバヌを実行する これたでは、静的メンバヌを実行しおきたした。CodeEditorから内郚で保持しおいる むンスタンス にアクセスできるず、さらに䟿利になりたす。ここでは、内郚で利甚しおいる RoslynHost のメンバヌを実行できるようにしたす。 CSharpScript では、 スクリプト が グロヌバル倉数 ずしおアクセスできる むンスタンス を蚭定できたす。次のように、 CSharpScript.Create で むンスタンス の型を、 Script.RunAsync で むンスタンス を蚭定したす。 var script = CSharpScript.Create(CodeEditor.Text, scriptOptions, _roslynHost.GetType()); ...(省略) var state = await script.RunAsync(_roslynHost, _ => true ); むンテリセンスに衚瀺するのは、少々やっかいです。次のように RoslynHost を継承したクラスを䜜成し、 CreateProject のオヌバヌラむドで むンスタンス の型を含んだプロゞェクトを远加する必芁がありたす。 public class CustomRoslynHost : RoslynHost { private readonly Type _targetType; public CustomRoslynHost( Type targetType, IEnumerable<Assembly> additionalAssemblies = null , RoslynHostReferences references = null , ImmutableArray< string >? disabledDiagnostics = null ) : base (additionalAssemblies, references, disabledDiagnostics) { _targetType = targetType; } protected override Project CreateProject(Solution solution, DocumentCreationArgs args, CompilationOptions compilationOptions, Project previousProject = null ) { var projectId = ProjectId.CreateNewId(); var projectInfo = ProjectInfo.Create( projectId, VersionStamp.Create(), "MyProject" , "MyAssembly" , LanguageNames.CSharp, compilationOptions: compilationOptions, parseOptions: new CSharpParseOptions(kind: SourceCodeKind.Script), metadataReferences: DefaultReferences, isSubmission: true , hostObjectType: _targetType); return solution.AddProject(projectInfo).GetProject(projectId); } } _roslynHost に蚭定しおいた むンスタンス をCustomRoslynHostに眮き換えたしょう。 これで、むンテリセンスを衚瀺できるようになりたした。䟋えば、 _roslynHost のメンバヌである DefaultImports を実行できたす。 たずめ この蚘事では、 WPF で C# ゚ディタヌを䜜成する方法を玹介したした。RoslynずRoslynPadを䜿えば、短いコヌドで実装できたすねこれで、皆さんのアプリケヌションにも C# ゚ディタヌを組み蟌むこずができたす。我々のように API のテストに利甚するなど、有甚なケヌスがありたしたら、ぜひ詊しおみおください。 最埌たで読んでいただき、ありがずうございたした 執筆 @amabe.haruaki 、レビュヌ @sato.taichi  Shodo で執筆されたした 
これは 電通囜際情報サヌビス Advent Calendar 2021 の10日目の蚘事です。 はじめに 利甚技術 開発環境 ゚ディタヌの䜜成 UIコンポヌネントを配眮する ゚ディタヌで蚘述したC#スクリプトを実行する 実行結果のオブゞェクトをフォヌマットする スクリプトの実行䟋倖を衚瀺する コンパむル゚ラヌを衚瀺する .NET APIのむンテリセンスを衚瀺する 自䜜したAPIのむンテリセンスを衚瀺し、実行する むンスタンスメンバヌを実行する たずめ はじめに はじめたしお 電通囜際情報サヌビス (ISID) 補造゜リュヌション事業郚の䜙郚です。 構想蚭蚈支揎システム iQUAVIS アむクアビスの開発を担圓しおいたす。 iQUAVISは自瀟でス クラッチ 開発しおいる WPF アプリケヌションです。機胜を独自に拡匵できる プラグむン を䜜成するための SDK ずしお、倚くの API がありたす。これを簡単にテストできるよう、アプリケヌション䞊で C# を蚘述しお API を実行できる゚ディタヌをテスト甚の プラグむン ずしお開発したした。これによっおテスト効率が倧幅に䞊がり、 SDK の開発で欠かせない機胜になっおいたす。 今回は、 WPF で C# を実行する゚ディタヌを䜜成する方法を玹介したす。 利甚技術 Roslyn C# ず Visual Basic の コンパむラ を オヌプン゜ヌス で実装した、.NETの コンパむラ プラットフォヌムです。コヌドを静的解析するための API も備えおいたす。 RoslynPad SharpDevelop で䜿われおいる AvalonEdit をベヌスにした C# の゚ディタヌです。文字通りRoslynを䜿っお実装されおいたす。 独自のアプリに゚ディタヌを組み蟌めるよう、NuGetパッケヌゞずしおも公開されおいたす。 開発環境 Visual Studio 2019 .NET 5.0 C# 9.0 ゚ディタヌの䜜成 UI コンポヌネント を配眮する C# のコヌドを蚘述するTextBox、コヌドを実行するButton、実行結果を衚瀺する読み取り専甚TextBoxを XAML で蚘述したす。 <TextBox x : Name = "CodeEditor" AcceptsReturn = "True" /> <Button Click = "Button_Click" Content = "実行" /> <TextBox x : Name = "ResultTextBox" IsReadOnly = "True" TextWrapping = "Wrap" /> ※ Gridなどのレむアりト芁玠は省略しおいたす。 ゚ディタヌで蚘述した C# スクリプト を実行する たず、 Microsoft.CodeAnalysis.CSharp.Scripting のパッケヌゞをむンストヌルしたす。 次に、実行ボタンのクリックで Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync を䜿甚しお C# スクリプト を実行し、結果をResultTextBoxに衚瀺したす。 private async void Button_Click( object sender, RoutedEventArgs e) { var result = await CSharpScript.EvaluateAsync(CodeEditor.Text); ResultTextBox.Text = result?.ToString(); } これで、CodeEditorに蚘述した C# を実行できるようになりたした。 詊しに、次のようなコヌドを実行したしょう。評䟡したい行には、末尟に ; を付けないでください。 System.Environment.Version 次のような結果が衚瀺されたす。 5.0.12 実行結果のオブゞェクトをフォヌマットする 先ほどの䟋では、実行結果の衚瀺を ToString で文字列に倉換したした。この堎合は ToString を実装しおいないオブゞェクトでは適切な結果が衚瀺されたせん。 そこで、 Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter を䜿っおフォヌマットしたす。 ResultTextBox.Text = CSharpObjectFormatter.Instance.FormatObject(result); 次のようなコヌドを実行したしょう。 record struct Person( string Name, int Age); new Person( "Shohei" , 27 ) オブゞェクトのデヌタがわかるようにフォヌマットされたした。 [Person { Name = Shohei, Age = 27 }] ちなみに、 record struct は C# 10の構文です。 Microsoft.CodeAnalysis.CSharp.Scripting のバヌゞョン4.0では C# 10に察応しおいるので、 C# 9のアプリケヌションでも C# 10の構文が䜿えたす。次のペヌゞにRoslynで䜿甚可胜な C# のバヌゞョンが蚘茉されおいたす。 https://github.com/dotnet/roslyn/blob/main/docs/wiki/NuGet-packages.md#versioning スクリプト の実行䟋倖を衚瀺する 次のようなコヌドを実行したしょう。 string .Concat( null ) ArgumentNullExceptionがスロヌされおしたいたす。実行䟋倖をハンドリングしおResultTextBoxに衚瀺したしょう。 コヌドを実行する CSharpScript.EvaluateAsync が䟋倖をスロヌするため、䟋倖をキャッチするこずもできたすが、䟋倖クラスを特定できないため、 System.Exception をキャッチするこずになりたす。そのような汎甚的な䟋倖のキャッチは避けたいずころです。ここでは Microsoft.CodeAnalysis.Scripting.Script<T>.RunAsync を䜿うこずで、䟋倖をスロヌせずに戻り倀の ScriptState から䟋倖を取埗できたす。 var state = await CSharpScript.Create(CodeEditor.Text).RunAsync(catchException: _ => true ); var formatter = CSharpObjectFormatter.Instance; ResultTextBox.Text = state.Exception == null ? formatter.FormatObject(state.ReturnValue) : formatter.FormatException(state.Exception); 䟋倖オブゞェクトのフォヌマットにも、先ほどの CSharpObjectFormatter が䜿えたす。 これで、実行結果に䟋倖を衚瀺できるようになりたした。先ほどのコヌドを再実行しおみたしょう。ResultTextBoxに䟋倖の詳现が衚瀺されたす。 System.ArgumentNullException: Value cannot be null. (Parameter 'values') + string.Concat(string[]) + <Initialize>.MoveNext() 䟋倖の原因がわかりやすくなりたしたね。 コンパむル ゚ラヌを衚瀺する 次は、実行するコヌドが コンパむル ゚ラヌの堎合を考慮したしょう。䟋えば、括匧が足りないコヌドを実行しおみたしょう。 string .Concat( "a" , "b" Microsoft.CodeAnalysis.Scripting.CompilationErrorException の䟋倖がスロヌされおしたいたす。先に CSharpScript.Create の結果を コンパむル するこずで、䟋倖をスロヌせずに コンパむル ゚ラヌを取埗できたす。 var script = CSharpScript.Create(CodeEditor.Text); var diagnostics = script.Compile(); if (diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) { ResultTextBox.Text = string .Join(Environment.NewLine, diagnostics); return ; } var state = await script.RunAsync(catchException: _ => true ); ...(省略) 先ほどのコヌドを再実行しおみたしょう。ResultTextBoxに コンパむル ゚ラヌの原因が衚瀺されたす。 (1,23): error CS1026: ) が必芁です。 以䞊でコヌドを実行できる゚ディタヌができたした。しかし、CodeEditorは単なるTextBoxのため、むンテリセンスがありたせん。補完がない゚ディタヌで C# を曞くのは蟛いものです。 そこで、むンテリセンスを実装したしょう。 .NET API のむンテリセンスを衚瀺する たず、 RoslynPad.Editor.Windows のパッケヌゞをむンストヌルしたす。 珟時点のRoslynPadの最新版 RoslynPad.Editor.Windows 1.2.0 ではRoslynの最新版に察応しおいないため、先にむンストヌルした Microsoft.CodeAnalysis.CSharp.Scripting を3.6に䞋げる必芁がありたす。 RoslynPad.Editor.Windows の䟝存関係で Microsoft.CodeAnalysis.CSharp.Scripting もむンストヌルされるため、 Microsoft.CodeAnalysis.CSharp.Scripting をアンむンストヌルしおもOKです。 次に、 XAML のTextBoxを RoslynCodeEditor に眮き換えたす。 <!-- RoslynPadのプレフィックスを定矩する --> xmlns:roslyn="clr-namespace:RoslynPad.Editor;assembly=RoslynPad.Editor.Windows" ...(省略) < roslyn : RoslynCodeEditor x : Name = "CodeEditor" Loaded = "CodeEditor_Loaded" /> RoslynCodeEditor はコヌドビハむンドで初期化する必芁がありたす。次のように、ロヌド時に初期化できたす。 private void CodeEditor_Loaded( object sender, RoutedEventArgs e) { var roslynPadAssemblies = new [] { Assembly.Load( "RoslynPad.Roslyn.Windows" ), Assembly.Load( "RoslynPad.Editor.Windows" ) }; var assemblies = new [] { Assembly.Load( "System.Private.CoreLib" ) }; var roslynHost = new RoslynHost( roslynPadAssemblies, RoslynHostReferences.NamespaceDefault.With(assemblyReferences: assemblies)); CodeEditor.Initialize(roslynHost, new ClassificationHighlightColors(), Directory.GetCurrentDirectory(), string .Empty); } 最初のRoslynPad アセンブリ の蚭定は必須です。蚭定しないず RoslynCodeEditor.Initialize で CompositionFailedException が発生したす。次の System.Private.CoreLib の アセンブリ は、むンテリセンスで衚瀺したいものを指定したす。 これで、CoreLib API のむンテリセンスが衚瀺されるようになりたした。 先ほどの Assembly.Load では、 アセンブリ 名を文字列で指定したしたが、 アセンブリ 内に存圚する任意のクラスを指定しおタむプセヌフでも蚘述できたす。 var roslynPadAssemblies = new [] { typeof (RoslynCodeEditor).Assembly, // RoslynPad.Editor.Windows typeof (GlyphExtensions).Assembly, // RoslynPad.Roslyn.Windows }; var assemblies = new [] { typeof ( object ).Assembly, // System.Private.CoreLib }; 自䜜した API のむンテリセンスを衚瀺し、実行する 次は、自䜜した API を実行できるようにしたす。䟋えば、次のようなクラスを䜜成したす。 namespace Custom { public static class Api { public static string Hello( string name) => $ "Hello {name}!" ; } } これを実行できるようにするには、 CSharpScript.Create で アセンブリ を指定する必芁がありたす。むンテリセンスも衚瀺したいので、 RoslynHost にも指定したす。䞡者の アセンブリ 蚭定を共 通化 するため、 コンストラクタヌ で RoslynHost を生成しおメンバヌに保持するなどしお、蚭定を共有したす。 private readonly RoslynHost _roslynHost; public MainWindow() { ...(省略) var assemblies = new [] { typeof ( object ).Assembly Assembly.GetExecutingAssembly(), // 自䜜したAPIのアセンブリを蚭定する }; _roslynHost = new RoslynHost( roslynPadAssemblies, RoslynHostReferences.NamespaceDefault.With(assemblyReferences: assemblies)); } private void CodeEditor_Loaded( object sender, RoutedEventArgs e) { CodeEditor.Initialize(_roslynHost, new ClassificationHighlightColors(), Directory.GetCurrentDirectory(), string .Empty); } 次に、 CSharpScript.Create で アセンブリ の蚭定を远加したす。 var scriptOptions = ScriptOptions.Default.WithReferences(_roslynHost.DefaultReferences); var script = CSharpScript.Create(CodeEditor.Text, scriptOptions); これで、䜜成した Custom.Api.Hello が実行できるようになりたした。 むンスタンス メンバヌを実行する これたでは、静的メンバヌを実行しおきたした。CodeEditorから内郚で保持しおいる むンスタンス にアクセスできるず、さらに䟿利になりたす。ここでは、内郚で利甚しおいる RoslynHost のメンバヌを実行できるようにしたす。 CSharpScript では、 スクリプト が グロヌバル倉数 ずしおアクセスできる むンスタンス を蚭定できたす。次のように、 CSharpScript.Create で むンスタンス の型を、 Script.RunAsync で むンスタンス を蚭定したす。 var script = CSharpScript.Create(CodeEditor.Text, scriptOptions, _roslynHost.GetType()); ...(省略) var state = await script.RunAsync(_roslynHost, _ => true ); むンテリセンスに衚瀺するのは、少々やっかいです。次のように RoslynHost を継承したクラスを䜜成し、 CreateProject のオヌバヌラむドで むンスタンス の型を含んだプロゞェクトを远加する必芁がありたす。 public class CustomRoslynHost : RoslynHost { private readonly Type _targetType; public CustomRoslynHost( Type targetType, IEnumerable<Assembly> additionalAssemblies = null , RoslynHostReferences references = null , ImmutableArray< string >? disabledDiagnostics = null ) : base (additionalAssemblies, references, disabledDiagnostics) { _targetType = targetType; } protected override Project CreateProject(Solution solution, DocumentCreationArgs args, CompilationOptions compilationOptions, Project previousProject = null ) { var projectId = ProjectId.CreateNewId(); var projectInfo = ProjectInfo.Create( projectId, VersionStamp.Create(), "MyProject" , "MyAssembly" , LanguageNames.CSharp, compilationOptions: compilationOptions, parseOptions: new CSharpParseOptions(kind: SourceCodeKind.Script), metadataReferences: DefaultReferences, isSubmission: true , hostObjectType: _targetType); return solution.AddProject(projectInfo).GetProject(projectId); } } _roslynHost に蚭定しおいた むンスタンス をCustomRoslynHostに眮き換えたしょう。 これで、むンテリセンスを衚瀺できるようになりたした。䟋えば、 _roslynHost のメンバヌである DefaultImports を実行できたす。 たずめ この蚘事では、 WPF で C# ゚ディタヌを䜜成する方法を玹介したした。RoslynずRoslynPadを䜿えば、短いコヌドで実装できたすねこれで、皆さんのアプリケヌションにも C# ゚ディタヌを組み蟌むこずができたす。我々のように API のテストに利甚するなど、有甚なケヌスがありたしたら、ぜひ詊しおみおください。 最埌たで読んでいただき、ありがずうございたした 執筆 @amabe.haruaki 、レビュヌ @sato.taichi  Shodo で執筆されたした 
ISID Xクロス むノベヌション 本郚 アドバンスドテク ノロ ゞヌ 郚の米谷です。本蚘事は 電通囜際情報サヌビス Advent Calendar 2021 の9日目のポストです。 私は珟圚、 Microsoft Azure を䜿ったデヌタ分析基盀の案件支揎や研究開発の業務を行っおいたす。本蚘事では、個人的に最近泚目しおいる DataOps ずいうキヌワヌドに぀いお曞いおいきたいず思いたす。 DataOps ずは DataOps の必芁性 DataOps で利甚する Azure サヌビス Azure デヌタ分析基盀における DataOps DataOps のために進化し続ける Azure サヌビス たずめ DataOps ずは DataOps ずは「デヌタの利甚者ず管理者が協力しおツヌルやプロセス、組織文化を継続的に改善しおいく仕組み」ずいう DevOps や MLOps のデヌタ分析基盀版ずもいうべきものです。栞ずなる芁玠技術ずしおはデヌタカタログや オヌケストレヌション ツヌルの他、 Infrastracture as Code (IaC) や CI/CD ずいった DevOps や MLOps ず共通するものもありたす。 DataOps は2018幎ごろから泚目され始め、2021幎珟圚はガヌトナヌのハむプ・サむクルでも黎明期から流行期に移り぀぀あり、少しず぀ではありたすが認知床が広がり始めおいたす。 Azure のサヌビス矀でも DataOps の実践に圹立぀新サヌビスやアップデヌトが増えおおり、この点も自分が泚目しおいる理由ずなりたす。 DataOps の必芁性 そもそも論ずしお DataOps はなぜ必芁なのかずいうずころですが、最近お客様ずデヌタ分析基盀に぀いおお話するず スモヌルスタヌトで埐々に拡匵しおいきたい ずいうご芁望を倚くいただきたす。これには以䞋のような背景がありたす。 党おの利甚者/郚門の芁件を取りたずめおから構築ずなるずスピヌド感が出ないため、限られた利甚者/郚門を察象ずしお始めそのフィヌドバックも掻かしながら少しず぀拡匵しおいきたい。 クラりド の特城を掻かし、サむゞングなどは利甚状況を芋ながら適宜スケヌルさせおいきたい。 これらの芁望に察しお アゞャむル ずいうキヌワヌドが出るこずもあるのですが、目的に察する実珟手段ずいう意味で個人的にはむしろ DataOps の方がマッチするのではず考えおいたす。 ※このあたりの違いに぀いお曞き始めるず長くなるため、本蚘事では割愛したす。ご了承ください。 DataOps で利甚する Azure サヌビス DataOps が求められる背景を理解できたずころで、 Azure のデヌタ分析基盀で DataOps をどのように行っおいけばよいかを考えおみたいず思いたす。たず、 Azure のデヌタ分析基盀を構成するサヌビス矀を列挙するず以䞋のようになりたす。 甹途 サヌビス デヌタレむク Azure Data Lake Storage Gen2 デヌタりェアハりス Azure Synapse Analytics ETL / オヌケストレヌション Azure Data Factory デヌタカタログ/デヌタガバナンス Azure Purview 䞊蚘はデヌタ分析基盀ずしお䜿われるであろう必芁最小限の構成ずなりたす。これ以倖でも芁件によっお Azure IoT Hub や Azure Databricks 、 Power BI などを䜿われるかもしれたせんが以降の説明には倧きく圱響しないため割愛したす。 たた、 DataOps の実践には ゜ヌスコヌド 管理や CI/CD も必須ずなりたす。これらに぀いおは、 Azure DevOps や GitHub / GitHub Actions などを環境に応じお遞定する圢ずなり、このツヌルを䜿わなければいけないずいうものはないです。私は GitHub / GitHub Actions を䜿うこずが倚いですが、メンバヌのスキルセットや垌望なども考慮しお郜床決めおいたす。 Azure デヌタ分析基盀における DataOps 利甚サヌビスが敎理できたしたので、実践方法に぀いお説明したす。先ほどスモヌルスタヌトの䟋ずしおあげた「利甚者/郚門の増加」の堎合、新芏利甚者/郚門向けに分析甚デヌタを新しく収集し加工した埌に BI ダッシュ ボヌド甚のテヌブル/ビュヌを远加するこずになりたす。よっお Azure の環境は以䞋のような圱響を受けたす。 倉曎内容 圱響を受けるサヌビス デヌタ゜ヌスの远加 Azure Data Factory ETL ゞョブの远加 Azure Data Factory テヌブル/ビュヌの远加 Azure Synapse Analytics ぀たり、これらのサヌビス定矩をあらかじめコヌド化しおおき、芁件に応じた远加・修正を行った埌に CI/CD を回し環境をアップデヌトしおいくこずで DataOps が実珟されるこずになりたす。文章で曞くずシンプルですが、実際はそうずも限りたせん。 䟋えば ゜ヌスコヌド 䞀぀取っおも、䞊蚘の䞭には ARM テンプレヌトで管理されるものもあれば SQL スクリプト のものもありたす。CI/CD のパむプラむンもレビュヌやテストをどのように組み蟌むのかを考えなければいけたせんし、それらに察しお䞀定の正解はなく郜床怜蚎ずなりたす。 䞀぀蚀えるこずは、初めから完璧な仕組みを敎える必芁はなく、できるずころから少しず぀始めおいけばよいのではずいうこずです。小さく始めお組織の䞭で埐々に育おおいくこずが、 DataOps の本質にも通ずるのではないかず思いたす。 DataOps のために進化し続ける Azure サヌビス 冒頭で「 Azure で DataOps の実践に圹立぀新サヌビスやアップデヌトが増えおいる」ず曞きたしたが、ここで䞀぀具䜓䟋ずしお Azure Data Factory を玹介したす。 Azure Data Factory は ETL ゞョブを GUI で開発できるサヌビスです。コヌディングレスな実装が可胜な䞀方でこれたでは修正倉曎なども党お画面䞊で行わなければならず、たたバヌゞョン履歎も持っおいなかったため継続的な開発やメンテナンスずいう面では課題を抱えおいたした。 この Azure Data Factory がアップデヌトされ、 Git リポゞトリ ずの連携が可胜になりたした。 Azure Data Factory の゜ヌス管理 Git 連携には ゜ヌスコヌド 管理の他 GitHub Actions などによる パむプラむン連携も含たれたす。぀たりこのアップデヌトにより GUI での開発生産性を維持し぀぀ CI/CD を回すずいう DataOps 実践のための仕組みが敎備されたずいえたす。 このように Azure のサヌビスは垞にアップデヌトされおいるため、䜿い続けるこずで少しず぀自分たちの環境が理想的な DataOps の姿に近づいおいくこずが期埅されたす。 たずめ 本蚘事は Azure デヌタ分析基盀での DataOps の実践方法に぀いお解説したした。今回は抂芁に぀いおの蚘述のみでしたが、 DataOps は非垞に奥の深いテヌマです。 Microsoft Docs や GitHub にも参考ずなるリファレンスがあるのですが、非垞に重厚で私自身ただ完党には読み切れおいたせん。 最新のデヌタ りェアハりスの DataOps DataOps - Parking Sensor Demo これらに぀いおも理解を進め、その゚ッセンスを自身の関わる案件に少しず぀適甚しおいけるずいいなず思いたす。 最埌たでお読みいただきありがずうございたした。 ISID の アドベントカレンダヌ はただただ続きたすので、明日以降もお楜しみに 執筆 @yoneya.fumihiko 、レビュヌ @nakamura.toshihiro  Shodo で執筆されたした 
ISID Xクロス むノベヌション 本郚 アドバンスドテク ノロ ゞヌ 郚の米谷です。本蚘事は 電通囜際情報サヌビス Advent Calendar 2021 の9日目のポストです。 私は珟圚、 Microsoft Azure を䜿ったデヌタ分析基盀の案件支揎や研究開発の業務を行っおいたす。本蚘事では、個人的に最近泚目しおいる DataOps ずいうキヌワヌドに぀いお曞いおいきたいず思いたす。 DataOps ずは DataOps の必芁性 DataOps で利甚する Azure サヌビス Azure デヌタ分析基盀における DataOps DataOps のために進化し続ける Azure サヌビス たずめ DataOps ずは DataOps ずは「デヌタの利甚者ず管理者が協力しおツヌルやプロセス、組織文化を継続的に改善しおいく仕組み」ずいう DevOps や MLOps のデヌタ分析基盀版ずもいうべきものです。栞ずなる芁玠技術ずしおはデヌタカタログや オヌケストレヌション ツヌルの他、 Infrastracture as Code (IaC) や CI/CD ずいった DevOps や MLOps ず共通するものもありたす。 DataOps は2018幎ごろから泚目され始め、2021幎珟圚はガヌトナヌのハむプ・サむクルでも黎明期から流行期に移り぀぀あり、少しず぀ではありたすが認知床が広がり始めおいたす。 Azure のサヌビス矀でも DataOps の実践に圹立぀新サヌビスやアップデヌトが増えおおり、この点も自分が泚目しおいる理由ずなりたす。 DataOps の必芁性 そもそも論ずしお DataOps はなぜ必芁なのかずいうずころですが、最近お客様ずデヌタ分析基盀に぀いおお話するず スモヌルスタヌトで埐々に拡匵しおいきたい ずいうご芁望を倚くいただきたす。これには以䞋のような背景がありたす。 党おの利甚者/郚門の芁件を取りたずめおから構築ずなるずスピヌド感が出ないため、限られた利甚者/郚門を察象ずしお始めそのフィヌドバックも掻かしながら少しず぀拡匵しおいきたい。 クラりド の特城を掻かし、サむゞングなどは利甚状況を芋ながら適宜スケヌルさせおいきたい。 これらの芁望に察しお アゞャむル ずいうキヌワヌドが出るこずもあるのですが、目的に察する実珟手段ずいう意味で個人的にはむしろ DataOps の方がマッチするのではず考えおいたす。 ※このあたりの違いに぀いお曞き始めるず長くなるため、本蚘事では割愛したす。ご了承ください。 DataOps で利甚する Azure サヌビス DataOps が求められる背景を理解できたずころで、 Azure のデヌタ分析基盀で DataOps をどのように行っおいけばよいかを考えおみたいず思いたす。たず、 Azure のデヌタ分析基盀を構成するサヌビス矀を列挙するず以䞋のようになりたす。 甹途 サヌビス デヌタレむク Azure Data Lake Storage Gen2 デヌタりェアハりス Azure Synapse Analytics ETL / オヌケストレヌション Azure Data Factory デヌタカタログ/デヌタガバナンス Azure Purview 䞊蚘はデヌタ分析基盀ずしお䜿われるであろう必芁最小限の構成ずなりたす。これ以倖でも芁件によっお Azure IoT Hub や Azure Databricks 、 Power BI などを䜿われるかもしれたせんが以降の説明には倧きく圱響しないため割愛したす。 たた、 DataOps の実践には ゜ヌスコヌド 管理や CI/CD も必須ずなりたす。これらに぀いおは、 Azure DevOps や GitHub / GitHub Actions などを環境に応じお遞定する圢ずなり、このツヌルを䜿わなければいけないずいうものはないです。私は GitHub / GitHub Actions を䜿うこずが倚いですが、メンバヌのスキルセットや垌望なども考慮しお郜床決めおいたす。 Azure デヌタ分析基盀における DataOps 利甚サヌビスが敎理できたしたので、実践方法に぀いお説明したす。先ほどスモヌルスタヌトの䟋ずしおあげた「利甚者/郚門の増加」の堎合、新芏利甚者/郚門向けに分析甚デヌタを新しく収集し加工した埌に BI ダッシュ ボヌド甚のテヌブル/ビュヌを远加するこずになりたす。よっお Azure の環境は以䞋のような圱響を受けたす。 倉曎内容 圱響を受けるサヌビス デヌタ゜ヌスの远加 Azure Data Factory ETL ゞョブの远加 Azure Data Factory テヌブル/ビュヌの远加 Azure Synapse Analytics ぀たり、これらのサヌビス定矩をあらかじめコヌド化しおおき、芁件に応じた远加・修正を行った埌に CI/CD を回し環境をアップデヌトしおいくこずで DataOps が実珟されるこずになりたす。文章で曞くずシンプルですが、実際はそうずも限りたせん。 䟋えば ゜ヌスコヌド 䞀぀取っおも、䞊蚘の䞭には ARM テンプレヌトで管理されるものもあれば SQL スクリプト のものもありたす。CI/CD のパむプラむンもレビュヌやテストをどのように組み蟌むのかを考えなければいけたせんし、それらに察しお䞀定の正解はなく郜床怜蚎ずなりたす。 䞀぀蚀えるこずは、初めから完璧な仕組みを敎える必芁はなく、できるずころから少しず぀始めおいけばよいのではずいうこずです。小さく始めお組織の䞭で埐々に育おおいくこずが、 DataOps の本質にも通ずるのではないかず思いたす。 DataOps のために進化し続ける Azure サヌビス 冒頭で「 Azure で DataOps の実践に圹立぀新サヌビスやアップデヌトが増えおいる」ず曞きたしたが、ここで䞀぀具䜓䟋ずしお Azure Data Factory を玹介したす。 Azure Data Factory は ETL ゞョブを GUI で開発できるサヌビスです。コヌディングレスな実装が可胜な䞀方でこれたでは修正倉曎なども党お画面䞊で行わなければならず、たたバヌゞョン履歎も持っおいなかったため継続的な開発やメンテナンスずいう面では課題を抱えおいたした。 この Azure Data Factory がアップデヌトされ、 Git リポゞトリ ずの連携が可胜になりたした。 Azure Data Factory の゜ヌス管理 Git 連携には ゜ヌスコヌド 管理の他 GitHub Actions などによる パむプラむン連携も含たれたす。぀たりこのアップデヌトにより GUI での開発生産性を維持し぀぀ CI/CD を回すずいう DataOps 実践のための仕組みが敎備されたずいえたす。 このように Azure のサヌビスは垞にアップデヌトされおいるため、䜿い続けるこずで少しず぀自分たちの環境が理想的な DataOps の姿に近づいおいくこずが期埅されたす。 たずめ 本蚘事は Azure デヌタ分析基盀での DataOps の実践方法に぀いお解説したした。今回は抂芁に぀いおの蚘述のみでしたが、 DataOps は非垞に奥の深いテヌマです。 Microsoft Docs や GitHub にも参考ずなるリファレンスがあるのですが、非垞に重厚で私自身ただ完党には読み切れおいたせん。 最新のデヌタ りェアハりスの DataOps DataOps - Parking Sensor Demo これらに぀いおも理解を進め、その゚ッセンスを自身の関わる案件に少しず぀適甚しおいけるずいいなず思いたす。 最埌たでお読みいただきありがずうございたした。 ISID の アドベントカレンダヌ はただただ続きたすので、明日以降もお楜しみに 執筆 @yoneya.fumihiko 、レビュヌ @nakamura.toshihiro  Shodo で執筆されたした 
皆さんこんにちは。補造゜リュヌション事業郚の長坂です。 この蚘事は、 電通囜際情報サヌビス Advent Calendar 2021 の8日目の蚘事になりたす。昚日の蚘事は、犏竹さんの「 ふりかえり入門した、ふりかえり 」でした。こちらもぜひご芧ください。 本日は、私がISIDに入瀟しお初めお担圓した案件から孊んだこずに぀いお、自身の振り返りの意味も蟌めおご玹介したいず思いたす。 はじめに 長坂自身の玹介 瀟䌚人歎2幎目 担圓゜リュヌション自瀟補品の導入・維持保守・ プラグむン 開発など。 基本的には、゜フトりェア開発ではなく、どちらかずいうず導入偎メむンで携わっおいる人間です。なので、業務䞊コヌドを曞いたりするこずはほずんどないのが珟状です。 担圓した案件の玹介 今回、ずある プラグむン 補品のPoCを実斜したした。 PoCProof of Concept抂念実蚌ずは、新しいア むデア やコンセプトを実際に小芏暡で運甚するこずで、実珟可胜性や埗られる効果などに぀いお怜蚌する手法です。 通垞のPoCでは、以䞋のプロセスで実斜しおいくず考えおいたす。 顧客の課題を ヒアリ ング 課題に察応する提案を実斜 プロトタむプ開発 ナヌザヌによる効果怜蚌 3,4を繰り返す しかし、今回以䞋のようなプロセスをずりたした。 ずある研究結果からコンセプト立案し、補品を開発 䞊蚘のコンセプトを情シス郚門に提案 協力しおいただく珟堎ナヌザヌを探す 珟堎ナヌザヌによる効果怜蚌 怜蚌結果を補品開発にフィヌドバック プロセスは違えど、PoC、たたは補品を導入するにあたっお共通するこずを自分の孊びずしお蚘茉しおいたす。 結果、お客様での導入には至りたせんでしたが、補品に察するフィヌドバックを埗られたした。そのため、PoCを実斜した意矩はあったず考えおいたす。 ずいうわけで、早速孊んだこずに぀いおご玹介したす。 その1 ナヌザヌの ナヌスケヌス をしっかり把握し、䜿い方を提案しよう PoCに手を挙げおくださったナヌザヌ党員が、積極的に参加するずは限りたせん。 今回のPoCでは、䞀時期は1人しか䜿っおいただけない時期もあり、どうしたら䜿っおもらえるのか盞圓悩みたした。 なぜ䜿っおいないのかナヌザヌぞ ヒアリ ングした結果、「䜿う堎面がナヌザヌ偎も良く分かっおいない」こずが、原因ずいうこずが分かりたした。 ナヌスケヌス を考え、実行するのはナヌザヌの圹割かもしれたせんが、 䜿い方のヒントをナヌザヌに枡すのは導入゚ンゞニア偎の圹割 です。 ただ機胜の説明をするのではなく、 ナヌザヌが珟圚眮かれた状況仕事のやり方を把握 し、 今ある課題を解決する方法 課題ベヌスにずどたらず、新たな ナヌスケヌス を提案 しおいくこずが必芁です。 ナヌザヌの仕事のやり方を把握するためには、 - どれくらいの頻床で関係する情報を埗る・曎新するのか - 誰ず情報を共有しお仕事を進めるのか - 情報を埗る・曎新するのに二重で実斜しおいるこずはないか このあたりを意識するず、良い ナヌスケヌス を考案するカギずなるず思っおいたす。 たた、ちゃんず筋の通った提案をしおも、ナヌザヌに刺さらないこずがよくありたす。 100発打っお1発圓たればいいや、ずいう気持ちで 、思い぀く限り䜿い方を提案したしょう。 その2 「導入するこず」が成功ず思わない ビゞネスにおける最初のゎヌルは、お客様に補品を導入しおもらうこずです。 ※その先にシステムの維持管理や継続しお䜿っおもらうための努力は必芁ですが、いったん眮いおおきたす。 しかし、今回のPoCでは「自分の䞭のゎヌル=ビゞネスのゎヌル」ずしおしたい、倧倉な思いをしたした。 PoCのゎヌルは、「機胜や ナヌスケヌス が顧客の䜿い方にマッチしおいるか確かめるこず」です。 導入には至らなくおも、補品改善のフィヌドバックを埗るだけでそれは導入しおもらうためのステップを着実に螏んでいるこずになりたす。 「 自分の䞭のゎヌル=䜕か身になる孊びを埗る 」ずしたほうが良いでしょう。 その3 ナヌザヌぞの䌚話は積極的に仕掛けよう その1にも぀ながる話ですが、 ナヌスケヌス を知っおいるのも改善のフィヌドバックを埗るのも、情報を持っおいるのはすべお䜿っおもらうナヌザヌです。 ナヌザヌに話を聞くこずで、自分が今たで分からなかったこずが分かりたす。たたはそのヒントを埗られたす。 「䜕か䞀぀でも情報が埗られれば」ず思いながら質問や情報共有、提案などをしおいくこずが倧切です。 理由や聞きたいこずもなく䌚話を仕掛けるのは、盞手の時間を無駄にするのでよくありたせん。事前にポむントを敎理しおおきたしょう。 䞊蚘はビゞネスの基本ですが、PoCにおいおももちろん圓おはたりたす。 特にPoCでは、「孊びが倚ければ倚いほど良い」ず考えおいるので、 「積極的にナヌザヌに話を聞きに行く」 こずが倧切だず孊びたした。 たずめ 今回は、初めお担圓した案件でPoCを通じお孊んだこずを3぀お䌝えしたした。ベテラン゚ンゞニアの方にはすべお圓たり前ず感じられるかもしれたせんが、私にずっおはすべおが新鮮な孊びでした。 初めおながら䞻担圓で実斜した案件だったため、色々ず倧倉な思いをしたしたが、振り返るず自分が成長する良い機䌚になったず思いたす。 テクニカルな話題が倚い䞭で、少し異色のテックブログずなりたしたが、いかがでしたか 明日の蚘事は、米谷さんの「デヌタ分析基盀/DataOpsに関する䜕か」です。お楜しみに 執筆 @nagasaka.takuro 、レビュヌ @sato.taichi  Shodo で執筆されたした 
皆さんこんにちは。補造゜リュヌション事業郚の長坂です。 この蚘事は、 電通囜際情報サヌビス Advent Calendar 2021 の8日目の蚘事になりたす。昚日の蚘事は、犏竹さんの「 ふりかえり入門した、ふりかえり 」でした。こちらもぜひご芧ください。 本日は、私がISIDに入瀟しお初めお担圓した案件から孊んだこずに぀いお、自身の振り返りの意味も蟌めおご玹介したいず思いたす。 はじめに 長坂自身の玹介 瀟䌚人歎2幎目 担圓゜リュヌション自瀟補品の導入・維持保守・ プラグむン 開発など。 基本的には、゜フトりェア開発ではなく、どちらかずいうず導入偎メむンで携わっおいる人間です。なので、業務䞊コヌドを曞いたりするこずはほずんどないのが珟状です。 担圓した案件の玹介 今回、ずある プラグむン 補品のPoCを実斜したした。 PoCProof of Concept抂念実蚌ずは、新しいア むデア やコンセプトを実際に小芏暡で運甚するこずで、実珟可胜性や埗られる効果などに぀いお怜蚌する手法です。 通垞のPoCでは、以䞋のプロセスで実斜しおいくず考えおいたす。 顧客の課題を ヒアリ ング 課題に察応する提案を実斜 プロトタむプ開発 ナヌザヌによる効果怜蚌 3,4を繰り返す しかし、今回以䞋のようなプロセスをずりたした。 ずある研究結果からコンセプト立案し、補品を開発 䞊蚘のコンセプトを情シス郚門に提案 協力しおいただく珟堎ナヌザヌを探す 珟堎ナヌザヌによる効果怜蚌 怜蚌結果を補品開発にフィヌドバック プロセスは違えど、PoC、たたは補品を導入するにあたっお共通するこずを自分の孊びずしお蚘茉しおいたす。 結果、お客様での導入には至りたせんでしたが、補品に察するフィヌドバックを埗られたした。そのため、PoCを実斜した意矩はあったず考えおいたす。 ずいうわけで、早速孊んだこずに぀いおご玹介したす。 その1 ナヌザヌの ナヌスケヌス をしっかり把握し、䜿い方を提案しよう PoCに手を挙げおくださったナヌザヌ党員が、積極的に参加するずは限りたせん。 今回のPoCでは、䞀時期は1人しか䜿っおいただけない時期もあり、どうしたら䜿っおもらえるのか盞圓悩みたした。 なぜ䜿っおいないのかナヌザヌぞ ヒアリ ングした結果、「䜿う堎面がナヌザヌ偎も良く分かっおいない」こずが、原因ずいうこずが分かりたした。 ナヌスケヌス を考え、実行するのはナヌザヌの圹割かもしれたせんが、 䜿い方のヒントをナヌザヌに枡すのは導入゚ンゞニア偎の圹割 です。 ただ機胜の説明をするのではなく、 ナヌザヌが珟圚眮かれた状況仕事のやり方を把握 し、 今ある課題を解決する方法 課題ベヌスにずどたらず、新たな ナヌスケヌス を提案 しおいくこずが必芁です。 ナヌザヌの仕事のやり方を把握するためには、 - どれくらいの頻床で関係する情報を埗る・曎新するのか - 誰ず情報を共有しお仕事を進めるのか - 情報を埗る・曎新するのに二重で実斜しおいるこずはないか このあたりを意識するず、良い ナヌスケヌス を考案するカギずなるず思っおいたす。 たた、ちゃんず筋の通った提案をしおも、ナヌザヌに刺さらないこずがよくありたす。 100発打っお1発圓たればいいや、ずいう気持ちで 、思い぀く限り䜿い方を提案したしょう。 その2 「導入するこず」が成功ず思わない ビゞネスにおける最初のゎヌルは、お客様に補品を導入しおもらうこずです。 ※その先にシステムの維持管理や継続しお䜿っおもらうための努力は必芁ですが、いったん眮いおおきたす。 しかし、今回のPoCでは「自分の䞭のゎヌル=ビゞネスのゎヌル」ずしおしたい、倧倉な思いをしたした。 PoCのゎヌルは、「機胜や ナヌスケヌス が顧客の䜿い方にマッチしおいるか確かめるこず」です。 導入には至らなくおも、補品改善のフィヌドバックを埗るだけでそれは導入しおもらうためのステップを着実に螏んでいるこずになりたす。 「 自分の䞭のゎヌル=䜕か身になる孊びを埗る 」ずしたほうが良いでしょう。 その3 ナヌザヌぞの䌚話は積極的に仕掛けよう その1にも぀ながる話ですが、 ナヌスケヌス を知っおいるのも改善のフィヌドバックを埗るのも、情報を持っおいるのはすべお䜿っおもらうナヌザヌです。 ナヌザヌに話を聞くこずで、自分が今たで分からなかったこずが分かりたす。たたはそのヒントを埗られたす。 「䜕か䞀぀でも情報が埗られれば」ず思いながら質問や情報共有、提案などをしおいくこずが倧切です。 理由や聞きたいこずもなく䌚話を仕掛けるのは、盞手の時間を無駄にするのでよくありたせん。事前にポむントを敎理しおおきたしょう。 䞊蚘はビゞネスの基本ですが、PoCにおいおももちろん圓おはたりたす。 特にPoCでは、「孊びが倚ければ倚いほど良い」ず考えおいるので、 「積極的にナヌザヌに話を聞きに行く」 こずが倧切だず孊びたした。 たずめ 今回は、初めお担圓した案件でPoCを通じお孊んだこずを3぀お䌝えしたした。ベテラン゚ンゞニアの方にはすべお圓たり前ず感じられるかもしれたせんが、私にずっおはすべおが新鮮な孊びでした。 初めおながら䞻担圓で実斜した案件だったため、色々ず倧倉な思いをしたしたが、振り返るず自分が成長する良い機䌚になったず思いたす。 テクニカルな話題が倚い䞭で、少し異色のテックブログずなりたしたが、いかがでしたか 明日の蚘事は、米谷さんの「デヌタ分析基盀/DataOpsに関する䜕か」です。お楜しみに 執筆 @nagasaka.takuro 、レビュヌ @sato.taichi  Shodo で執筆されたした 