電通総研のブログ - TECH PLAY

TECH PLAY

電通総研

電通総研 の技術ブログ

å…š849ä»¶

これは 電通囜際情報サヌビス アドベントカレンダヌ の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 で執筆されたした 
 こんにちは。ISID XI 本郚 AI トランスフォヌメヌションセンタヌ所属の犏竹です。  本蚘事は ISIDアドベントカレンダヌ蚘事 の7日目の蚘事ずなりたす。 これは䜕(TL;DR) Why ふりかえりふりかえりに興味を持぀たで What is ふりかえり(ふりかえりっお䜕) Y:やったこずやっおいるこず 1. きちんず時間をずっお、開発スプリント毎のふりかえりスプリントレトロスペクティブをやるやった 2. 開発業務以倖にも、珟状認識のチェックやアむデア出しにKPTやEffort&Pain等のフレヌムワヌクを䜿っおみた W:わかったこず気付き 基本はKPT。しかし曞き方や時間配分は基本を守ったほうが良い。 ツヌルはなんだっおいい。ただ、参加者にずっお平等で、盎感的に䜿いやすいこずは倧事。 アレンゞする時は「䜕が目的か」「迷いなくスコヌプを芋぀めおもらえるか」を考えおおくこずが倧事。 リモヌトファシリテヌションに「ふりかえり」は効く。 T:぀ぎやるこず これは䜕(TL;DR)  ふりかえり初心者が「ふりかえり」に興味を持ち、今幎やっお詊したこず考えたこずのふりかえりです。色々曞きたすが、コアメッセヌゞは䞀぀「ふりかえりはいいぞ」に尜きたす。 Why ふりかえりふりかえりに興味を持぀たで   私の所属する組織 では、内補 スクラム でプロダクト開発をしおいたす。10人匱の開発チヌム党員が䜕らかプロダクトの開発者であり スクラム メンバヌずいうチヌム構成です。筆者個人は今幎この開発チヌムにゞョむンし、珟圚はプロダクトの1぀の スクラム マスタヌ修行䞭を務めおいたす。    ずは蚀ったものの、私自身 スクラム 開発は珟職が初めおの経隓で、個人的に本幎はキャッチアップず詊行錯誀の幎でした。少しでもベヌス知識を 仕入 れようず スクラム 関連の曞籍を読み持っおいたのですが、そんな折に誘われた瀟内の読曞䌚※仕掛け人はアドカレ6日目の橋詰さんで本蚘事を曞くきっかけの䞀冊に行き圓たりたす。 アゞャむルなチヌムを぀くる ふりかえりガむドブック 始め方・ふりかえりの型・手法・マむンドセット  「ふりかえり」ずいう手法が色々ず琎線に觊れた事もあり、本曞片手にチヌムメンバヌの協力をいただきながら詊行錯誀した事が、本日の本蚘事のネタになりたす。 What is ふりかえり(ふりかえりっお䜕)  本蚘事はHow toを䞻県にしないので詳しくは割愛させおください。具䜓感ずしおは、「YWT」「 KPT 」「FUN/DONE/LEARN」等の、 アゞャむル レトロスペクティブに端を発するそしお実際のずころ アゞャむル 開発関係なく掻甚できるアクティビティを想定しおいたす。詳しくは是非ずも参考曞籍情報を埡芧ください。 Y:やったこずやっおいるこず  やったこずそのものはシンプルです。 1. きちんず時間をずっお、開発スプリント毎のふりかえりスプリントレトロスペクティブをやるやった  最初に気付いた事は、担圓補品のチヌムで既存メンバヌが忙しすぎお、数ヶ月ほどふりかえりスプリントレトロスペクティブが止たっおいた事でした。そこで開発の山を超えたあたりで私が無邪気に「ふりかえりやりたい」ず蚀い出しお、月1皋床の頻床で、ふりかえりを蚭定しお実斜するこずにしたした。そしお蚀い出しっぺの暩限で奜きに アゞェンダ を組たせお貰いたした。基本的な事ですが、けっこう状況ずしおはあるあるだず思いたす。  ずはいえ最初は右も巊も分からないので、「ふりかえりガむドブック」付属の「 チヌトシヌト 」を参考に恐る恐る アゞェンダ を組みたした。以埌も基本的には䞀郚を組み替え぀぀、 チヌトシヌト を参考にしおいたす。拙くお恐瞮ですが、 アゞェンダ 䟋45分はこんな感じです。私がそうだったのですが、やりはじめは具䜓䟋を知りたくなるず思うので茉せおおきたす。2回目以降も、基本は「 KPT 」を軞に同じような内容で蚭定したした 垌望ず懞念信号機5分アむスブレむク兌、期埅倀の確認 KPT 15分ふりかえりの本䞞 TをEffort&Painで敎理5分なるべく小さくすぐ始められるTryを集める /⊿でふりかえりのふりかえり5分次回ぞのフィヌドバック回収  なお開発チヌムはフルリモヌトで業務を行っおおり、ふりかえりの実斜もWeb䌚議です。色々考えお SharePoint 䞊に配眮した PowerPoint でホワむトボヌド颚のペヌゞを甚意しお、時折画面共有しながら時間䞭にOnlineで共同線集する䜜戊をずりたした。意倖ず成立したす。 2. 開発業務以倖にも、珟状認識のチェックやア むデア 出しに KPT やEffort&Pain等の フレヌムワヌク を䜿っおみた  1を䜕床か補品開発の スクラム でやっお気を良くした私は、マネヌゞャヌに盞談しおチヌムMTGでも「ふりかえり」チックなグルヌプワヌクを詊すこずにしたした。䞀般化しづらい内容なので具䜓的には曞きたせんが、「䞊半期のxxを振り返り぀぀来幎のyy 戊略を考える」みたいな内容にグルヌプワヌクを持ち蟌むようなむメヌゞです。  こちらに぀いおの気付きは埌述したすが、成立こそしたものの課題もありずいう感じでした。 W:わかったこず気付き  ここからは、実際に「ふりかえり」に取り組んでみお、わかったこずや気付きを䜕個か曞いおいきたす。 基本は KPT 。しかし曞き方や時間配分は基本を守ったほうが良い。  環境によっお差はあるかもしれたせんが、倧抵の人がすんなり入っおくれるのは KPT かなず感じおいたす。ただ人数にもよりたすが、 曞き方ず時間配分は基本を厩さないほうがいい ず感じおいたす。基本ずいうのは、この蟺です。 KeepずProblemずTryを曞くタむミングは分ける。 グルヌプワヌクずしおの KPT は他メンバヌの曞いた内容からも気付きを埗おほしい。たずめおやるず個人が持っおいる KPT の論理展開を曞いおしたいがち。 Kでポゞティブにスコヌプを振り返る時間をきちんず取る。 これが䞍十分だずPTが個人の反省䌚になりがち。 そしおKのシヌケンスは倚少共感や発芋を重芖する。「あ、こんないい事あったんだ」ず思えたらしめたもので、「どうしたら他にも良くできただろう」ずいう方向にいく 1 。  たた KPT は最埌のTを、きちんず明日からのTryに繋げおいくのが䞀番難しいなず感じおいたす。぀い぀いPの議論は盛り䞊がりがちですが、Tもちゃんず時間を取っお党員で敎理しないず、せっかくメンバヌが出しおくれたTryを積み残しがちでした。この蟺はただ修行䞭です。Feasible & Useful実珟可胜性ず有甚性の2軞でTryをプロットするなども䜿いながら、党員で芋える圢にしお実珟性や優先床を敎理するず改善に繋がりやすいかなず感じおいたす。 ツヌルはなんだっおいい。ただ、参加者にずっお平等で、盎感的に䜿いやすいこずは倧事。  党員がフルリモヌトの状況でふりかえりを始めようず思った時に、最初に迷ったのがツヌルでした。専甚ツヌルでオサレにやりたい欲が頭をよぎったものの「 初回はずにかく説明なしで誰もがすぐ入れるもので 」ず思い、匊瀟ではOffice 365が浞透しおいた事をふたえお、 PowerPoint を online線集する圢を取りたした。奜みもあるず思いたすが、Office 365が利甚できる環境であれば、手っ取り早い遞択肢の䞀぀ずしおお勧めです。  結局この蟺りは ファシリテヌタヌ が ファシリテヌション しやすいかで決めおいいず思いたすが、同時に倧事かなず感じおいるのは「 参加者にずっお平等で、盎感的に䜿いやすい事 」だず思っおいたす。䟋えば KPT を個人で曞き出すだけなら曞き䞋しのメモ垳やチャットツヌルのスレッドでも可胜ですが、グルヌプワヌクずしおのふりかえりでは各人のアむテムがなるべく平等に䞊んでいる状態が理想です。テキストの曞き䞋しはどうしおも順序性に瞛られおしたい、オンラむンな議論よりも バッチ凊理 的な読み䞋しになりがちです。  この点ホワむトボヌドツヌルに類するものは、䜍眮を移動させる事で簡単に近䌌性や階局構造をその堎で衚珟できるそしお違っおいたら戻せるのが圧倒的に有利です。いかに䌚議宀で暡造玙に貌る付箋が芁件を満たしおいたかを再発芋した気分でした。 アレンゞする時は「䜕が目的か」「迷いなくスコヌプを芋぀めおもらえるか」を考えおおくこずが倧事。  アレンゞはただあたりしおいたせんが 2 、目的が ファシリテヌタヌ の䞭でハッキリしおいれば、アクティビティの倚少の組み替えは機胜したした。  ただ圓たり前かもしれたせんが、アレンゞを組み蟌む時は、「この曞き方で参加者党員が同じように受け取れるか」よくよく考えお準備する必芁もありたすふりかえりに限った話ではないでしょうけど。  少し恥ずかしい倱敗䟋ですが、メンバヌがグルヌプワヌクに慣れおきたあたりで、ふりかえりに関係のない MTG でも自己流のグルヌプワヌクを蚭定しおみたした。ずころが参加者からは「これっおどこたでを含みたすか」「○○は含たれたすか」ずいう質問が頻発しお認識合わせに意倖ず時間を䜿っおしたいたした。自己流が党くダメずは蚀いたせんが、こんな質問が参加者から頻発する堎合は、 甚意した枠組みが本圓に抜け挏れ、重耇のないものか  たた 蚀葉の定矩が参加者共通で認識できおいるか よく問い盎す必芁があるず気付かされたした。そしおふりかえりの既存手法は盎感的にこの蟺りをクリアしやすいよう簡朔になっおいるのだな、ずいう事にも気付けたした。 リモヌト ファシリテヌション に「ふりかえり」は効く。  結局のずころ自分がふりかえりに惹かれたのは 「どうすればリモヌトワヌクでも発散系 MTG を実りあるものにできるか」ずいう問題意識に䞀番ミヌトした ずいうのもありたす。Web䌚議はどうしおも同時発話が成立しづらかったり、同期的な議論がしづらい堎面があっお、その点決たったルヌルに埓っお非同期で参加者が個人の考えを曞き出しおいくシヌケンスを挟む方匏は盞性が良いず感じおいたす。  以䞊、倚少シチュ゚ヌション䟝存の内容になるため䞀般化しづらい内容もありたすが、䜕かしらの参考になれば幞いです。 T:぀ぎやるこず  個人的に次やりたいこずは色々ありたす。本蚘事を曞きながら色々ず調べおいお、発端になったガむドブック䜜者の森さんが結構な量のリ゜ヌスを公開しおいるこずに気付きたした。ある皋床自分でTryした埌に、こうした倖郚情報でノりハり面を 仕入 れ続けるのは効果が高そうだず感じおいたす。 Qiita:ふりかえりを拡匵する「ふりかえりカタログ」   埌は䜕冊か他の本にも朜っおみようかなず思いたす。 アゞャむルレトロスペクティブズ 匷いチヌムを育おる「ふりかえり」の手匕き  たた自戒を蟌めおですが 「ふりかえりっお結局䜕のためにやるの」 ずいう問いぞの答えは垞に考えおおきたいずころです。この答えはおそらく、ふりかえりを実斜する堎面や人、チヌムによっお様々だず思いたす。この点は、最埌に少しだけ自分たちの䟡倀芳の話をしたす。 ナニコヌン䌁業のひみ぀  今幎チヌムで読んだ曞籍に「 ナニコヌン 䌁業のひみ぀」ずいう曞籍がありたす玠晎らしい本です。この曞籍の奜きな䞀節に 「スタヌトアップの本質は『孊習する機械』であるこず」 ずいう蚀葉がありたす。  私達はスタヌトアップでこそありたせんが、チヌムずしお垞に孊習するこず、成長するこずを重芖しおいたす。ふりかえりの目的や捉え方は様々かず思いたすが、私は「チヌムが孊習する機械であるために有甚なアクティビティの1぀」だず捉えおいたす。アクティビティずしおのふりかえりは楜しみ぀぀、この蟺りの䟡倀芳を䜓珟できるよう「チヌムで柔軟に詊し続ける・倉え続ける」 姿勢を今埌もセットで倧事にしたいず考えおいたす。  皆様も是非、よきふりかえりラむフを。 執筆 @fhiroaki 、レビュヌ @sato.taichi  Shodo で執筆されたした  同じような話が及川さんの tweet にも出おいお、あぁりチだけじゃなかったんだなぁず。以䞋たずめは珟堎の知芋がいっぱい集たっおるのでおすすめです。 TogetterリンクKPT (Keep/Problem/Try) 等のふりかえりで、K (Keep) ネタを増やすみんなの工倫 ↩ 「KずPは事前に曞いお読み䞊げの時間は取らず、圓日は他のメンバのものをじっず読んでレスポンスする時間にする」メンバが発話に慣れお来たこず前提で、蚘述量が増えおきた埌の時間短瞮ずしお「KをFUN/DONE/LEARN に眮き換えおそのたたPTに行く」メンバの成果の承認に時間を取りたいくらいでしょうか。 ↩
 こんにちは。ISID XI 本郚 AI トランスフォヌメヌションセンタヌ所属の犏竹です。  本蚘事は ISIDアドベントカレンダヌ蚘事 の7日目の蚘事ずなりたす。 これは䜕(TL;DR) Why ふりかえりふりかえりに興味を持぀たで What is ふりかえり(ふりかえりっお䜕) Y:やったこずやっおいるこず 1. きちんず時間をずっお、開発スプリント毎のふりかえりスプリントレトロスペクティブをやるやった 2. 開発業務以倖にも、珟状認識のチェックやアむデア出しにKPTやEffort&Pain等のフレヌムワヌクを䜿っおみた W:わかったこず気付き 基本はKPT。しかし曞き方や時間配分は基本を守ったほうが良い。 ツヌルはなんだっおいい。ただ、参加者にずっお平等で、盎感的に䜿いやすいこずは倧事。 アレンゞする時は「䜕が目的か」「迷いなくスコヌプを芋぀めおもらえるか」を考えおおくこずが倧事。 リモヌトファシリテヌションに「ふりかえり」は効く。 T:぀ぎやるこず これは䜕(TL;DR)  ふりかえり初心者が「ふりかえり」に興味を持ち、今幎やっお詊したこず考えたこずのふりかえりです。色々曞きたすが、コアメッセヌゞは䞀぀「ふりかえりはいいぞ」に尜きたす。 Why ふりかえりふりかえりに興味を持぀たで   私の所属する組織 では、内補 スクラム でプロダクト開発をしおいたす。10人匱の開発チヌム党員が䜕らかプロダクトの開発者であり スクラム メンバヌずいうチヌム構成です。筆者個人は今幎この開発チヌムにゞョむンし、珟圚はプロダクトの1぀の スクラム マスタヌ修行䞭を務めおいたす。    ずは蚀ったものの、私自身 スクラム 開発は珟職が初めおの経隓で、個人的に本幎はキャッチアップず詊行錯誀の幎でした。少しでもベヌス知識を 仕入 れようず スクラム 関連の曞籍を読み持っおいたのですが、そんな折に誘われた瀟内の読曞䌚※仕掛け人はアドカレ6日目の橋詰さんで本蚘事を曞くきっかけの䞀冊に行き圓たりたす。 アゞャむルなチヌムを぀くる ふりかえりガむドブック 始め方・ふりかえりの型・手法・マむンドセット  「ふりかえり」ずいう手法が色々ず琎線に觊れた事もあり、本曞片手にチヌムメンバヌの協力をいただきながら詊行錯誀した事が、本日の本蚘事のネタになりたす。 What is ふりかえり(ふりかえりっお䜕)  本蚘事はHow toを䞻県にしないので詳しくは割愛させおください。具䜓感ずしおは、「YWT」「 KPT 」「FUN/DONE/LEARN」等の、 アゞャむル レトロスペクティブに端を発するそしお実際のずころ アゞャむル 開発関係なく掻甚できるアクティビティを想定しおいたす。詳しくは是非ずも参考曞籍情報を埡芧ください。 Y:やったこずやっおいるこず  やったこずそのものはシンプルです。 1. きちんず時間をずっお、開発スプリント毎のふりかえりスプリントレトロスペクティブをやるやった  最初に気付いた事は、担圓補品のチヌムで既存メンバヌが忙しすぎお、数ヶ月ほどふりかえりスプリントレトロスペクティブが止たっおいた事でした。そこで開発の山を超えたあたりで私が無邪気に「ふりかえりやりたい」ず蚀い出しお、月1皋床の頻床で、ふりかえりを蚭定しお実斜するこずにしたした。そしお蚀い出しっぺの暩限で奜きに アゞェンダ を組たせお貰いたした。基本的な事ですが、けっこう状況ずしおはあるあるだず思いたす。  ずはいえ最初は右も巊も分からないので、「ふりかえりガむドブック」付属の「 チヌトシヌト 」を参考に恐る恐る アゞェンダ を組みたした。以埌も基本的には䞀郚を組み替え぀぀、 チヌトシヌト を参考にしおいたす。拙くお恐瞮ですが、 アゞェンダ 䟋45分はこんな感じです。私がそうだったのですが、やりはじめは具䜓䟋を知りたくなるず思うので茉せおおきたす。2回目以降も、基本は「 KPT 」を軞に同じような内容で蚭定したした 垌望ず懞念信号機5分アむスブレむク兌、期埅倀の確認 KPT 15分ふりかえりの本䞞 TをEffort&Painで敎理5分なるべく小さくすぐ始められるTryを集める /⊿でふりかえりのふりかえり5分次回ぞのフィヌドバック回収  なお開発チヌムはフルリモヌトで業務を行っおおり、ふりかえりの実斜もWeb䌚議です。色々考えお SharePoint 䞊に配眮した PowerPoint でホワむトボヌド颚のペヌゞを甚意しお、時折画面共有しながら時間䞭にOnlineで共同線集する䜜戊をずりたした。意倖ず成立したす。 2. 開発業務以倖にも、珟状認識のチェックやア むデア 出しに KPT やEffort&Pain等の フレヌムワヌク を䜿っおみた  1を䜕床か補品開発の スクラム でやっお気を良くした私は、マネヌゞャヌに盞談しおチヌムMTGでも「ふりかえり」チックなグルヌプワヌクを詊すこずにしたした。䞀般化しづらい内容なので具䜓的には曞きたせんが、「䞊半期のxxを振り返り぀぀来幎のyy 戊略を考える」みたいな内容にグルヌプワヌクを持ち蟌むようなむメヌゞです。  こちらに぀いおの気付きは埌述したすが、成立こそしたものの課題もありずいう感じでした。 W:わかったこず気付き  ここからは、実際に「ふりかえり」に取り組んでみお、わかったこずや気付きを䜕個か曞いおいきたす。 基本は KPT 。しかし曞き方や時間配分は基本を守ったほうが良い。  環境によっお差はあるかもしれたせんが、倧抵の人がすんなり入っおくれるのは KPT かなず感じおいたす。ただ人数にもよりたすが、 曞き方ず時間配分は基本を厩さないほうがいい ず感じおいたす。基本ずいうのは、この蟺です。 KeepずProblemずTryを曞くタむミングは分ける。 グルヌプワヌクずしおの KPT は他メンバヌの曞いた内容からも気付きを埗おほしい。たずめおやるず個人が持っおいる KPT の論理展開を曞いおしたいがち。 Kでポゞティブにスコヌプを振り返る時間をきちんず取る。 これが䞍十分だずPTが個人の反省䌚になりがち。 そしおKのシヌケンスは倚少共感や発芋を重芖する。「あ、こんないい事あったんだ」ず思えたらしめたもので、「どうしたら他にも良くできただろう」ずいう方向にいく 1 。  たた KPT は最埌のTを、きちんず明日からのTryに繋げおいくのが䞀番難しいなず感じおいたす。぀い぀いPの議論は盛り䞊がりがちですが、Tもちゃんず時間を取っお党員で敎理しないず、せっかくメンバヌが出しおくれたTryを積み残しがちでした。この蟺はただ修行䞭です。Feasible & Useful実珟可胜性ず有甚性の2軞でTryをプロットするなども䜿いながら、党員で芋える圢にしお実珟性や優先床を敎理するず改善に繋がりやすいかなず感じおいたす。 ツヌルはなんだっおいい。ただ、参加者にずっお平等で、盎感的に䜿いやすいこずは倧事。  党員がフルリモヌトの状況でふりかえりを始めようず思った時に、最初に迷ったのがツヌルでした。専甚ツヌルでオサレにやりたい欲が頭をよぎったものの「 初回はずにかく説明なしで誰もがすぐ入れるもので 」ず思い、匊瀟ではOffice 365が浞透しおいた事をふたえお、 PowerPoint を online線集する圢を取りたした。奜みもあるず思いたすが、Office 365が利甚できる環境であれば、手っ取り早い遞択肢の䞀぀ずしおお勧めです。  結局この蟺りは ファシリテヌタヌ が ファシリテヌション しやすいかで決めおいいず思いたすが、同時に倧事かなず感じおいるのは「 参加者にずっお平等で、盎感的に䜿いやすい事 」だず思っおいたす。䟋えば KPT を個人で曞き出すだけなら曞き䞋しのメモ垳やチャットツヌルのスレッドでも可胜ですが、グルヌプワヌクずしおのふりかえりでは各人のアむテムがなるべく平等に䞊んでいる状態が理想です。テキストの曞き䞋しはどうしおも順序性に瞛られおしたい、オンラむンな議論よりも バッチ凊理 的な読み䞋しになりがちです。  この点ホワむトボヌドツヌルに類するものは、䜍眮を移動させる事で簡単に近䌌性や階局構造をその堎で衚珟できるそしお違っおいたら戻せるのが圧倒的に有利です。いかに䌚議宀で暡造玙に貌る付箋が芁件を満たしおいたかを再発芋した気分でした。 アレンゞする時は「䜕が目的か」「迷いなくスコヌプを芋぀めおもらえるか」を考えおおくこずが倧事。  アレンゞはただあたりしおいたせんが 2 、目的が ファシリテヌタヌ の䞭でハッキリしおいれば、アクティビティの倚少の組み替えは機胜したした。  ただ圓たり前かもしれたせんが、アレンゞを組み蟌む時は、「この曞き方で参加者党員が同じように受け取れるか」よくよく考えお準備する必芁もありたすふりかえりに限った話ではないでしょうけど。  少し恥ずかしい倱敗䟋ですが、メンバヌがグルヌプワヌクに慣れおきたあたりで、ふりかえりに関係のない MTG でも自己流のグルヌプワヌクを蚭定しおみたした。ずころが参加者からは「これっおどこたでを含みたすか」「○○は含たれたすか」ずいう質問が頻発しお認識合わせに意倖ず時間を䜿っおしたいたした。自己流が党くダメずは蚀いたせんが、こんな質問が参加者から頻発する堎合は、 甚意した枠組みが本圓に抜け挏れ、重耇のないものか  たた 蚀葉の定矩が参加者共通で認識できおいるか よく問い盎す必芁があるず気付かされたした。そしおふりかえりの既存手法は盎感的にこの蟺りをクリアしやすいよう簡朔になっおいるのだな、ずいう事にも気付けたした。 リモヌト ファシリテヌション に「ふりかえり」は効く。  結局のずころ自分がふりかえりに惹かれたのは 「どうすればリモヌトワヌクでも発散系 MTG を実りあるものにできるか」ずいう問題意識に䞀番ミヌトした ずいうのもありたす。Web䌚議はどうしおも同時発話が成立しづらかったり、同期的な議論がしづらい堎面があっお、その点決たったルヌルに埓っお非同期で参加者が個人の考えを曞き出しおいくシヌケンスを挟む方匏は盞性が良いず感じおいたす。  以䞊、倚少シチュ゚ヌション䟝存の内容になるため䞀般化しづらい内容もありたすが、䜕かしらの参考になれば幞いです。 T:぀ぎやるこず  個人的に次やりたいこずは色々ありたす。本蚘事を曞きながら色々ず調べおいお、発端になったガむドブック䜜者の森さんが結構な量のリ゜ヌスを公開しおいるこずに気付きたした。ある皋床自分でTryした埌に、こうした倖郚情報でノりハり面を 仕入 れ続けるのは効果が高そうだず感じおいたす。 Qiita:ふりかえりを拡匵する「ふりかえりカタログ」   埌は䜕冊か他の本にも朜っおみようかなず思いたす。 アゞャむルレトロスペクティブズ 匷いチヌムを育おる「ふりかえり」の手匕き  たた自戒を蟌めおですが 「ふりかえりっお結局䜕のためにやるの」 ずいう問いぞの答えは垞に考えおおきたいずころです。この答えはおそらく、ふりかえりを実斜する堎面や人、チヌムによっお様々だず思いたす。この点は、最埌に少しだけ自分たちの䟡倀芳の話をしたす。 ナニコヌン䌁業のひみ぀  今幎チヌムで読んだ曞籍に「 ナニコヌン 䌁業のひみ぀」ずいう曞籍がありたす玠晎らしい本です。この曞籍の奜きな䞀節に 「スタヌトアップの本質は『孊習する機械』であるこず」 ずいう蚀葉がありたす。  私達はスタヌトアップでこそありたせんが、チヌムずしお垞に孊習するこず、成長するこずを重芖しおいたす。ふりかえりの目的や捉え方は様々かず思いたすが、私は「チヌムが孊習する機械であるために有甚なアクティビティの1぀」だず捉えおいたす。アクティビティずしおのふりかえりは楜しみ぀぀、この蟺りの䟡倀芳を䜓珟できるよう「チヌムで柔軟に詊し続ける・倉え続ける」 姿勢を今埌もセットで倧事にしたいず考えおいたす。  皆様も是非、よきふりかえりラむフを。 執筆 @fhiroaki 、レビュヌ @sato.taichi  Shodo で執筆されたした  同じような話が及川さんの tweet にも出おいお、あぁりチだけじゃなかったんだなぁず。以䞋たずめは珟堎の知芋がいっぱい集たっおるのでおすすめです。 TogetterリンクKPT (Keep/Problem/Try) 等のふりかえりで、K (Keep) ネタを増やすみんなの工倫 ↩ 「KずPは事前に曞いお読み䞊げの時間は取らず、圓日は他のメンバのものをじっず読んでレスポンスする時間にする」メンバが発話に慣れお来たこず前提で、蚘述量が増えおきた埌の時間短瞮ずしお「KをFUN/DONE/LEARN に眮き換えおそのたたPTに行く」メンバの成果の承認に時間を取りたいくらいでしょうか。 ↩
金融゜リュヌション事業郚の橋詰です、こんにちは。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の6日目のポストです。5日目の昚日は柎田さんの Policy as Codeを実珟する Open Policy Agent / Rego の玹介 でした。 さお、2021幎も瀟内で耇数の技術曞読曞䌚を開催したした。どんな本をどう読んだのかお披露目したす。ISID瀟内には技術曞の読曞䌚がたくさんあるため、私が参加した䌚を䞭心にご玹介したす。このテックブログに2021幎の蚘録を残しお、2022幎も頑匵ろうずいう気持ちを蟌めおのポストです。 読んだ本 読んだ本の䞀芧です。2020幎からの継続ず、今幎仕掛りした本を含めおいたす。合蚈6冊6読曞䌚でした。 AI゚ンゞニアを目指す人のための 機械孊習入門 実装しながらアルゎリズムの流れを孊ぶ システム蚭蚈の謎を解く 改蚂版 匷いSEになるための機胜蚭蚈ず入出力蚭蚈の極意 PyTorch実践入門 アゞャむルなチヌムを぀くる ふりかえりガむドブック 始め方・ふりかえりの型・手法・マむンドセット ここはりォヌタヌフォヌル垂、アゞャむル町 ストヌリヌで孊ぶアゞャむルな組織の぀くり方 システム障害察応の教科曞 それぞれの本ず読み方を簡単にご玹介 本ごずに有志で集たっお読んでいたす。参加者はだいたい7-9人でしょうか。簡単に本の䞭身ず感想、どんな読み方をしたのかたずめたす。 AI゚ンゞニアを目指す人のための 機械孊習 入門 機械孊習 のさたざたなモデルに぀いお、 理論 を 簡単 に説明しおくれる良曞。「うわっ぀らの説明」ず「難しい完党な理論の説明」のちょうど良い間をいっおくれる、゚ンゞニアにずっおちょうどよい入門曞です。本曞は茪読圢匏で読みたした。 システム蚭蚈の謎を解く システム開発 の基本蚭蚈に焊点を圓おた本。蚭蚈を行う䞊で、これは最䜎限抌さえおおいおほしいなぁずいう粒床で蚘茉されおいたす。若手ず䞀緒に読みたした。この本も茪読圢匏です。 PyTorch実践入門 先述の「AI゚ンゞニアを」に続いお読んだ本。前半は 機械孊習 ラむブラリであるPyTorchの基瀎、埌半は CTスキャン 画像から肺がんを怜出するタスクを題材にプロゞェクトベヌスで理解を深めたす。埌半はけっこう難しい。しかしながら読曞䌚ずいうみんなで協力しお匷制しお読む効果が発揮され、党員無事に読み切れたした。こちらも茪読圢匏です。 ふりかえりガむドブック 瀟内の アゞャむル 開発をしおいる人界隈で読もうずなった本。 システム開発 では必須のアクティビティである ふりかえり に焊点を圓おおいたす。この本は期日たでに各々で読んで集合し、本曞の内容や呚蟺の話題、珟堎の悩みをネタに、ディスカッションリヌンコヌヒヌなどをする圢匏をずりたした。同じ本を読み、コンテキストが揃っおいるず、普段仕事では関わらないメンバヌずでも最初から良い議論ができるんだなず知った䌚でした。 ここ あじ ゃ本 組織の アゞャむル 化のヒントを探すために、手に取った本。章ごずに小説調のストヌリヌず解説があり、ずおも読みやすいです。茪読䌚圢匏で読み進めたものの、読曞する負担が少なく、他曞ず比べお倚くのダむアログの時間を取るこずができたした。 システム障害察応の教科曞 本曞はただいた茪読䌚が進行䞭です。「できる人がやる」、「背䞭を芋お育お」ず考えられおいたシステム障害察応を、知識・タスク・ツヌル・組織の面から敎理し教科曞的にたずめ䞊げおいたす。曞籍の内容ず、過去に経隓した生々しい事䟋を共有・比范しながら進めおいけるずいうのが、瀟内読曞䌚を開催する倧きなメリットですね。 さいごに 今幎は、AI、 システム開発 、 アゞャむル など、バリ゚ヌション豊かに読曞䌚を開催できたした。読み方が茪読䌚䞀蟺倒になったずころは、改善の䜙地がありたすね。もう少し遊び心があるず良いかもしれたせん。技術曞でActive Book Dialogueを詊すのも䞀興です。 さお、明日は読曞䌚でもご䞀緒したこずがある犏竹さんの「ふりかえり入門した、ふりかえり」です。 執筆 @hashizume.hideki 、レビュヌ @sato.taichi  Shodo で執筆されたした 
金融゜リュヌション事業郚の橋詰です、こんにちは。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の6日目のポストです。5日目の昚日は柎田さんの Policy as Codeを実珟する Open Policy Agent / Rego の玹介 でした。 さお、2021幎も瀟内で耇数の技術曞読曞䌚を開催したした。どんな本をどう読んだのかお披露目したす。ISID瀟内には技術曞の読曞䌚がたくさんあるため、私が参加した䌚を䞭心にご玹介したす。このテックブログに2021幎の蚘録を残しお、2022幎も頑匵ろうずいう気持ちを蟌めおのポストです。 読んだ本 読んだ本の䞀芧です。2020幎からの継続ず、今幎仕掛りした本を含めおいたす。合蚈6冊6読曞䌚でした。 AI゚ンゞニアを目指す人のための 機械孊習入門 実装しながらアルゎリズムの流れを孊ぶ システム蚭蚈の謎を解く 改蚂版 匷いSEになるための機胜蚭蚈ず入出力蚭蚈の極意 PyTorch実践入門 アゞャむルなチヌムを぀くる ふりかえりガむドブック 始め方・ふりかえりの型・手法・マむンドセット ここはりォヌタヌフォヌル垂、アゞャむル町 ストヌリヌで孊ぶアゞャむルな組織の぀くり方 システム障害察応の教科曞 それぞれの本ず読み方を簡単にご玹介 本ごずに有志で集たっお読んでいたす。参加者はだいたい7-9人でしょうか。簡単に本の䞭身ず感想、どんな読み方をしたのかたずめたす。 AI゚ンゞニアを目指す人のための 機械孊習 入門 機械孊習 のさたざたなモデルに぀いお、 理論 を 簡単 に説明しおくれる良曞。「うわっ぀らの説明」ず「難しい完党な理論の説明」のちょうど良い間をいっおくれる、゚ンゞニアにずっおちょうどよい入門曞です。本曞は茪読圢匏で読みたした。 システム蚭蚈の謎を解く システム開発 の基本蚭蚈に焊点を圓おた本。蚭蚈を行う䞊で、これは最䜎限抌さえおおいおほしいなぁずいう粒床で蚘茉されおいたす。若手ず䞀緒に読みたした。この本も茪読圢匏です。 PyTorch実践入門 先述の「AI゚ンゞニアを」に続いお読んだ本。前半は 機械孊習 ラむブラリであるPyTorchの基瀎、埌半は CTスキャン 画像から肺がんを怜出するタスクを題材にプロゞェクトベヌスで理解を深めたす。埌半はけっこう難しい。しかしながら読曞䌚ずいうみんなで協力しお匷制しお読む効果が発揮され、党員無事に読み切れたした。こちらも茪読圢匏です。 ふりかえりガむドブック 瀟内の アゞャむル 開発をしおいる人界隈で読もうずなった本。 システム開発 では必須のアクティビティである ふりかえり に焊点を圓おおいたす。この本は期日たでに各々で読んで集合し、本曞の内容や呚蟺の話題、珟堎の悩みをネタに、ディスカッションリヌンコヌヒヌなどをする圢匏をずりたした。同じ本を読み、コンテキストが揃っおいるず、普段仕事では関わらないメンバヌずでも最初から良い議論ができるんだなず知った䌚でした。 ここ あじ ゃ本 組織の アゞャむル 化のヒントを探すために、手に取った本。章ごずに小説調のストヌリヌず解説があり、ずおも読みやすいです。茪読䌚圢匏で読み進めたものの、読曞する負担が少なく、他曞ず比べお倚くのダむアログの時間を取るこずができたした。 システム障害察応の教科曞 本曞はただいた茪読䌚が進行䞭です。「できる人がやる」、「背䞭を芋お育お」ず考えられおいたシステム障害察応を、知識・タスク・ツヌル・組織の面から敎理し教科曞的にたずめ䞊げおいたす。曞籍の内容ず、過去に経隓した生々しい事䟋を共有・比范しながら進めおいけるずいうのが、瀟内読曞䌚を開催する倧きなメリットですね。 さいごに 今幎は、AI、 システム開発 、 アゞャむル など、バリ゚ヌション豊かに読曞䌚を開催できたした。読み方が茪読䌚䞀蟺倒になったずころは、改善の䜙地がありたすね。もう少し遊び心があるず良いかもしれたせん。技術曞でActive Book Dialogueを詊すのも䞀興です。 さお、明日は読曞䌚でもご䞀緒したこずがある犏竹さんの「ふりかえり入門した、ふりかえり」です。 執筆 @hashizume.hideki 、レビュヌ @sato.taichi  Shodo で執筆されたした 
こんにちは、X むノベヌション 本郚の柎田です。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の5日目のポストです。 4日目のポストは加玍さんの「リアルタむムレンダラヌP3Dのご玹介」でした。 さお、このポストではOpen Policy Agentずポリシヌ蚀語Regoの玹介をしたいず思いたす。 前半ではRegoの文法を簡単に説明したす。 埌半では私がOpen Policy AgentずRegoを実際に䜿っおいおハマった点をいく぀かご玹介したす。 このポストを読んでくださる方の圹に立おば幞いです。 Open Policy Agentずは Regoずは たずは動かしおみる 蚭問 構造化デヌタinput.json ポリシヌexample.rego 怜蚌 Regoの文法 本章で扱う構造化デヌタ 倉数 倉数の束瞛 配列、集合、オブゞェクトぞのアクセス ルヌル 集合を生成する オブゞェクト蟞曞を生成する 倀を生成する 耇数の定矩を曞く 関数 内包衚蚘 リスト内包衚蚘 集合内包衚蚘 オブゞェクト内包衚蚘 キヌワヌドず挔算子 not some default in with モゞュヌル、パッケヌゞ テストを曞く OPA/Regoを利甚するツヌル Conftest Gatekeeper KubernetesにおけるConftestずGatekeeperの䜿い分け それ以倖のツヌル ハマったずころ 矛盟したルヌルを定矩しない 配列や集合がある条件を満たす倀を含んでいないか怜蚌するルヌルの曞き方 オブゞェクトのフィヌルドが特定の倀であるか怜蚌するルヌルの曞き方 異垞系テストのアサヌションの曞き方 オブゞェクトの存圚しないキヌを参照した際の挙動 ポリシヌのデバッグ方法 = ず := ず == の違い フォヌマッタを䜿う おわりに 参考 Open Policy Agentずは Open Policy AgentOPAは汎甚ポリシヌ゚ンゞンです。 䞎えられた構造化デヌタがRegoず呌ばれるポリシヌ蚀語で蚘述されたポリシヌを満たしおいるか刀定したす。 OPAを䜿っおサヌビス本䜓ずポリシヌ゚ンゞンを 疎結合 にするこずでポリシヌの曎新、デプロむ、バヌゞョン管理などをサヌビス本䜓から分離できたす。 ※図は Open Policy Agent | Documentation から匕甚しおいたす。 OPAには様々な ナヌスケヌス がありたす。いく぀か䟋を挙げたす。 Infrastructure as Code  Infrastructure as Codeではむンフラの理想的な状態を yaml やHCL2などの構造化デヌタずしお宣蚀的に蚘述したす。 そしおそれをTerraformなどのツヌルぞ枡すこずで宣蚀に埓っお実際のむンフラを構築したす。 OPAを䜿っお yaml やHCL2が満たすべきルヌルむンフラの蚭定をポリシヌずしお定矩するこずでInfrastructure as Codeの品質を担保できたす。 これは特に耇数のチヌムが独自にサヌビスを構築・運甚しおいる堎合にチヌム暪断で品質を向䞊する方法ずしお有効です。 ログ分析  OPAを䜿っおセキュリティや監査の構造化ログを分析し、指定したポリシヌを満たさない異垞なログが出力されおいないかチェックできたす。 たずえばメルカリでは GCP のセキュリティログをOPAを䜿っお分析しおいたす。 参考 Achieving Security Compliance Monitoring with Open Policy Agent and Rego - Speaker Deck デヌタパむプラむン䞊のバリデヌション  OPAを䜿っおデヌタパむプラむン䞊を流れる構造化デヌタが指定したポリシヌを満たしおいるかチェックできたす。 たずえば 日本経枈新聞瀟 ではデヌタパむプラむン䞊のト ラッキング デヌタが正垞に加工されおいるかOPAでチェックしおいたす。 参考 【開催報告】新聞瀟による AWS を掻甚した DX 事䟋セミナヌ | Amazon Web Services ブログ OPAの゜ヌスコヌド は Apache License 2.0 で公開されおいたす。 Regoずは RegoはOPAが䜿甚する宣蚀型ク゚リ蚀語です。 Datalog Prolog のサブセットである宣蚀型論理 プログラミング蚀語 にむンスパむアされおいたす。 たずは動かしおみる 公匏の Example に掲茉されおいる䟋題を手元で実行しおみたす。 蚭問 䞎えられた構造化デヌタが以䞋のポリシヌを満たしおいるか怜蚌したす。 むンタヌネットから到達可胜なサヌバのうち、安党でない http プロトコル を䜿甚しおいるものはないか。 telnet プロトコル を䜿甚しおいるサヌバはないか。 構造化デヌタ input.json  { " servers ": [ { " id ": " app ", " protocols ": [ " https ", " ssh " ] , " ports ": [ " p1 ", " p2 ", " p3 " ]} , { " id ": " db ", " protocols ": [ " mysql " ] , " ports ": [ " p3 " ]} , { " id ": " cache ", " protocols ": [ " memcache " ] , " ports ": [ " p3 " ]} , { " id ": " ci ", " protocols ": [ " http " ] , " ports ": [ " p1 ", " p2 " ]} , { " id ": " busybox ", " protocols ": [ " telnet " ] , " ports ": [ " p1 " ]} ] , " networks ": [ { " id ": " net1 ", " public ": " false " } , { " id ": " net2 ", " public ": " false " } , { " id ": " net3 ", " public ": " true " } , { " id ": " net4 ", " public ": " true " } ] , " ports ": [ { " id ": " p1 ", " network ": " net1 " } , { " id ": " p2 ", " network ": " net3 " } , { " id ": " p3 ", " network ": " net2 " } ] } ポリシヌ example.rego  䞊述の蚭問を怜蚌するためにRegoで蚘述されたポリシヌを䜿甚したす。 ※Regoの文法は埌ほど説明したす。今はむメヌゞだけ把握しおいただければ結構です。 package example # allow のデフォルト倀を false に蚭定したす default allow = false # violation の芁玠数が 0 の堎合、 allow を true に蚭定したす allow = true { count(violation) == 0 } # 生成した集合 public_server の芁玠 server のうち protocols が "http" である芁玠の id を集合 violation の芁玠に远加したす violation[server.id] { some server public_server[server] server.protocols[_] == "http" } # 配列 input.servers の芁玠 server のうち protocols が "telnet" である芁玠の id を集合 violation の芁玠に远加したす violation[server.id] { server := input.servers[_] server.protocols[_] == "telnet" } # 配列 input.servers の芁玠 server のうち以䞋の条件を満たす芁玠を集合 public_server の芁玠に远加したす # 1. 配列 input.ports のうち server.ports のいずれかず id が合臎する芁玠の添字を i ずしたす # 2. 配列 input.networks のうち input.ports[i].network ず id が合臎する芁玠の添字を j ずしたす # 3. input.networks[j].public が true である堎合、 server を集合 public_server の芁玠に远加したす public_server[server] { some i, j server := input.servers[_] server.ports[_] == input.ports[i].id input.ports[i].network == input.networks[j].id input.networks[j].public } 怜蚌 ロヌカル環境で実行する堎合は以䞋を行っおください。 open-policy-agent/opa から最新のリリヌスバむナリをダりンロヌドしお、実行パスの通った ディレクト リに配眮したす。 opa eval コマンドでポリシヌを評䟡したす。 # 蚭問を満たしおいるか怜蚌したす。結果は "false" 満たしおいないでした。 $ opa eval -i input.json -d policy.rego --format pretty data.example.allow false # 蚭問のポリシヌを満たしおいないサヌバは "ci","busybox" であるこずが確認できたす。 $ opa eval -i input.json -d policy.rego --format pretty data.example.violation [ "ci", "busybox" ] たたは The Rego Playground からも実行できたす。 Regoの文法 Regoの文法を簡単に説明したす。 本章で扱う構造化デヌタ 本章 Regoの文法 では以䞋の構造化デヌタをサンプルデヌタずしお䜿甚したす。 { " persons ": [ { " name ": " alice ", " age ": 20 , " height ": 170 , " weight ": 60 } , { " name ": " bob ", " age ": 22 , " height ": 180 , " weight ": 80 } , { " name ": " carol ", " age ": 17 , " height ": 175 , " weight ": 66 } , { " name ": " dave ", " age ": 18 , " height ": 155 , " weight ": 50 } ] } 倉数 倉数の束瞛 Regoの倉数は「指定された条件を満たすよう束瞛された倀」です。 䟋えば以䞋の堎合、倉数 i は 配列 persons のうち「20才以䞋か぀身長170cm以䞊の人」を指す任意の添字 の倀、぀たり 0 ず 2 に束瞛されたす。 some i persons[i].age <= 20 persons[i].height >= 170 手続き型 プログラミング蚀語 のように倀を再び代入するこずはできたせん。 i := 1 i := 2 # i は既に 1 に束瞛にされおいるため゚ラヌになる たた特殊な倉数ずしお _ がありたす。 _ は登堎する床に他の倉数ず競合しない䞀意な倉数ぞ倉換されたす。再び参照する必芁のない倉数は _ を䜿うこずが掚奚されおいたす。 _ を䜿っお先皋の䟋を曞き換えるず以䞋のようになりたす。 person := persons[_] person.age <= 20 person.height >= 160 配列、集合、オブゞェクトぞのアクセス Regoには以䞋のような型がありたす。 数倀 文字列 ブヌル倀 配列 集合 オブゞェクト蟞曞 配列 arr から芁玠 val を取りだす際は以䞋のように曞きたす。 # 倉数を䜿った曞き方。iは配列の添字、valは配列の倀に束瞛される。 some i val := arr[i] # たたは `_` を䜿った曞き方。 val := arr[_] 集合 a_set から芁玠 val を取りだす際は以䞋のように曞きたす。 # valは集合の各芁玠に束瞛される a_set[val] オブゞェクト obj のキヌ key にアクセスする際は以䞋のように曞きたす。 # `.` を䜿った曞き方 value := obj.key # たたは `[]` を䜿った曞き方 value := obj["key"] ルヌル OPAでは、枡された構造化デヌタベヌスドキュメントずも蚀いたすを元に、新しい構造化デヌタ仮想ドキュメントずも蚀いたすを算出したす。 この仮想ドキュメントの定矩を ルヌル ず蚀いたす。OPAでは様々なルヌルを定矩するこずでポリシヌを実装したす。 集合を生成する 集合を生成するルヌルは以䞋のように蚘述したす。 <name>[<value>] { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <value> 」を芁玠ずしお持぀集合になりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」の名前の集合 を生成するルヌルの䟋です。 young_and_tall_persons[person.name] { person := input.persons[_] person.age <= 20 person.height >= 170 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func youngAndTallPersons(input Input) [] string { result := [] string {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result = append (result, person.name) } } return result } オブゞェクト蟞曞を生成する オブゞェクトを生成するルヌルは以䞋のように蚘述したす。 <name>[<key>] = <value> { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <key> ず <value> のペア」を芁玠ずしお持぀オブゞェクトになりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」に぀いお、名前ず䜓重のペアを芁玠ずしお持぀のオブゞェクト を生成するルヌルの䟋です。 young_and_tall_persons_weight[person.name] = person.weight { person := input.persons[_] person.age <= 20 person.height >= 170 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func youngAndTallPersonsWeight(input Input) map [ string ] int { result := map [ string ] int {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result[person.name] = person.weight } } return result } 倀を生成する 倀を生成するルヌルは以䞋のように蚘述したす。 <name> = <value> { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <value> の倀」になりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は「Aliceの身長」を返すルヌルの䟋です。 alice_height = person.height { person := input.persons[_] person.name == "alice" } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func aliceHeight(input Input) int { result := 0 for _, person := range input.persons { if person.name == "alice" { result = person.height } } return result } <vaule> には数倀、文字列、真停倀だけでなく、集合、配列、オブゞェクトなども指定できたす。 = <value> 郚を省略するず = true ずしお扱われたす。 䟋えば以䞋のルヌル alice_exists は name キヌの倀が alice な芁玠が存圚する堎合のみ true になりたす。 alice_exists { person := input.persons[_] person.name == "alice" } { <body> } 郚を省略するず { true } ずしお扱われたす。定数はこの曞き方を䜿っお定矩したす。 pi = 3.14 耇数の定矩を曞く ルヌルは耇数に分割しお定矩できたす。 分割しお蚘述されたルヌルは 論理和 ORのように評䟡されたす。 以䞋は 「 BMI が18.5未満たたは25以䞊の人」の名前の集合 を返すルヌルの䟋です。 unhealthy_persons[person.name] { person := input.persons[_] bmi := (person.weight / (person.height * person.height)) * 10000 bmi < 18.5 } unhealthy_persons[person.name] { person := input.persons[_] bmi := (person.weight / (person.height * person.height)) * 10000 bmi >= 25 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func unhealthyPersons(input Input) [] string { result := [] string {} for _, person := range input.persons { bmi := float64 (person.weight) / ( float64 (person.height) * float64 (person.height)) * 10000.0 if bmi < 18.5 || bmi >= 25 { result = append (result, person.name) } } return result } 関数 関数は以䞋のように蚘述したす。匕数を取るこず以倖は 倀を生成するルヌル ず抂ね同じです。 <name> (<args>) = <value> { <body> } 以䞋は BMI を蚈算する関数ず、 BMI の分類を返す関数の䟋です。 bmi(height, weight) = (weight / (height * height)) * 10000 bmi_class(person) = "underweight" { bmi(person.height, person.weight) < 18.5 } bmi_class(person) = "normal range" { bmi(person.height, person.weight) >= 18.5 bmi(person.height, person.weight) < 25 } bmi_class(person) = "overweight" { bmi(person.height, person.weight) >= 25 } たたOPA/Regoには組蟌み関数がありたす。よく䜿う組蟌み関数をいく぀か玹介したす。 # 曞匏付き文字列を評䟡しお結果の文字列を返す sprintf("%s's weight is %d", [person.name, person.weight]) # 配列、集合、オブゞェクトの芁玠数を返す count(young_and_tall_persons) == 0 # オブゞェクトを文字列json圢匏に倉換したものを返す json.marshal(obj) # --explainオプションを぀けお実行した際に文字列を出力する詳现は埌述 trace("...") 䞊で玹介した以倖にも様々な組蟌み関数がありたす。詳现は Built-in Functions を参照しおください。 内包衚蚘 Regoでは内包衚蚘を䜿甚できたす。 リスト内包衚蚘 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」の名前の配列 を生成する内包衚蚘の䟋です。 array := [person.name | person := input.persons[_]; person.age <= 20; person.height >= 170] これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 array := func (input Input) [] string { result := [] string {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result = append (result, person.name) } } return result }(input) 集合内包衚蚘 以䞋は 集合を生成する で䟋瀺した 「幎霢20才以䞋、身長170cm以䞊の人」の名前の集合 を内包衚蚘で蚘述した䟋です。 a_set := {person.name | person := input.persons[_]; person.age <= 20; person.height >= 170} これをGoで曞いた堎合のコヌドは リスト内包衚蚘 ず同じため割愛したす※あくたでむメヌゞです。 オブゞェクト内包衚蚘 以䞋は オブゞェクト蟞曞を生成する で䟋瀺した 「幎霢20才以䞋、身長170cm以䞊の人」に぀いお、名前ず䜓重のペアを芁玠ずしお持぀のオブゞェクト を内包衚蚘で蚘述した䟋です。 obj := {person.name: person.weight | person := input.persons[_]; person.age <= 20; person.height >= 170} これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 obj := func (input Input) map [ string ] int { result := map [ string ] int {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result[person.name] = person.weight } } return result }(input) キヌワヌドず 挔算子 not 匏を吊定するには not を䜿甚したす。 not person.age <= 20 ルヌルが仮想ドキュメントを生成したか 配列や集合やオブゞェクトの䞭に指定した芁玠が存圚するか を刀定する際にも䜿甚したす。 not input.persons[4] not person.birthday some some を䜿うこずでルヌル内のロヌカル倉数を明瀺的に宣蚀できたす。 young_and_tall_persons[person.name] { some i person := input.persons[i] person.age <= 20 person.height >= 170 } ロヌカル倉数の宣蚀を必ず行う必芁はありたせんが、倉数名ず同じルヌルが存圚した堎合でも期埅通りロヌカル倉数ずしお扱われるよう、明瀺的に宣蚀するこずが掚奚されおいたす。 䟋えば以䞋のルヌル young_and_tall_persons は some i の有無で結果が倉わりたす。 i = 1 young_and_tall_persons[person.name] { some i person := input.persons[i] person.age <= 20 person.height >= 170 } default default を䜿うこずで 倀を生成するルヌル のデフォルト倀を指定できたす。 以䞋の䟋では、ルヌル alice_exists は input.persons の䞭にAliceの芁玠が存圚すれば true 、そうでなければ false になりたす。 default キヌワヌドを省略するず、ルヌル alice_exists は input.persons の䞭にAliceの芁玠が存圚しない堎合 false ではなく未定矩になりたす。 default alice_exists = false alice_exists { person := input.persons[_] person.name == "alice" } in in はOPAの v0.34.0 で導入されたキヌワヌドです。 配列、集合、オブゞェクトがある倀を芁玠に含んでいるかたたは含んでいないか刀定する 配列、集合、オブゞェクトの芁玠に倉数を束瞛する ずいったこずができたす。 OPA v0.34.2 時点では、 in キヌワヌドを䜿うには import future.keywords.in を宣蚀する必芁がありたす。 以䞋は配列、集合、オブゞェクトがある倀を芁玠に含んでいるか刀定するルヌルの䟋です。 import future.keywords.in # 名前の集合。結果は ["alice", "bob", "carol", "dave"] 。 person_names[person.name] { person := input.persons[_] } # 名前ず䜓重のペアからなるオブゞェクト。結果は {"alice": 60, "bob": 80, "carol": 66, "dave": 50} 。 person_weights[person.name] = person.weight { person := input.persons[_] } # 集合 person_names の䞭に "alice" が存圚するか。結果は true 。 alice_exists { "alice" in person_names } # オブゞェクト person_weights の䞭に倀が 60 である芁玠䟋 {"alice": 60} が存圚するか。結果は true 。 sixty_kg_person_exists { 60 in person_weights } not ず組み合わせお、配列、集合、オブゞェクトがある倀を芁玠に含んでいないかを刀定できたす。 # 集合 person_names の䞭に "ellen" が存圚しないか。結果は true 。 ellen_does_not_exist { not "ellen" in person_names } # オブゞェクト person_weights の䞭に倀が 70 である芁玠䟋 {"alice": 70} が存圚しないか。結果は true 。 seventy_kg_person_does_not_exist { not 70 in person_weights } 巊蟺に匕数を2぀枡すこずで、配列、オブゞェクトが「添字、キヌ」ず「倀」のペアを含んでいるかを刀定できたす。 # オブゞェクト person_weights の䞭に芁玠 {"alice": 60} が存圚するか。結果は true 。 is_alice_sixty_kg { "alice", 60 in person_weights } 配列、集合の定矩 関数の匕数 などで in キヌワヌドの巊蟺に匕数を2぀枡す堎合は、正しく評䟡されるよう () で囲む必芁がありたす。 # 誀った曞き方。「`0`ず `2 in [2]` の2぀の匕数を受け取る関数f」ずしお解釈される。 f(0, 2 in [2]) # 正しい曞き方。「`0, 2 in [2]` の結果を1぀の匕数ずしお受け取る関数f」ずしお解釈される。 f((0, 2 in [2])) some ず組み合わせお、配列、集合、オブゞェクトの芁玠に倉数を束瞛できたす。 # 䜓重が60kgの人の名前の集合を返す。結果は {"alice"} 。 sixty_kg_persons[name] { some name, 60 in person_weights } # 結果は ["a", "r", "y"] unique[x] { some x in ["a", "r", "r", "a", "y"] } with ルヌルの評䟡時に with を䜿っお input data.<path> の構造化デヌタを指定した倀に眮き換えるこずができたす。 allow with input as {"user": "charlie", "method": "GET"} with data.roles as {"dev": ["charlie"]} これは䞻に 単䜓テスト を曞く際に䜿甚したす。テストの曞き方は テストを曞く で説明したす。 モゞュヌル、パッケヌゞ 0個以䞊のルヌルの集合をモゞュヌルずいい、それを特定の 名前空間 にグルヌプ化したものをパッケヌゞずいいたす。 同じパッケヌゞのポリシヌを同じ ディレクト リに配眮する必芁はありたせん。 パッケヌゞ名は package で指定したす。 package example 他のパッケヌゞのルヌルや関数を参照する堎合は import data.<パッケヌゞ名> のように宣蚀したす。 import data.other_example example_rule[value] { value := other_example.other_rule } テストを曞く 単䜓テスト を曞くこずでポリシヌが期埅通り動䜜するか確認できたす。 テストコヌドはファむル名の末尟を _test.rego ずしおください。 䟋えば example.rego のテストコヌドのファむル名は example_test.rego です。 テストケヌスは名前が test_ から始たるルヌルずしお蚘述したす。ルヌルのbody郚の匏が党お真ならば成功、そうでなければ倱敗です。 package example test_young_and_tall_persons { input := {"persons": [ {"name": "alice", "age": 20, "height": 170, "weight": 60}, {"name": "bob", "age": 22, "height": 180, "weight": 80}, {"name": "carol", "age": 17, "height": 175, "weight": 66}, {"name": "dave", "age": 18, "height": 155, "weight": 50}, ]} young_and_tall_persons == {"alice", "carol"} with input as input } test_no_young_and_tall_persons { input := {"persons": [ {"name": "alice", "age": 30, "height": 170, "weight": 60}, {"name": "bob", "age": 22, "height": 180, "weight": 80}, {"name": "carol", "age": 27, "height": 175, "weight": 66}, {"name": "dave", "age": 18, "height": 155, "weight": 50}, ]} count(young_and_tall_persons) == 0 with input as input } テストは以䞋のように実行したす。 $ opa test . PASS: 2/2 詊しにテストケヌス test_young_and_tall_persons の アサヌション の右蟺を {"alice", "carol"} から {"alice", "bob"} ぞ曞き換えおテストを倱敗させたす。 テストが倱敗した堎合は次のような結果になりたす。 $ opa test . data.example.test_young_and_tall_persons: FAIL (1.466812ms) -------------------------------------------------------------------------------- PASS: 1/2 FAIL: 1/2 opa test コマンドには以䞋のようなオプションもありたす。 -v, --verbose テスト結果の詳现を衚瀺したす。 -r, --run 指定したテストケヌスのみを実行できたす。 -c, --coverate テスト カバレッゞ を出力できたす。 OPA/Regoを利甚するツヌル OPA/Regoを利甚するツヌルを簡単にご玹介したす。 Conftest Conftest は Kubernetes の マニフェスト ファむルやTerraformコヌドなどの構成ファむルがRegoで蚘述されたポリシヌに埓っおいるか怜蚌するための CLI ツヌルです。 以䞋は Kubernetes のPodに Readiness Probe が蚭定されおいるか怜蚌するポリシヌの䟋です※このポリシヌは説明のために簡略化しおおり実運甚には適しおいたせん。 package deny_container_without_readiness_probe violation[msg] { input.kind == "Pod" container := input.spec.containers[_] not container.readinessProbe msg := "Readiness Probe must be set" } 先皋のポリシヌを甚いお以䞋の マニフェスト ファむルを怜蚌しおみたす。 apiVersion : v1 kind : Pod metadata : name : myapp spec : containers : - name : myapp image : myapp:1.0.0 ports : - containerPort : 8080 $ conftest test --policy . --all-namespaces manifests.yaml FAIL - manifests.yaml - deny_container_without_readiness_probe - Readiness Probe must be set 1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions マニフェスト がポリシヌに違反しおいるこずを怜出できたした。 Conftestは Kubernetes の マニフェスト ファむル以倖の構成ファむルに察しおも利甚できたす。公匏ドキュメントの Examples には以䞋の構成ファむルを怜蚌するサンプルポリシヌが掲茉されおいたす。 AWS SAM Framework CUE Docker compose Dockerfile EDN Ignore HCL HCL 2 HOCON INI Jsonnet Kubernetes Kustomize Serverless Framework Traefik Typescript VCL XML Gatekeeper Gatekeeper は Kubernetes の Validating Admission Webhook ずしお動䜜したす。 kube-apiserverに察するリ゜ヌス䜜成の芁求を怜蚌し、ポリシヌに違反するリ゜ヌスの䜜成を犁止できたす。 Kubernetes におけるConftestず Gatekeeper の䜿い分け Conftestは䞻に開発者のロヌカル環境やCIサヌバなどで実行されたす。 git リポゞトリ 䞊の マニフェスト ファむルが倉曎された際に、その倉曎がポリシヌに埓っおいるか怜蚌し、即座に開発者ぞフィヌドバックできたす。 ただし以䞋のようなケヌスはConftestで怜知できたせん。 オペレヌタヌが kubectl create などで Kubernetes クラスタ ヌにリ゜ヌスを盎接䜜成した堎合 Kubernetes クラスタ ヌ䞊のCustomControllerによっおリ゜ヌスが䜜成された堎合 Gatekeeper は Kubernetes のValidating Admission Webhookずしお動䜜したす。 kube-apiserverに察する党おのリ゜ヌス䜜成の芁求を怜蚌し、ポリシヌに違反するリ゜ヌスの䜜成を犁止できたす。 ただし kubectl create や kubectl apply を実行しお実際にkube-apiserverぞリク ゚ス トを送信するたで、ポリシヌに違反しおいるか怜蚌できたせん。 Conftestず Gatekeeper はどちらか片方だけ䜿うのではなく、䞡方組み合わせお䜿うのがよいでしょう。 䞻な実行堎所 䞻な実行タむミング 怜蚌察象 Conftest 開発者のロヌカル環境、CIサヌバ マニフェスト ファむルの曎新時 マニフェスト ファむル Gatekeeper Kubernetes のValidating Admission Webhook kube-apiserverぞのリ゜ヌス䜜成の芁求時 kube-apiserverに察する党おのリ゜ヌス䜜成の芁求 Conftestも Gatekeeper もRegoで蚘述されたポリシヌを䜿甚したす。 しかし構造化デヌタ マニフェスト の枡し方などに差異がありたす。 Conftestず Gatekeeper で同じポリシヌを䜿甚する堎合、䜕らかの方法でこの差分を吞収する必芁がありたす。 マニフェスト の栌玍堎所 Conftest --combine オプションなし(*1) input Conftest --combine オプションあり(*1) input[_].contents Gatekeeper input.review.object (*1)Conftestは通垞 マニフェスト ファむルに含たれるリ゜ヌスを1぀ず぀個別に評䟡したす。 そのため、䟋えばDeploymentに察しおPodDisruptionBudgetが定矩されおいるかずいったような、耇数のリ゜ヌスにたたがったポリシヌを評䟡できたせん。 --combine オプションを蚭定するこずで、 マニフェスト ファむルに含たれる党おのリ゜ヌスを同時にRegoぞ枡し、耇数のリ゜ヌスにたたがったポリシヌを評䟡できたす。 たたConftestが䜿甚する *.rego ファむルから Gatekeeper が必芁ずするリ゜ヌス ConstraintTemplate などを生成する必芁がありたす。 これを行うツヌルに konstraint がありたす。 それ以倖のツヌル これたで玹介したツヌルの他に、以䞋のツヌルもRegoで蚘述されたポリシヌを利甚しおいたす。 Trivy Terrascan ハマったずころ 私が実際にOPA/Regoを䜿っおいおハマった点をいく぀かご玹介したす。 矛盟したルヌルを定矩しない ルヌルの定矩が矛盟しおはいけたせん。そのようなルヌルに矛盟を発生させる構造化デヌタを枡すず実行時゚ラヌが発生したす。 いく぀か悪い䟋を玹介したす。 以䞋は倀を生成するルヌルです。ただし倀が1぀に定たりたせん。 height = person.height { person = input.persons[_] } 以䞋の䟋ではルヌルの定矩が耇数に分かれおいたす。 1぀目の定矩では「 name ず weight のペアを芁玠ずしお持぀オブゞェクト」を生成したす。 䞀方、2぀目の定矩では「 name ず height のペアを芁玠ずしお持぀オブゞェクト」を生成したす。 結果、生成されたオブゞェクトの name キヌの倀は1぀に定たりたせん。 personal_health_info[person.name] = person.height { person := input.persons[_] } personal_health_info[person.name] = person.weight { person := input.persons[_] } 配列や集合がある条件を満たす倀を含んでいないか怜蚌するルヌルの曞き方 配列 array や集合 a_set が関数 f を満たす倀を含たないか刀定するルヌルは以䞋のように蚘述できたす。 # 配列が関数fを満たす倀を含んでいないか none_in_array_match { count({x | x := array[_]; f(x)}) == 0 } # 集合が関数fを満たす倀を含んでいないか none_in_set_match { count({x | a_set[x]; f(x)}) == 0 } 特に配列 array や集合 a_set がある倀 x を芁玠に含んでいないか刀定したい堎合は in を䜿っお以䞋のように蚘述できたす。 ※OPA v0.34.2 時点では、 in キヌワヌドを䜿うには import future.keywords.in を宣蚀する必芁がありたす。 import future.keywords.in # 配列がある倀を含んでいないか none_in_array_match { not x in array } # 集合がある倀を含んでいないか none_in_set_match { not x in a_set } 以䞋の曞き方は誀りです。 以䞋のルヌルは配列や集合に関数 f を満たさない倀が1぀でも存圚すれば true になりたす。 配列や集合の党おの芁玠が関数 f を満たさないこずは怜蚌できたせん。 # 配列が関数fを満たす倀を含んでいないか間違った曞き方 none_in_array_match { x := array[_] not f(x) } # 集合が関数fを満たす倀を含んでいないか間違った曞き方 none_in_set_match { a_set[x] not f(x) } オブゞェクトのフィヌルドが特定の倀であるか怜蚌するルヌルの曞き方 オブゞェクト obj のキヌ key の倀が value であるこずを刀定するルヌルは以䞋のように蚘述できたす。 violation[msg] { not has_specific_value(obj) msg := "'obj.key' must be 'value'" } has_specific_value(obj) { obj.key == value } 以䞋の曞き方は誀りです。 「オブゞェクト obj のキヌ key の倀が value である堎合」に加えお「オブゞェクト obj にキヌ key が存圚しない堎合」にもルヌルのbody郚が false になるためです。 violation[msg] { obj.key != value msg := "'obj.key' must be 'value'" } 異垞系テストの アサヌション の曞き方 以䞋は入力デヌタの倀が偶数かどうか刀定するポリシヌの䟋です。 violation[msg] { input.value % 2 != 0 msg := "Value must be even" } 䞊述のポリシヌに察する異垞系テストずしお、最初私は以䞋のようなテストケヌスを蚘述しおいたした。 test_odd { input := {"value": 1} violation with input as input } ですが䞊述のテストケヌスは䞋衚の通り垞に成功しおしたいたす。 これは {}  空集合 が真ずしお扱われるためです。 よっおこのテストケヌスの曞き方は誀りです。 value の倀 violation の結果 test_odd の結果 奇数䟋1, 3, ... {"Value must be even"} true 偶数䟋2, 4, ... {}  空集合  true 参考 open policy agent - Rego testing: how to test "not deny"? - Stack Overflow 正しくは以䞋のいずれかのように蚘述するずよいでしょう。䞊の方がより厳密に怜蚌を行いたす。 # 䟋1violationが指定した倀に完党に䞀臎するか確認する。 test_odd { input := {"value": 1} violation == {"Value must be even"} with input as input } # 䟋2violationに指定した芁玠が含たれおいるか確認する。他の芁玠が含たれおいる可胜性もある。 test_odd { input := {"value": 1} violation["Value must be even"] with input as input } # 䟋3violationが空でないこずを確認する。具䜓的な芁玠たでは確認しない。 test_odd { input := {"value": 1} count(violation) > 0 with input as input } オブゞェクトの存圚しないキヌを参照した際の挙動 オブゞェクトの存圚しないキヌを参照するずルヌルが意図しない結果を返すため泚意が必芁です。 先皋の偶数かどうか刀定するポリシヌを誀っお以䞋のように蚘述したずしたす。 violation[msg] { input.number % 2 != 0 # 倀が栌玍されおいるのは input.value だが誀っお input.number を参照しおいる msg := "Value must be even" } このずき input.value がどのような倀でも violation は 空集合 を返したす。 これはルヌル violation のbody郚における1番目の匏が、 input.value の倀にかかわらず、垞に未定矩぀たり真ではないになるためです。 $ cat input_odd.json { "value": 1 } $ opa eval -i input_odd.json -d policy.rego --format pretty data.example.violation [] $ cat input_even.json { "value": 2 } $ opa eval -i input_even.json -d policy.rego --format pretty data.example.violation [] ここで問題なのは未定矩が false ず同様に扱われおいるこずです。 ルヌルの䞭でオブゞェクトの存圚しないキヌを参照しお未定矩が発生しおも特に䟋倖などは発生したせん。 そのため正しくポリシヌが評䟡されおルヌルのbody郚が false になったのか、オブゞェクトの存圚しないキヌを参照しお未定矩になったのか、区別するのは困難です。 珟時点では、 単䜓テスト の カバレッゞ を䞊げる以倖に、この問題を解決するよい方法は芋぀けられおいたせん。 たたこれは「OPAのポリシヌ゚ンゞン」ず「それを呌びだす倖郚サヌビス」のむンタヌフェヌス郚分の仕様が倉曎された堎合も問題になりたす。 䟋えばConftestでは v0.22.0 で --combine オプションを぀けた際にRegoぞ枡すデヌタの構造が倉曎されたした #388 。 結果、いく぀かのルヌルがオブゞェクトの存圚しないキヌを参照しお必ず未定矩になり、 マニフェスト がポリシヌに違反しおいおもConftestの怜蚌が垞に成功し続けるずいう問題が起こりたした。 これを防ぐ方法ずしお、Regoの 単䜓テスト に加えお「OPAのポリシヌ゚ンゞン」ず「それを呌びだす倖郚サヌビス」の間の 結合テスト を実装するこずが挙げられたす。 䟋えば私はConftestのテスト結果を conftest test -o json で出力しおおき、Conftestをバヌゞョンアップする際はテスト結果に意図しない倉曎が発生しおいないか確認するスナップショットテストを行うようにしおいたす。 ポリシヌの デバッグ 方法 ポリシヌの結果が期埅通りでない堎合、原因を調査する必芁がありたす。ですがRegoの凊理の流れは耇雑で远うのが困難です。 ポリシヌの挙動を把握する方法ずしお --explain オプションを掻甚できたす。 䟋ずしお以䞋のポリシヌず構造化デヌタを --explain オプションを぀けお評䟡したす。 violation[msg] { trace(sprintf("input.value is %d", [input.value])) input.value % 2 != 0 msg := "Value must be even" } { " value ": 2 } --explain オプションの倀ずそれに察する出力は以䞋のずおりです。 --explain=full ルヌルがどのように評䟡されたか党お衚瀺する。 $ opa eval -i input.json -d policy.rego --explain full --format pretty data.example.violation query:1 Enter data.example.violation = _ query:1 | Eval data.example.violation = _ query:1 | Index data.example.violation (matched 1 rule) policy.rego:3 | Enter data.example.violation policy.rego:4 | | Eval __local3__ = input.value policy.rego:4 | | Eval sprintf("input.value is %d", [__local3__], __local1__) policy.rego:4 | | Eval trace(__local1__) policy.rego:4 | | Note "input.value is 2" policy.rego:5 | | Eval __local4__ = input.value policy.rego:5 | | Eval rem(__local4__, 2, __local2__) policy.rego:5 | | Eval neq(__local2__, 0) policy.rego:5 | | Fail neq(__local2__, 0) policy.rego:5 | | Redo rem(__local4__, 2, __local2__) policy.rego:5 | | Redo __local4__ = input.value policy.rego:4 | | Redo trace(__local1__) policy.rego:4 | | Redo sprintf("input.value is %d", [__local3__], __local1__) policy.rego:4 | | Redo __local3__ = input.value query:1 | Exit data.example.violation = _ query:1 Redo data.example.violation = _ query:1 | Redo data.example.violation = _ [] --explain=fails 匏が false になった郚分のみ衚瀺する。 $ opa eval -i input.json -d policy.rego --explain fails --format pretty data.example.violation query:1 Enter data.example.violation = _ policy.rego:3 | Enter data.example.violation policy.rego:5 | | Fail neq(__local2__, 0) [] --explain=notes  trace 関数埌述の内容のみ衚瀺する。 $ opa eval -i input.json -d policy.rego --explain notes --format pretty data.example.violation query:1 Enter data.example.violation = _ policy.rego:3 | Enter data.example.violation policy.rego:4 | | Note "input.value is 2" [] trace 関数を䜿うず --explain オプションを぀けお実行した際に文字列を出力できたす。 trace 関数の匕数は文字列ですが sprintf 関数や json.marshal 関数ず組み合わせるこずで文字列以倖の倀数倀やオブゞェクトなども出力できたす。 これを䜿っおprint デバッグ できたす。 --explain=full の出力を読み解くのはなかなか倧倉なので、最初は trace 関数ず --explain=notes オプションを組み合わせおprint デバッグ するのがよいでしょう。 Conftestでも --trace オプションを぀けるこずでルヌルがどのように評䟡されたか衚瀺できたす。これは opa コマンドの --explain=full に盞圓したす。 = ず := ず == の違い Regoには = 、 := 、 == ずいう䌌たような 挔算子 がありたす。それぞれの違いは以䞋のずおりです。 蚘法 蚘述できる堎所 コンパむル ゚ラヌ ナヌスケヌス := ルヌル内 倉数が既に定矩されおいる堎合に発生 ロヌカル倉数を定矩する == ルヌル内 倉数がただ定矩されおいない堎合に発生 倀を比范する = どこでも 倉数が正しく参照できない堎合に発生 ク゚リを衚珟する := ず == のかわりに = を䜿うこずができたす。 ただし := ず == は コンパむル 時に远加のチェックが働くため、䜿える堎面ではなるべく = よりも := ず == を䜿うずよいでしょう。 参考 Equality: Assignment, Comparison, and Unification フォヌマッタを䜿う opa fmt --write . で珟圚の ディレクト リ配䞋にあるポリシヌのフォヌマットを敎えるこずができたす。 耇数人でポリシヌを曎新する際はこのコマンドを䜿っおむンデントや改行の有無などを統䞀するずよいでしょう。 たた opa fmt --fail . でポリシヌのフォヌマットが敎っおいなかった堎合に0以倖の終了コヌドを返すこずができたす。 CIに組み蟌んでポリシヌのフォヌマットが敎っおいるか怜蚌するずよいでしょう。 おわりに このポストではOpen Policy Agentずポリシヌ蚀語Regoの玹介をしたした。 前半ではRegoの文法を簡単に説明したした。 埌半では私がOpen Policy AgentずRegoを実際に䜿っおいおハマった点をいく぀かご玹介したした。 このポストが読んでくださった方の圹に立おば幞いです。 さお、明日は橋詰さんの「今幎瀟内の技術曞読曞䌚で読んだ本」です。 どんな技術曞が玹介されるのか楜しみです 最埌たでお読みいただきありがずうございたした。 参考 Open Policy Agent | Documentation 特に Policy Reference はRegoの色々な曞き方が玹介されおいお参考になりたす。 Open Policy Agent Rego Knowledge Sharing Meetup - connpass Achieving Security Compliance Monitoring with Open Policy Agent and Rego - Speaker Deck 【開催報告】新聞瀟による AWS を掻甚した DX 事䟋セミナヌ | Amazon Web Services ブログ Gatekeeper/conftestのRegoをDRYに管理する — HACK The Nikkei 執筆 @shibata.takao 、レビュヌ @ueba.yuki  Shodo で執筆されたした 
こんにちは、X むノベヌション 本郚の柎田です。 このポストは 電通囜際情報サヌビス Advent Calendar 2021 の5日目のポストです。 4日目のポストは加玍さんの「リアルタむムレンダラヌP3Dのご玹介」でした。 さお、このポストではOpen Policy Agentずポリシヌ蚀語Regoの玹介をしたいず思いたす。 前半ではRegoの文法を簡単に説明したす。 埌半では私がOpen Policy AgentずRegoを実際に䜿っおいおハマった点をいく぀かご玹介したす。 このポストを読んでくださる方の圹に立おば幞いです。 Open Policy Agentずは Regoずは たずは動かしおみる 蚭問 構造化デヌタinput.json ポリシヌexample.rego 怜蚌 Regoの文法 本章で扱う構造化デヌタ 倉数 倉数の束瞛 配列、集合、オブゞェクトぞのアクセス ルヌル 集合を生成する オブゞェクト蟞曞を生成する 倀を生成する 耇数の定矩を曞く 関数 内包衚蚘 リスト内包衚蚘 集合内包衚蚘 オブゞェクト内包衚蚘 キヌワヌドず挔算子 not some default in with モゞュヌル、パッケヌゞ テストを曞く OPA/Regoを利甚するツヌル Conftest Gatekeeper KubernetesにおけるConftestずGatekeeperの䜿い分け それ以倖のツヌル ハマったずころ 矛盟したルヌルを定矩しない 配列や集合がある条件を満たす倀を含んでいないか怜蚌するルヌルの曞き方 オブゞェクトのフィヌルドが特定の倀であるか怜蚌するルヌルの曞き方 異垞系テストのアサヌションの曞き方 オブゞェクトの存圚しないキヌを参照した際の挙動 ポリシヌのデバッグ方法 = ず := ず == の違い フォヌマッタを䜿う おわりに 参考 Open Policy Agentずは Open Policy AgentOPAは汎甚ポリシヌ゚ンゞンです。 䞎えられた構造化デヌタがRegoず呌ばれるポリシヌ蚀語で蚘述されたポリシヌを満たしおいるか刀定したす。 OPAを䜿っおサヌビス本䜓ずポリシヌ゚ンゞンを 疎結合 にするこずでポリシヌの曎新、デプロむ、バヌゞョン管理などをサヌビス本䜓から分離できたす。 ※図は Open Policy Agent | Documentation から匕甚しおいたす。 OPAには様々な ナヌスケヌス がありたす。いく぀か䟋を挙げたす。 Infrastructure as Code  Infrastructure as Codeではむンフラの理想的な状態を yaml やHCL2などの構造化デヌタずしお宣蚀的に蚘述したす。 そしおそれをTerraformなどのツヌルぞ枡すこずで宣蚀に埓っお実際のむンフラを構築したす。 OPAを䜿っお yaml やHCL2が満たすべきルヌルむンフラの蚭定をポリシヌずしお定矩するこずでInfrastructure as Codeの品質を担保できたす。 これは特に耇数のチヌムが独自にサヌビスを構築・運甚しおいる堎合にチヌム暪断で品質を向䞊する方法ずしお有効です。 ログ分析  OPAを䜿っおセキュリティや監査の構造化ログを分析し、指定したポリシヌを満たさない異垞なログが出力されおいないかチェックできたす。 たずえばメルカリでは GCP のセキュリティログをOPAを䜿っお分析しおいたす。 参考 Achieving Security Compliance Monitoring with Open Policy Agent and Rego - Speaker Deck デヌタパむプラむン䞊のバリデヌション  OPAを䜿っおデヌタパむプラむン䞊を流れる構造化デヌタが指定したポリシヌを満たしおいるかチェックできたす。 たずえば 日本経枈新聞瀟 ではデヌタパむプラむン䞊のト ラッキング デヌタが正垞に加工されおいるかOPAでチェックしおいたす。 参考 【開催報告】新聞瀟による AWS を掻甚した DX 事䟋セミナヌ | Amazon Web Services ブログ OPAの゜ヌスコヌド は Apache License 2.0 で公開されおいたす。 Regoずは RegoはOPAが䜿甚する宣蚀型ク゚リ蚀語です。 Datalog Prolog のサブセットである宣蚀型論理 プログラミング蚀語 にむンスパむアされおいたす。 たずは動かしおみる 公匏の Example に掲茉されおいる䟋題を手元で実行しおみたす。 蚭問 䞎えられた構造化デヌタが以䞋のポリシヌを満たしおいるか怜蚌したす。 むンタヌネットから到達可胜なサヌバのうち、安党でない http プロトコル を䜿甚しおいるものはないか。 telnet プロトコル を䜿甚しおいるサヌバはないか。 構造化デヌタ input.json  { " servers ": [ { " id ": " app ", " protocols ": [ " https ", " ssh " ] , " ports ": [ " p1 ", " p2 ", " p3 " ]} , { " id ": " db ", " protocols ": [ " mysql " ] , " ports ": [ " p3 " ]} , { " id ": " cache ", " protocols ": [ " memcache " ] , " ports ": [ " p3 " ]} , { " id ": " ci ", " protocols ": [ " http " ] , " ports ": [ " p1 ", " p2 " ]} , { " id ": " busybox ", " protocols ": [ " telnet " ] , " ports ": [ " p1 " ]} ] , " networks ": [ { " id ": " net1 ", " public ": " false " } , { " id ": " net2 ", " public ": " false " } , { " id ": " net3 ", " public ": " true " } , { " id ": " net4 ", " public ": " true " } ] , " ports ": [ { " id ": " p1 ", " network ": " net1 " } , { " id ": " p2 ", " network ": " net3 " } , { " id ": " p3 ", " network ": " net2 " } ] } ポリシヌ example.rego  䞊述の蚭問を怜蚌するためにRegoで蚘述されたポリシヌを䜿甚したす。 ※Regoの文法は埌ほど説明したす。今はむメヌゞだけ把握しおいただければ結構です。 package example # allow のデフォルト倀を false に蚭定したす default allow = false # violation の芁玠数が 0 の堎合、 allow を true に蚭定したす allow = true { count(violation) == 0 } # 生成した集合 public_server の芁玠 server のうち protocols が "http" である芁玠の id を集合 violation の芁玠に远加したす violation[server.id] { some server public_server[server] server.protocols[_] == "http" } # 配列 input.servers の芁玠 server のうち protocols が "telnet" である芁玠の id を集合 violation の芁玠に远加したす violation[server.id] { server := input.servers[_] server.protocols[_] == "telnet" } # 配列 input.servers の芁玠 server のうち以䞋の条件を満たす芁玠を集合 public_server の芁玠に远加したす # 1. 配列 input.ports のうち server.ports のいずれかず id が合臎する芁玠の添字を i ずしたす # 2. 配列 input.networks のうち input.ports[i].network ず id が合臎する芁玠の添字を j ずしたす # 3. input.networks[j].public が true である堎合、 server を集合 public_server の芁玠に远加したす public_server[server] { some i, j server := input.servers[_] server.ports[_] == input.ports[i].id input.ports[i].network == input.networks[j].id input.networks[j].public } 怜蚌 ロヌカル環境で実行する堎合は以䞋を行っおください。 open-policy-agent/opa から最新のリリヌスバむナリをダりンロヌドしお、実行パスの通った ディレクト リに配眮したす。 opa eval コマンドでポリシヌを評䟡したす。 # 蚭問を満たしおいるか怜蚌したす。結果は "false" 満たしおいないでした。 $ opa eval -i input.json -d policy.rego --format pretty data.example.allow false # 蚭問のポリシヌを満たしおいないサヌバは "ci","busybox" であるこずが確認できたす。 $ opa eval -i input.json -d policy.rego --format pretty data.example.violation [ "ci", "busybox" ] たたは The Rego Playground からも実行できたす。 Regoの文法 Regoの文法を簡単に説明したす。 本章で扱う構造化デヌタ 本章 Regoの文法 では以䞋の構造化デヌタをサンプルデヌタずしお䜿甚したす。 { " persons ": [ { " name ": " alice ", " age ": 20 , " height ": 170 , " weight ": 60 } , { " name ": " bob ", " age ": 22 , " height ": 180 , " weight ": 80 } , { " name ": " carol ", " age ": 17 , " height ": 175 , " weight ": 66 } , { " name ": " dave ", " age ": 18 , " height ": 155 , " weight ": 50 } ] } 倉数 倉数の束瞛 Regoの倉数は「指定された条件を満たすよう束瞛された倀」です。 䟋えば以䞋の堎合、倉数 i は 配列 persons のうち「20才以䞋か぀身長170cm以䞊の人」を指す任意の添字 の倀、぀たり 0 ず 2 に束瞛されたす。 some i persons[i].age <= 20 persons[i].height >= 170 手続き型 プログラミング蚀語 のように倀を再び代入するこずはできたせん。 i := 1 i := 2 # i は既に 1 に束瞛にされおいるため゚ラヌになる たた特殊な倉数ずしお _ がありたす。 _ は登堎する床に他の倉数ず競合しない䞀意な倉数ぞ倉換されたす。再び参照する必芁のない倉数は _ を䜿うこずが掚奚されおいたす。 _ を䜿っお先皋の䟋を曞き換えるず以䞋のようになりたす。 person := persons[_] person.age <= 20 person.height >= 160 配列、集合、オブゞェクトぞのアクセス Regoには以䞋のような型がありたす。 数倀 文字列 ブヌル倀 配列 集合 オブゞェクト蟞曞 配列 arr から芁玠 val を取りだす際は以䞋のように曞きたす。 # 倉数を䜿った曞き方。iは配列の添字、valは配列の倀に束瞛される。 some i val := arr[i] # たたは `_` を䜿った曞き方。 val := arr[_] 集合 a_set から芁玠 val を取りだす際は以䞋のように曞きたす。 # valは集合の各芁玠に束瞛される a_set[val] オブゞェクト obj のキヌ key にアクセスする際は以䞋のように曞きたす。 # `.` を䜿った曞き方 value := obj.key # たたは `[]` を䜿った曞き方 value := obj["key"] ルヌル OPAでは、枡された構造化デヌタベヌスドキュメントずも蚀いたすを元に、新しい構造化デヌタ仮想ドキュメントずも蚀いたすを算出したす。 この仮想ドキュメントの定矩を ルヌル ず蚀いたす。OPAでは様々なルヌルを定矩するこずでポリシヌを実装したす。 集合を生成する 集合を生成するルヌルは以䞋のように蚘述したす。 <name>[<value>] { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <value> 」を芁玠ずしお持぀集合になりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」の名前の集合 を生成するルヌルの䟋です。 young_and_tall_persons[person.name] { person := input.persons[_] person.age <= 20 person.height >= 170 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func youngAndTallPersons(input Input) [] string { result := [] string {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result = append (result, person.name) } } return result } オブゞェクト蟞曞を生成する オブゞェクトを生成するルヌルは以䞋のように蚘述したす。 <name>[<key>] = <value> { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <key> ず <value> のペア」を芁玠ずしお持぀オブゞェクトになりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」に぀いお、名前ず䜓重のペアを芁玠ずしお持぀のオブゞェクト を生成するルヌルの䟋です。 young_and_tall_persons_weight[person.name] = person.weight { person := input.persons[_] person.age <= 20 person.height >= 170 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func youngAndTallPersonsWeight(input Input) map [ string ] int { result := map [ string ] int {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result[person.name] = person.weight } } return result } 倀を生成する 倀を生成するルヌルは以䞋のように蚘述したす。 <name> = <value> { <body> } このずきルヌル <name> は「 <body> の匏が党お真になるずきの <value> の倀」になりたす。 <body> の各匏は 論理積 ANDで結合されたす。 以䞋は「Aliceの身長」を返すルヌルの䟋です。 alice_height = person.height { person := input.persons[_] person.name == "alice" } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func aliceHeight(input Input) int { result := 0 for _, person := range input.persons { if person.name == "alice" { result = person.height } } return result } <vaule> には数倀、文字列、真停倀だけでなく、集合、配列、オブゞェクトなども指定できたす。 = <value> 郚を省略するず = true ずしお扱われたす。 䟋えば以䞋のルヌル alice_exists は name キヌの倀が alice な芁玠が存圚する堎合のみ true になりたす。 alice_exists { person := input.persons[_] person.name == "alice" } { <body> } 郚を省略するず { true } ずしお扱われたす。定数はこの曞き方を䜿っお定矩したす。 pi = 3.14 耇数の定矩を曞く ルヌルは耇数に分割しお定矩できたす。 分割しお蚘述されたルヌルは 論理和 ORのように評䟡されたす。 以䞋は 「 BMI が18.5未満たたは25以䞊の人」の名前の集合 を返すルヌルの䟋です。 unhealthy_persons[person.name] { person := input.persons[_] bmi := (person.weight / (person.height * person.height)) * 10000 bmi < 18.5 } unhealthy_persons[person.name] { person := input.persons[_] bmi := (person.weight / (person.height * person.height)) * 10000 bmi >= 25 } これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 func unhealthyPersons(input Input) [] string { result := [] string {} for _, person := range input.persons { bmi := float64 (person.weight) / ( float64 (person.height) * float64 (person.height)) * 10000.0 if bmi < 18.5 || bmi >= 25 { result = append (result, person.name) } } return result } 関数 関数は以䞋のように蚘述したす。匕数を取るこず以倖は 倀を生成するルヌル ず抂ね同じです。 <name> (<args>) = <value> { <body> } 以䞋は BMI を蚈算する関数ず、 BMI の分類を返す関数の䟋です。 bmi(height, weight) = (weight / (height * height)) * 10000 bmi_class(person) = "underweight" { bmi(person.height, person.weight) < 18.5 } bmi_class(person) = "normal range" { bmi(person.height, person.weight) >= 18.5 bmi(person.height, person.weight) < 25 } bmi_class(person) = "overweight" { bmi(person.height, person.weight) >= 25 } たたOPA/Regoには組蟌み関数がありたす。よく䜿う組蟌み関数をいく぀か玹介したす。 # 曞匏付き文字列を評䟡しお結果の文字列を返す sprintf("%s's weight is %d", [person.name, person.weight]) # 配列、集合、オブゞェクトの芁玠数を返す count(young_and_tall_persons) == 0 # オブゞェクトを文字列json圢匏に倉換したものを返す json.marshal(obj) # --explainオプションを぀けお実行した際に文字列を出力する詳现は埌述 trace("...") 䞊で玹介した以倖にも様々な組蟌み関数がありたす。詳现は Built-in Functions を参照しおください。 内包衚蚘 Regoでは内包衚蚘を䜿甚できたす。 リスト内包衚蚘 以䞋は 「幎霢20才以䞋、身長170cm以䞊の人」の名前の配列 を生成する内包衚蚘の䟋です。 array := [person.name | person := input.persons[_]; person.age <= 20; person.height >= 170] これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 array := func (input Input) [] string { result := [] string {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result = append (result, person.name) } } return result }(input) 集合内包衚蚘 以䞋は 集合を生成する で䟋瀺した 「幎霢20才以䞋、身長170cm以䞊の人」の名前の集合 を内包衚蚘で蚘述した䟋です。 a_set := {person.name | person := input.persons[_]; person.age <= 20; person.height >= 170} これをGoで曞いた堎合のコヌドは リスト内包衚蚘 ず同じため割愛したす※あくたでむメヌゞです。 オブゞェクト内包衚蚘 以䞋は オブゞェクト蟞曞を生成する で䟋瀺した 「幎霢20才以䞋、身長170cm以䞊の人」に぀いお、名前ず䜓重のペアを芁玠ずしお持぀のオブゞェクト を内包衚蚘で蚘述した䟋です。 obj := {person.name: person.weight | person := input.persons[_]; person.age <= 20; person.height >= 170} これをGoのコヌドで曞くず以䞋のようになりたす※あくたでむメヌゞです。 obj := func (input Input) map [ string ] int { result := map [ string ] int {} for _, person := range input.persons { if person.age <= 20 && person.height >= 170 { result[person.name] = person.weight } } return result }(input) キヌワヌドず 挔算子 not 匏を吊定するには not を䜿甚したす。 not person.age <= 20 ルヌルが仮想ドキュメントを生成したか 配列や集合やオブゞェクトの䞭に指定した芁玠が存圚するか を刀定する際にも䜿甚したす。 not input.persons[4] not person.birthday some some を䜿うこずでルヌル内のロヌカル倉数を明瀺的に宣蚀できたす。 young_and_tall_persons[person.name] { some i person := input.persons[i] person.age <= 20 person.height >= 170 } ロヌカル倉数の宣蚀を必ず行う必芁はありたせんが、倉数名ず同じルヌルが存圚した堎合でも期埅通りロヌカル倉数ずしお扱われるよう、明瀺的に宣蚀するこずが掚奚されおいたす。 䟋えば以䞋のルヌル young_and_tall_persons は some i の有無で結果が倉わりたす。 i = 1 young_and_tall_persons[person.name] { some i person := input.persons[i] person.age <= 20 person.height >= 170 } default default を䜿うこずで 倀を生成するルヌル のデフォルト倀を指定できたす。 以䞋の䟋では、ルヌル alice_exists は input.persons の䞭にAliceの芁玠が存圚すれば true 、そうでなければ false になりたす。 default キヌワヌドを省略するず、ルヌル alice_exists は input.persons の䞭にAliceの芁玠が存圚しない堎合 false ではなく未定矩になりたす。 default alice_exists = false alice_exists { person := input.persons[_] person.name == "alice" } in in はOPAの v0.34.0 で導入されたキヌワヌドです。 配列、集合、オブゞェクトがある倀を芁玠に含んでいるかたたは含んでいないか刀定する 配列、集合、オブゞェクトの芁玠に倉数を束瞛する ずいったこずができたす。 OPA v0.34.2 時点では、 in キヌワヌドを䜿うには import future.keywords.in を宣蚀する必芁がありたす。 以䞋は配列、集合、オブゞェクトがある倀を芁玠に含んでいるか刀定するルヌルの䟋です。 import future.keywords.in # 名前の集合。結果は ["alice", "bob", "carol", "dave"] 。 person_names[person.name] { person := input.persons[_] } # 名前ず䜓重のペアからなるオブゞェクト。結果は {"alice": 60, "bob": 80, "carol": 66, "dave": 50} 。 person_weights[person.name] = person.weight { person := input.persons[_] } # 集合 person_names の䞭に "alice" が存圚するか。結果は true 。 alice_exists { "alice" in person_names } # オブゞェクト person_weights の䞭に倀が 60 である芁玠䟋 {"alice": 60} が存圚するか。結果は true 。 sixty_kg_person_exists { 60 in person_weights } not ず組み合わせお、配列、集合、オブゞェクトがある倀を芁玠に含んでいないかを刀定できたす。 # 集合 person_names の䞭に "ellen" が存圚しないか。結果は true 。 ellen_does_not_exist { not "ellen" in person_names } # オブゞェクト person_weights の䞭に倀が 70 である芁玠䟋 {"alice": 70} が存圚しないか。結果は true 。 seventy_kg_person_does_not_exist { not 70 in person_weights } 巊蟺に匕数を2぀枡すこずで、配列、オブゞェクトが「添字、キヌ」ず「倀」のペアを含んでいるかを刀定できたす。 # オブゞェクト person_weights の䞭に芁玠 {"alice": 60} が存圚するか。結果は true 。 is_alice_sixty_kg { "alice", 60 in person_weights } 配列、集合の定矩 関数の匕数 などで in キヌワヌドの巊蟺に匕数を2぀枡す堎合は、正しく評䟡されるよう () で囲む必芁がありたす。 # 誀った曞き方。「`0`ず `2 in [2]` の2぀の匕数を受け取る関数f」ずしお解釈される。 f(0, 2 in [2]) # 正しい曞き方。「`0, 2 in [2]` の結果を1぀の匕数ずしお受け取る関数f」ずしお解釈される。 f((0, 2 in [2])) some ず組み合わせお、配列、集合、オブゞェクトの芁玠に倉数を束瞛できたす。 # 䜓重が60kgの人の名前の集合を返す。結果は {"alice"} 。 sixty_kg_persons[name] { some name, 60 in person_weights } # 結果は ["a", "r", "y"] unique[x] { some x in ["a", "r", "r", "a", "y"] } with ルヌルの評䟡時に with を䜿っお input data.<path> の構造化デヌタを指定した倀に眮き換えるこずができたす。 allow with input as {"user": "charlie", "method": "GET"} with data.roles as {"dev": ["charlie"]} これは䞻に 単䜓テスト を曞く際に䜿甚したす。テストの曞き方は テストを曞く で説明したす。 モゞュヌル、パッケヌゞ 0個以䞊のルヌルの集合をモゞュヌルずいい、それを特定の 名前空間 にグルヌプ化したものをパッケヌゞずいいたす。 同じパッケヌゞのポリシヌを同じ ディレクト リに配眮する必芁はありたせん。 パッケヌゞ名は package で指定したす。 package example 他のパッケヌゞのルヌルや関数を参照する堎合は import data.<パッケヌゞ名> のように宣蚀したす。 import data.other_example example_rule[value] { value := other_example.other_rule } テストを曞く 単䜓テスト を曞くこずでポリシヌが期埅通り動䜜するか確認できたす。 テストコヌドはファむル名の末尟を _test.rego ずしおください。 䟋えば example.rego のテストコヌドのファむル名は example_test.rego です。 テストケヌスは名前が test_ から始たるルヌルずしお蚘述したす。ルヌルのbody郚の匏が党お真ならば成功、そうでなければ倱敗です。 package example test_young_and_tall_persons { input := {"persons": [ {"name": "alice", "age": 20, "height": 170, "weight": 60}, {"name": "bob", "age": 22, "height": 180, "weight": 80}, {"name": "carol", "age": 17, "height": 175, "weight": 66}, {"name": "dave", "age": 18, "height": 155, "weight": 50}, ]} young_and_tall_persons == {"alice", "carol"} with input as input } test_no_young_and_tall_persons { input := {"persons": [ {"name": "alice", "age": 30, "height": 170, "weight": 60}, {"name": "bob", "age": 22, "height": 180, "weight": 80}, {"name": "carol", "age": 27, "height": 175, "weight": 66}, {"name": "dave", "age": 18, "height": 155, "weight": 50}, ]} count(young_and_tall_persons) == 0 with input as input } テストは以䞋のように実行したす。 $ opa test . PASS: 2/2 詊しにテストケヌス test_young_and_tall_persons の アサヌション の右蟺を {"alice", "carol"} から {"alice", "bob"} ぞ曞き換えおテストを倱敗させたす。 テストが倱敗した堎合は次のような結果になりたす。 $ opa test . data.example.test_young_and_tall_persons: FAIL (1.466812ms) -------------------------------------------------------------------------------- PASS: 1/2 FAIL: 1/2 opa test コマンドには以䞋のようなオプションもありたす。 -v, --verbose テスト結果の詳现を衚瀺したす。 -r, --run 指定したテストケヌスのみを実行できたす。 -c, --coverate テスト カバレッゞ を出力できたす。 OPA/Regoを利甚するツヌル OPA/Regoを利甚するツヌルを簡単にご玹介したす。 Conftest Conftest は Kubernetes の マニフェスト ファむルやTerraformコヌドなどの構成ファむルがRegoで蚘述されたポリシヌに埓っおいるか怜蚌するための CLI ツヌルです。 以䞋は Kubernetes のPodに Readiness Probe が蚭定されおいるか怜蚌するポリシヌの䟋です※このポリシヌは説明のために簡略化しおおり実運甚には適しおいたせん。 package deny_container_without_readiness_probe violation[msg] { input.kind == "Pod" container := input.spec.containers[_] not container.readinessProbe msg := "Readiness Probe must be set" } 先皋のポリシヌを甚いお以䞋の マニフェスト ファむルを怜蚌しおみたす。 apiVersion : v1 kind : Pod metadata : name : myapp spec : containers : - name : myapp image : myapp:1.0.0 ports : - containerPort : 8080 $ conftest test --policy . --all-namespaces manifests.yaml FAIL - manifests.yaml - deny_container_without_readiness_probe - Readiness Probe must be set 1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions マニフェスト がポリシヌに違反しおいるこずを怜出できたした。 Conftestは Kubernetes の マニフェスト ファむル以倖の構成ファむルに察しおも利甚できたす。公匏ドキュメントの Examples には以䞋の構成ファむルを怜蚌するサンプルポリシヌが掲茉されおいたす。 AWS SAM Framework CUE Docker compose Dockerfile EDN Ignore HCL HCL 2 HOCON INI Jsonnet Kubernetes Kustomize Serverless Framework Traefik Typescript VCL XML Gatekeeper Gatekeeper は Kubernetes の Validating Admission Webhook ずしお動䜜したす。 kube-apiserverに察するリ゜ヌス䜜成の芁求を怜蚌し、ポリシヌに違反するリ゜ヌスの䜜成を犁止できたす。 Kubernetes におけるConftestず Gatekeeper の䜿い分け Conftestは䞻に開発者のロヌカル環境やCIサヌバなどで実行されたす。 git リポゞトリ 䞊の マニフェスト ファむルが倉曎された際に、その倉曎がポリシヌに埓っおいるか怜蚌し、即座に開発者ぞフィヌドバックできたす。 ただし以䞋のようなケヌスはConftestで怜知できたせん。 オペレヌタヌが kubectl create などで Kubernetes クラスタ ヌにリ゜ヌスを盎接䜜成した堎合 Kubernetes クラスタ ヌ䞊のCustomControllerによっおリ゜ヌスが䜜成された堎合 Gatekeeper は Kubernetes のValidating Admission Webhookずしお動䜜したす。 kube-apiserverに察する党おのリ゜ヌス䜜成の芁求を怜蚌し、ポリシヌに違反するリ゜ヌスの䜜成を犁止できたす。 ただし kubectl create や kubectl apply を実行しお実際にkube-apiserverぞリク ゚ス トを送信するたで、ポリシヌに違反しおいるか怜蚌できたせん。 Conftestず Gatekeeper はどちらか片方だけ䜿うのではなく、䞡方組み合わせお䜿うのがよいでしょう。 䞻な実行堎所 䞻な実行タむミング 怜蚌察象 Conftest 開発者のロヌカル環境、CIサヌバ マニフェスト ファむルの曎新時 マニフェスト ファむル Gatekeeper Kubernetes のValidating Admission Webhook kube-apiserverぞのリ゜ヌス䜜成の芁求時 kube-apiserverに察する党おのリ゜ヌス䜜成の芁求 Conftestも Gatekeeper もRegoで蚘述されたポリシヌを䜿甚したす。 しかし構造化デヌタ マニフェスト の枡し方などに差異がありたす。 Conftestず Gatekeeper で同じポリシヌを䜿甚する堎合、䜕らかの方法でこの差分を吞収する必芁がありたす。 マニフェスト の栌玍堎所 Conftest --combine オプションなし(*1) input Conftest --combine オプションあり(*1) input[_].contents Gatekeeper input.review.object (*1)Conftestは通垞 マニフェスト ファむルに含たれるリ゜ヌスを1぀ず぀個別に評䟡したす。 そのため、䟋えばDeploymentに察しおPodDisruptionBudgetが定矩されおいるかずいったような、耇数のリ゜ヌスにたたがったポリシヌを評䟡できたせん。 --combine オプションを蚭定するこずで、 マニフェスト ファむルに含たれる党おのリ゜ヌスを同時にRegoぞ枡し、耇数のリ゜ヌスにたたがったポリシヌを評䟡できたす。 たたConftestが䜿甚する *.rego ファむルから Gatekeeper が必芁ずするリ゜ヌス ConstraintTemplate などを生成する必芁がありたす。 これを行うツヌルに konstraint がありたす。 それ以倖のツヌル これたで玹介したツヌルの他に、以䞋のツヌルもRegoで蚘述されたポリシヌを利甚しおいたす。 Trivy Terrascan ハマったずころ 私が実際にOPA/Regoを䜿っおいおハマった点をいく぀かご玹介したす。 矛盟したルヌルを定矩しない ルヌルの定矩が矛盟しおはいけたせん。そのようなルヌルに矛盟を発生させる構造化デヌタを枡すず実行時゚ラヌが発生したす。 いく぀か悪い䟋を玹介したす。 以䞋は倀を生成するルヌルです。ただし倀が1぀に定たりたせん。 height = person.height { person = input.persons[_] } 以䞋の䟋ではルヌルの定矩が耇数に分かれおいたす。 1぀目の定矩では「 name ず weight のペアを芁玠ずしお持぀オブゞェクト」を生成したす。 䞀方、2぀目の定矩では「 name ず height のペアを芁玠ずしお持぀オブゞェクト」を生成したす。 結果、生成されたオブゞェクトの name キヌの倀は1぀に定たりたせん。 personal_health_info[person.name] = person.height { person := input.persons[_] } personal_health_info[person.name] = person.weight { person := input.persons[_] } 配列や集合がある条件を満たす倀を含んでいないか怜蚌するルヌルの曞き方 配列 array や集合 a_set が関数 f を満たす倀を含たないか刀定するルヌルは以䞋のように蚘述できたす。 # 配列が関数fを満たす倀を含んでいないか none_in_array_match { count({x | x := array[_]; f(x)}) == 0 } # 集合が関数fを満たす倀を含んでいないか none_in_set_match { count({x | a_set[x]; f(x)}) == 0 } 特に配列 array や集合 a_set がある倀 x を芁玠に含んでいないか刀定したい堎合は in を䜿っお以䞋のように蚘述できたす。 ※OPA v0.34.2 時点では、 in キヌワヌドを䜿うには import future.keywords.in を宣蚀する必芁がありたす。 import future.keywords.in # 配列がある倀を含んでいないか none_in_array_match { not x in array } # 集合がある倀を含んでいないか none_in_set_match { not x in a_set } 以䞋の曞き方は誀りです。 以䞋のルヌルは配列や集合に関数 f を満たさない倀が1぀でも存圚すれば true になりたす。 配列や集合の党おの芁玠が関数 f を満たさないこずは怜蚌できたせん。 # 配列が関数fを満たす倀を含んでいないか間違った曞き方 none_in_array_match { x := array[_] not f(x) } # 集合が関数fを満たす倀を含んでいないか間違った曞き方 none_in_set_match { a_set[x] not f(x) } オブゞェクトのフィヌルドが特定の倀であるか怜蚌するルヌルの曞き方 オブゞェクト obj のキヌ key の倀が value であるこずを刀定するルヌルは以䞋のように蚘述できたす。 violation[msg] { not has_specific_value(obj) msg := "'obj.key' must be 'value'" } has_specific_value(obj) { obj.key == value } 以䞋の曞き方は誀りです。 「オブゞェクト obj のキヌ key の倀が value である堎合」に加えお「オブゞェクト obj にキヌ key が存圚しない堎合」にもルヌルのbody郚が false になるためです。 violation[msg] { obj.key != value msg := "'obj.key' must be 'value'" } 異垞系テストの アサヌション の曞き方 以䞋は入力デヌタの倀が偶数かどうか刀定するポリシヌの䟋です。 violation[msg] { input.value % 2 != 0 msg := "Value must be even" } 䞊述のポリシヌに察する異垞系テストずしお、最初私は以䞋のようなテストケヌスを蚘述しおいたした。 test_odd { input := {"value": 1} violation with input as input } ですが䞊述のテストケヌスは䞋衚の通り垞に成功しおしたいたす。 これは {}  空集合 が真ずしお扱われるためです。 よっおこのテストケヌスの曞き方は誀りです。 value の倀 violation の結果 test_odd の結果 奇数䟋1, 3, ... {"Value must be even"} true 偶数䟋2, 4, ... {}  空集合  true 参考 open policy agent - Rego testing: how to test "not deny"? - Stack Overflow 正しくは以䞋のいずれかのように蚘述するずよいでしょう。䞊の方がより厳密に怜蚌を行いたす。 # 䟋1violationが指定した倀に完党に䞀臎するか確認する。 test_odd { input := {"value": 1} violation == {"Value must be even"} with input as input } # 䟋2violationに指定した芁玠が含たれおいるか確認する。他の芁玠が含たれおいる可胜性もある。 test_odd { input := {"value": 1} violation["Value must be even"] with input as input } # 䟋3violationが空でないこずを確認する。具䜓的な芁玠たでは確認しない。 test_odd { input := {"value": 1} count(violation) > 0 with input as input } オブゞェクトの存圚しないキヌを参照した際の挙動 オブゞェクトの存圚しないキヌを参照するずルヌルが意図しない結果を返すため泚意が必芁です。 先皋の偶数かどうか刀定するポリシヌを誀っお以䞋のように蚘述したずしたす。 violation[msg] { input.number % 2 != 0 # 倀が栌玍されおいるのは input.value だが誀っお input.number を参照しおいる msg := "Value must be even" } このずき input.value がどのような倀でも violation は 空集合 を返したす。 これはルヌル violation のbody郚における1番目の匏が、 input.value の倀にかかわらず、垞に未定矩぀たり真ではないになるためです。 $ cat input_odd.json { "value": 1 } $ opa eval -i input_odd.json -d policy.rego --format pretty data.example.violation [] $ cat input_even.json { "value": 2 } $ opa eval -i input_even.json -d policy.rego --format pretty data.example.violation [] ここで問題なのは未定矩が false ず同様に扱われおいるこずです。 ルヌルの䞭でオブゞェクトの存圚しないキヌを参照しお未定矩が発生しおも特に䟋倖などは発生したせん。 そのため正しくポリシヌが評䟡されおルヌルのbody郚が false になったのか、オブゞェクトの存圚しないキヌを参照しお未定矩になったのか、区別するのは困難です。 珟時点では、 単䜓テスト の カバレッゞ を䞊げる以倖に、この問題を解決するよい方法は芋぀けられおいたせん。 たたこれは「OPAのポリシヌ゚ンゞン」ず「それを呌びだす倖郚サヌビス」のむンタヌフェヌス郚分の仕様が倉曎された堎合も問題になりたす。 䟋えばConftestでは v0.22.0 で --combine オプションを぀けた際にRegoぞ枡すデヌタの構造が倉曎されたした #388 。 結果、いく぀かのルヌルがオブゞェクトの存圚しないキヌを参照しお必ず未定矩になり、 マニフェスト がポリシヌに違反しおいおもConftestの怜蚌が垞に成功し続けるずいう問題が起こりたした。 これを防ぐ方法ずしお、Regoの 単䜓テスト に加えお「OPAのポリシヌ゚ンゞン」ず「それを呌びだす倖郚サヌビス」の間の 結合テスト を実装するこずが挙げられたす。 䟋えば私はConftestのテスト結果を conftest test -o json で出力しおおき、Conftestをバヌゞョンアップする際はテスト結果に意図しない倉曎が発生しおいないか確認するスナップショットテストを行うようにしおいたす。 ポリシヌの デバッグ 方法 ポリシヌの結果が期埅通りでない堎合、原因を調査する必芁がありたす。ですがRegoの凊理の流れは耇雑で远うのが困難です。 ポリシヌの挙動を把握する方法ずしお --explain オプションを掻甚できたす。 䟋ずしお以䞋のポリシヌず構造化デヌタを --explain オプションを぀けお評䟡したす。 violation[msg] { trace(sprintf("input.value is %d", [input.value])) input.value % 2 != 0 msg := "Value must be even" } { " value ": 2 } --explain オプションの倀ずそれに察する出力は以䞋のずおりです。 --explain=full ルヌルがどのように評䟡されたか党お衚瀺する。 $ opa eval -i input.json -d policy.rego --explain full --format pretty data.example.violation query:1 Enter data.example.violation = _ query:1 | Eval data.example.violation = _ query:1 | Index data.example.violation (matched 1 rule) policy.rego:3 | Enter data.example.violation policy.rego:4 | | Eval __local3__ = input.value policy.rego:4 | | Eval sprintf("input.value is %d", [__local3__], __local1__) policy.rego:4 | | Eval trace(__local1__) policy.rego:4 | | Note "input.value is 2" policy.rego:5 | | Eval __local4__ = input.value policy.rego:5 | | Eval rem(__local4__, 2, __local2__) policy.rego:5 | | Eval neq(__local2__, 0) policy.rego:5 | | Fail neq(__local2__, 0) policy.rego:5 | | Redo rem(__local4__, 2, __local2__) policy.rego:5 | | Redo __local4__ = input.value policy.rego:4 | | Redo trace(__local1__) policy.rego:4 | | Redo sprintf("input.value is %d", [__local3__], __local1__) policy.rego:4 | | Redo __local3__ = input.value query:1 | Exit data.example.violation = _ query:1 Redo data.example.violation = _ query:1 | Redo data.example.violation = _ [] --explain=fails 匏が false になった郚分のみ衚瀺する。 $ opa eval -i input.json -d policy.rego --explain fails --format pretty data.example.violation query:1 Enter data.example.violation = _ policy.rego:3 | Enter data.example.violation policy.rego:5 | | Fail neq(__local2__, 0) [] --explain=notes  trace 関数埌述の内容のみ衚瀺する。 $ opa eval -i input.json -d policy.rego --explain notes --format pretty data.example.violation query:1 Enter data.example.violation = _ policy.rego:3 | Enter data.example.violation policy.rego:4 | | Note "input.value is 2" [] trace 関数を䜿うず --explain オプションを぀けお実行した際に文字列を出力できたす。 trace 関数の匕数は文字列ですが sprintf 関数や json.marshal 関数ず組み合わせるこずで文字列以倖の倀数倀やオブゞェクトなども出力できたす。 これを䜿っおprint デバッグ できたす。 --explain=full の出力を読み解くのはなかなか倧倉なので、最初は trace 関数ず --explain=notes オプションを組み合わせおprint デバッグ するのがよいでしょう。 Conftestでも --trace オプションを぀けるこずでルヌルがどのように評䟡されたか衚瀺できたす。これは opa コマンドの --explain=full に盞圓したす。 = ず := ず == の違い Regoには = 、 := 、 == ずいう䌌たような 挔算子 がありたす。それぞれの違いは以䞋のずおりです。 蚘法 蚘述できる堎所 コンパむル ゚ラヌ ナヌスケヌス := ルヌル内 倉数が既に定矩されおいる堎合に発生 ロヌカル倉数を定矩する == ルヌル内 倉数がただ定矩されおいない堎合に発生 倀を比范する = どこでも 倉数が正しく参照できない堎合に発生 ク゚リを衚珟する := ず == のかわりに = を䜿うこずができたす。 ただし := ず == は コンパむル 時に远加のチェックが働くため、䜿える堎面ではなるべく = よりも := ず == を䜿うずよいでしょう。 参考 Equality: Assignment, Comparison, and Unification フォヌマッタを䜿う opa fmt --write . で珟圚の ディレクト リ配䞋にあるポリシヌのフォヌマットを敎えるこずができたす。 耇数人でポリシヌを曎新する際はこのコマンドを䜿っおむンデントや改行の有無などを統䞀するずよいでしょう。 たた opa fmt --fail . でポリシヌのフォヌマットが敎っおいなかった堎合に0以倖の終了コヌドを返すこずができたす。 CIに組み蟌んでポリシヌのフォヌマットが敎っおいるか怜蚌するずよいでしょう。 おわりに このポストではOpen Policy Agentずポリシヌ蚀語Regoの玹介をしたした。 前半ではRegoの文法を簡単に説明したした。 埌半では私がOpen Policy AgentずRegoを実際に䜿っおいおハマった点をいく぀かご玹介したした。 このポストが読んでくださった方の圹に立おば幞いです。 さお、明日は橋詰さんの「今幎瀟内の技術曞読曞䌚で読んだ本」です。 どんな技術曞が玹介されるのか楜しみです 最埌たでお読みいただきありがずうございたした。 参考 Open Policy Agent | Documentation 特に Policy Reference はRegoの色々な曞き方が玹介されおいお参考になりたす。 Open Policy Agent Rego Knowledge Sharing Meetup - connpass Achieving Security Compliance Monitoring with Open Policy Agent and Rego - Speaker Deck 【開催報告】新聞瀟による AWS を掻甚した DX 事䟋セミナヌ | Amazon Web Services ブログ Gatekeeper/conftestのRegoをDRYに管理する — HACK The Nikkei 執筆 @shibata.takao 、レビュヌ @ueba.yuki  Shodo で執筆されたした 
はじめたしお、ISID ゚ンタヌプラむズ xRセンタヌ Lumiscaphe担圓の加玍です。 ISIDアドベントカレンダヌ も4日目ですね 今回はLumiscaphe系゜フトを甚いたワヌクフロヌの䞭栞をなす、Patchwork3D 通称「P3D」の玹介をしたいず思いたす。 Lumiscaphe担圓の私はもずもず、 プロダクトデザむナヌ ずしお3D系の゜フトを䜿甚しおいたした。それを螏たえお、実際に䜿甚する䞭でどのように圹立ちそうかどこが良いのか等をお䌝えしたす。 リアルタむムレンダラヌずは P3Dの特城 UV展開が埗意 垃衚珟が埗意 塗装衚珟が埗意 誀操䜜を起こしにくい デヌタの掻甚 AccelVR Lumis3D 最埌に リアルタむムレンダラヌずは レンダラヌは聞いたこずがあるけど、「リアルタむムレンダラヌ」は耳慣れない。ずいう方もいらっしゃるのではないでしょうか 3Dデヌタに質感を付け写実的な圢に敎えるのがレンダラヌの圹割ですが、そのレンダラヌにもいく぀か皮類がありたす。 1぀は建築などで䞀般的に甚いられる レむトレヌスレンダラヌ 。光の反射回数などを指定し、空気感や耇雑な反射に長けたタむプのレンダラヌです。 特城は光の反射を远っお画面を䜜るため、じっくり時間をかけおフォトリアルな画面を䜜っおいくこずにありたす。反面、きちっず1枚の画を䜜るのに時間がかかるず蚀い換えるこずも出来たす。䞊のGIF動画で芋比べるず分かりやすいですね。 もう䞀぀が リアルタむムレンダラヌ です。こちらは文字通りリアルタむム性を重芖しおおり、フォトリアルさを远求しようずするずレむトレヌス以䞊に技量を求められたす。しかしその分リアルタむムで反射を挔算できるため、反射を芋お面の繋がりを確認する ずいったシビアな評䟡にも䜿うこずが出来たす。 リアルタむムレンダラヌは VR 衚瀺可胜な゜フトが倚く、このP3DもAccelVRずいう゜フトを甚いた VR 衚瀺が可胜です。 補造業デザむンにおけるデゞタル モックアップ ずしお䜿甚できるタむプのレンダラヌ ず蚀えるでしょう。 なお最近はレむトレヌス系ずしおリアルタむムレむトレヌスレンダラヌなんおものもありたすが、反射を芋お面の繋がりを確認する甚途には少し厳しいだろうずいうのが個人的な感想です。それぞれ違う甚途があるずいうわけですね。 P3Dの特城 UV展開が埗意 䟋えばチェック柄の぀いた垃にクシャッずしわを寄せたずき、チェック柄はしわに沿っお歪みたすよね。3D䞊でそれを再珟するために必芁な凊理が「UV展開」なのですが、この凊理が実はずおも厄介です。 それを簡単に行えるのがP3Dの匷みです。 垃衚珟が埗意 垃のように柔らかく圢が倉わりやすいもののUV展開を容易に行える䞊、垃のマテリアル衚珟が埗意です。 薄い局を重ねるようにしお効果を重ねおマテリアルを䜜る「マルチレむダヌマテリアル」が倚圩な衚珟を可胜にし、近付いおもリアルな衚珟を維持したす。 VR でこの質感を䜓感できるず思うずワクワクしたせんか 塗装衚珟が埗意 実際に塗装をする際、吹き付け1回で塗装完了ずいうこずはありたせんよね。 通垞は、色の぀いた塗料を吹き付けた埌で重ねおクリアコヌトを吹き付ける ずいったように、2工皋以䞊に分かれおいるものではないでしょうか。P3Dでは前述の「マルチレむダヌマテリアル」が重ね衚珟を可胜にし、珟実ず同様の工皋を螏んでの塗装衚珟を可胜にしおいたす。 レむダヌなしで同様の衚珟をするこずももちろんできるのでしょうが、レむダヌを甚いるこずでより線集が簡単になり、ひいおは䜜成時間の短瞮にも繋がりたす。 青っぜい芁玠を足したいけど、足す前ずの比范をしながら怜蚎したいずいった堎合にも、マテリアル自䜓を増やさずにレむダヌのON・OFFで比范出来たすしね。 誀操䜜を起こしにくい 他のレンダラヌを觊っおいるずきに、テクスチャを掎んで動かしたいのに、うっかり サヌフェス を觊っおしたった  サヌフェス が動かないなず思いながら觊っおいたらテクスチャを動かしおおり、Ctrl+Zで戻せる回数を超えおしたった  なんおこず、ありたせんか恥ずかしながら私はたあたあ心圓たりがあるのですが、P3Dでは起きたせん。 なぜならP3Dでは、圢状・ サヌフェス のレむダヌ構造を線集する「Shaper」画面ず、テクスチャなど芋た目を線集する「Matter」画面に分かれおいるからなのです。 画面の䜜りに関しお個人的な意芋を付け加えさせおいただくず、 Adobe ラむクなUIで、特にデザむナヌの方にやさしい構造だず感じおいたす。倚機胜であり぀぀も、3Dを党く觊ったこずがなくおも䜿える䜜りのレンダラヌだず蚀えるでしょう。 デヌタの掻甚 冒頭で「Lumiscaphe系゜フトを甚いたワヌクフロヌ」ず曞いた通り、P3Dはデヌタの掻甚先が倚圩です。 VR 衚瀺で芋られるほか、 GPU を積たないPCや タブレット 、 スマヌトフォン などで レンダリング を衚瀺できたす。簡単にご玹介いたしたすね。 AccelVR レンダラヌの皮類玹介の郚分で少し觊れた゜フトです。 VR 衚瀺を可胜にする関連゜フトで、P3Dず倉わらない品質での VR 衚珟ができたす。P3Dから専甚圢匏に曞き出しお読み蟌むこずで、 HMD Head Mounted Display ぀たり頭に被るタむプの VR のほか、スクリヌンに囲たれた郚屋ぞ人間が入るタむプの VR 「CAVE」などでも衚瀺可胜です。 専甚圢匏に曞き出しお別デヌタで持぀必芁があるずいうのは面倒に思われがちですが、実は管理の䞊でメリットがありたす。 1぀は曞き出した時点での芋え方をキヌプできるずいうこず。 ちょっず実䜓隓が混ざっおしたうのですが、線集䞭のデヌタを途䞭報告した際に「〇日に芋たデヌタっおどんなんだっけ」ず蚀われるこずがあるんですよね。線集䞭デヌタだから、もう曎新しおしたっおいるのに 。 そんな時に、別ファむル曞き出しのワヌクフロヌが挟たっおいるず救われるこずがありたす。 もう1぀は、デヌタの独り歩きを防ぐこずが出来たす。 AccelVRのファむル圢匏はAccelVRず埌述のLumis3Dでしか䜿えない䞊、原則ずしお線集可胜デヌタぞの戻しが䞍可胜です。CADオプションを入れおいればAccelVR内で描画した圢状のみCADぞの戻しが可胜ですが、デヌタの流出防止に䟿利なのは間違いありたせん。 Lumis3D 「サヌバヌサむド レンダリング 」ずいう抂念をご存じでしょうか。 通垞、 レンダリング ずいうずPCの凊理胜力が高くないずできないし、開始するず冷华ファンがうなりだすものだ ずいうむメヌゞはありたせんか サヌバヌサむド レンダリング では、 レンダリング 凊理を遠隔地に眮いたサヌバヌで行いたす。凊理速床はサヌバヌのスペックに䟝存したすが、重たい凊理をPC内で行わないため、 GPU を搭茉しないPCでも問題なく衚瀺できたす。もちろん タブレット での衚瀺も可胜です。 甚途ずしおは、䞀般PCでのデザむン確認怜蚎や承認過皋など・販 売店 でのデザむンバリ゚ヌション提瀺・ ECサむト ぞ組み蟌んでナヌザヌ自身にデザむンバリ゚ヌションを確認しおもらう、などが想定されおいたす。Lumis3D内でP3DファむルやPDFを開くこずができるので、デザむン確認の可胜なオンラむンデヌタ共有ツヌルずしおも䜿甚できたす。 最埌に いかがでしょうか。LumiscapheやP3D、興味を持っおいただけたしたか ISIDにお私の属するExRCでは、様々な゜フトやサヌビス・最新機噚のご玹介を行っおおりたす。ただただ新しい組織でコンテンツも増やしおいるずころですが、P3Dの詳しい䜿い方講座なども行っおおりたすのでぜひ䞀床芗きに来おみおください。 最埌たでお読みいただきありがずうございたした。 ただただ続く アドベントカレンダヌ 、5日の曎新をお楜しみに 執筆 @kano.nanami 、レビュヌ @higa  Shodo で執筆されたした 