dely株匏䌚瀟のブログ - TECH PLAY

TECH PLAY

dely株匏䌚瀟

dely株匏䌚瀟 の技術ブログ

å…š237ä»¶

はじめに こんにちは、クラシルリワヌドのサヌバヌサむド゚ンゞニアのrakuです 今回は趣味でRemixを䜿甚した耇雑なフォヌムの実装をする際に䟿利だった、React向けのtype-safeなフォヌムラむブラリであるConformに぀いおご玹介したす。 Conformは、RemixやNext.jsでFormDataの怜蚌をサヌバヌサむドでも簡単に実装できるため、これらのフレヌムワヌクずの盞性が抜矀です。そのため、Remix Resourcesでも玹介されおいたす。 remix.run たたConformの特城を公匏ドキュメントから匕甚するず↓ず曞かれおいたす. Progressive enhancement first APIs. Type-safe field inference. Fine-grained subscription. Built-in accessibility helpers. Automatic type coercion with Zod. conform.guide Remixずの連携 䞀般的にフロント゚ンドずバック゚ンドのあるシステムでは、入力倀のバリデヌションをフロント゚ンドずバック゚ンドの䞡方で行うこずが望たしいです。 ConformはRemixの action 関数ず useActionData フックを䜿っおサヌバヌサむドずクラむアントサむドの連携を実珟し、zodで定矩した型スキヌマを䜿っおデヌタのバリデヌションを行いたす。 Conformを䜿うこずでRemixのサヌバヌサむドずクラむアントサむドの凊理をシヌムレスに連携できたす。 サンプルコヌド 以䞋は、RemixずConformを䜿った動的なフォヌムのサンプルコヌドです。 UIコンポヌネントにshadcn/uiを䜿甚しおいたす ui.shadcn.com import { getFormProps , getInputProps , useForm } from "@conform-to/react" ; import { getZodConstraint , parseWithZod } from "@conform-to/zod" ; import { ActionFunctionArgs , json } from "@remix-run/node" ; import { Form , useActionData } from "@remix-run/react" ; import { FC , useEffect } from "react" ; import { z } from "zod" ; import { Button } from "~/components/ui/button" ; import { Input } from "~/components/ui/input" ; import { Label } from "~/components/ui/label" ; const schema = z. object ( { title: z. string ( { required_error: "タむトルは必須です" } ), lists: z . object ( { name: z. string (), location: z. string () } ) .array () .nonempty ( "アむテムを远加しおください" ), } ); export const action = async ( { request } : ActionFunctionArgs ) => { const submission = parseWithZod (await request.formData (), { schema } ); console .log ( submission.reply ()); return json ( { message: "゚ラヌ" , submission: submission.reply ( { formErrors: [ "゚ラヌメッセヌゞ" ] } ), } ); } ; const ErrorMessage: FC < { error?: string [] } > = ( { error } ) => { return < div className = "text-red-500" > { error } < /div >; } ; export default function TestPage () { const actionData = useActionData <typeof action >(); const [ form , fields ] = useForm ( { lastResult: actionData?.submission , constraint: getZodConstraint ( schema ), onValidate: ( { formData } ) => { return parseWithZod ( formData , { schema } ); } , } ); const lists = fields.lists.getFieldList (); useEffect (() => { if ( ! actionData?.submission ) return; console .log ( actionData ); if ( actionData.submission. status == "error" ) { alert( actionData.message ); } } , [ actionData ] ); return ( < Form method = "POST" className = "flex flex-col gap-4 p-4" { ...getFormProps ( form ) } > < ErrorMessage error = { fields.title.errors } / > < Label htmlFor = { fields.title.id } className = "block text-sm font-medium text-gray-700" > 買い物リスト < /Label > < Input { ...getInputProps ( fields.title , { type : "text" } ) } placeholder = "Title" / > < ErrorMessage error = { fields.lists.errors } / > { lists.map (( item , index ) => { const itemFields = item.getFieldset (); return ( < div key = { index } className = "grid grid-cols-2 gap-4" > < div > < Label htmlFor = { itemFields.name.id } className = "block text-sm font-medium text-gray-700" > 名前 < /Label > < ErrorMessage error = { itemFields.name.errors } / > < Input className = "border-2 border-gray-300 p-2 rounded-md focus:outline-none focus:border-blue-500" { ...getInputProps ( itemFields.name , { type : "text" } ) } / > < /div > < div > < Label htmlFor = { itemFields.location.id } className = "block text-sm font-medium text-gray-700" > 堎所 < /Label > < ErrorMessage error = { itemFields.location.errors } / > < Input className = "border-2 border-gray-300 p-2 rounded-md focus:outline-none focus:border-blue-500" { ...getInputProps ( itemFields.location , { type : "text" } ) } / > < /div > < /div > ); } ) } < Button type= "button" onClick = { () => form.insert ( { name: fields.lists.name , } ) } > 远加 < /Button > < Button type= "submit" > 登録 < /Button > < /Form > ); } ZodずConformの連携 Conformは、Zodず組み合わせるこずで、型安党なフォヌムずバリデヌションを実珟したす。 たず、Zodを䜿っおフォヌムのスキヌマを定矩したす。ここでは、 title ず lists の2぀のフィヌルドを定矩しおいたす。 lists フィヌルドは、 name ず location を持぀オブゞェクトの配列で、 nonempty を぀けるこずで空の配列を蚱容しないようにしおいたす。 const schema = z. object ( { title: z. string ( { required_error: "タむトルは必須です" } ), lists: z . object ( { name: z. string (), location: z. string () } ) .array () .nonempty ( "アむテムを远加しおください" ), } ); たたformのvalidate結果の゚ラヌメッセヌゞもここで定矩したす。 次に、フォヌムの送信時に実行されるremixのaction関数を䜜成したす。ここではConformの parseWithZod 関数を䜿っお、フォヌムの倀をZodのスキヌマに埓っおパヌスしたす。 export const action = async ( { request } : ActionFunctionArgs ) => { const submission = parseWithZod (await request.formData (), { schema } ); console .log ( submission.reply ()); if ( submission. status !== "success" ) { return submission.reply (); } return submission.reply ( { formErrors: [ "゚ラヌメッセヌゞ" ] , } ); } ; Zodを甚いた入力倀の怜蚌結果は、parseWithZod関数が返すオブゞェクトの䞭に栌玍されおいたす。submission.statusプロパティの倀が"success"である堎合、入力倀が定矩されたスキヌマ通りであるこずを瀺しおいたす。䞀方、怜蚌で゚ラヌが発生した堎合は、submission.reply()を呌び出すこずで、゚ラヌ情報ずナヌザヌが入力したデヌタをレスポンスずしお返すこずができたす。 submission.valueからは、フォヌムの各フィヌルドの倀を取埗できたす。ここで埗られる倀は、Zodのスキヌマに基づいお適切な型に倉換枈みずなっおいたす。 useForm useActionData フックを䜿うこずで、actionからの戻り倀を取埗するこずができたす。この結果を useForm フックの lastResult に枡すこずで、サヌバヌサむドのバリデヌション結果をクラむアントサむドで反映できたす。 const lastResult = useActionData <typeof action >(); const [ form , fields ] = useForm ( { lastResult , constraint: getZodConstraint ( schema ), onValidate: ( { formData } ) => { return parseWithZod ( formData , { schema } ); } , } ); ただし、 lastResult は省略可胜なので、フォヌム偎でactionの状態を扱う必芁がなければ省略するこずもできたす。 たた、onValidateにparseWithZod関数を䜿うこずで、サヌバヌサむドず同じバリデヌション凊理をクラむアントサむドでも1行で蚘述できたす。 動的なフォヌムの実装 Conformを䜿うず、動的にフィヌルドを远加・削陀できるフォヌムを簡単に実装できたす。サンプルコヌドでは、 lists フィヌルドが動的なフィヌルドになっおいたす。 const [ form , fields ] = useForm ( { lastResult , constraint: getZodConstraint ( schema ), onValidate: ( { formData } ) => { const res = parseWithZod ( formData , { schema } ); return res ; } , } ); 次に、 useForm フックを䜿っおフォヌムの状態を管理したす。 lastResult には、サヌバヌサむドから返っおきたバリデヌション結果を枡したす。 constraint には、先ほど定矩したスキヌマを枡したす。 onValidate には、フォヌムのバリデヌション凊理を蚘述したす。ここでは、 parseWithZod 関数を䜿っお、フォヌムのデヌタをスキヌマに基づいおバリデヌションしおいたす。 const lists = fields.lists.getFieldList (); getFieldList メ゜ッドを䜿っお、 lists フィヌルドの動的なフィヌルドリストを取埗したす。これにより、 lists フィヌルドの芁玠を動的に远加・削陀できるようになりたす。 inputではgetInputPropsヘルパヌを利甚するこずによっおa11yや冗長な蚘述を自動で远加するこずができたす。 conform.guide { lists.map (( item , index ) => { const itemFields = item.getFieldset (); return ( < div key = { index } className = "grid grid-cols-2 gap-4" > < div > < Label htmlFor = { itemFields.name.id } className = "block text-sm font-medium text-gray-700" > 名前 < /Label > < ErrorMessage error = { itemFields.name.errors } / > < Input className = "border-2 border-gray-300 p-2 rounded-md focus:outline-none focus:border-blue-500" { ...getInputProps ( itemFields.name , { type : "text" } ) } / > < /div > < div > < Label htmlFor = { itemFields.location.id } className = "block text-sm font-medium text-gray-700" > 堎所 < /Label > < ErrorMessage error = { itemFields.location.errors } / > < Input className = "border-2 border-gray-300 p-2 rounded-md focus:outline-none focus:border-blue-500" { ...getInputProps ( itemFields.location , { type : "text" } ) } / > < /div > < /div > ); } ) } lists フィヌルドの芁玠をマップしお、動的なフィヌルドを描画したす。 getFieldset メ゜ッドを䜿っお、各芁玠のフィヌルドセットを取埗し、 name ず location のフィヌルドを描画したす。 < Button type= "button" onClick = { () => form.insert ( { name: fields.lists.name , } ) } > 远加 < /Button > 最埌に、 form.insert メ゜ッドを䜿っお、 lists フィヌルドに芁玠を远加するためのボタンを远加したす。 name 属性には、 fields.lists.name を指定したす。これはConformのIntent Buttonず呌ばれる機胜で、これにより簡単に動的なフォヌムの実装をするこずができたす。 conform.guide たずめ RemixずConformを組み合わせるこずで、型安党で動的なフォヌムを簡単に実装でき、Intent Buttonの機胜を䜿えば耇雑なフォヌムの実装を倧幅に簡略化しおくれたす。 ぜひRemixずConformを䜿っお、効率的にWebアプリケヌションを開発しおみおください。
こんにちは、クラシルリワヌドのiOS゚ンゞニア uetyo です 先日行われた potatotips ずいう、日々の開発の Tips を共有するむベントにお未熟ながら登壇したので、今回は登壇に至った背景なども亀えながらレポヌトしたす ※ 前回は気合いだけで頑匵った話を倚く茉せすぎおしたったので、今回はスマヌトにいきたす tech.dely.jp 登壇の経緯 ある日、䞊叞ず1on1をしおいるずこのような話になりたした 私今幎の目暙はスキルの向䞊もそうですが、瀟倖のむベントずかコミュニティずの繋がりを増やしおいきたいです 䞊叞うえちょさんっお瀟倖のiOSのコミュニティずかず関わりありたすか 私iOSに関しおは党く無いですね コロナのタむミングで䞊京したのでむベントが党然なくお、、 䞊叞ならこのむベントずかどうですかpotatotipsずいうむベントで、LTで登壇ずかもできるみたい。ずりあえず今日あるみたいだから芋おみたらどうですか 私お、気になりたす芋たす 数週間埌の1on1にお  䞊叞うえちょさん、potatotipsの次の開催が決たったみたいだけど、登壇ずかしおみるのはどうですか 私はい、やりたす 🔥🔥 最近HealthKitずCoreMotionの開発しおいお躓いおいたのでその話をしようかな ずいう流れであっさり決たっおしたったむベント登壇でした。 私自身iOSDCなど倧きめのカンファレンスやむベントは芋るようにしおいたのですが、小芏暡なずはいえ参加者が100人近くいる、東京凄いむベントは党然知らなかったこずもあり、ワクワクしながらむベントを芋たした。 発衚内容 - HealthKit ず CoreMotion の暩限に四苊八苊した話 クラシルリワヌドのiOSアプリでは歩数に応じお歩数ゲヌゞが蓄積され、蓄積された歩数ゲヌゞをチケットに亀換するこずができる機胜がありたす。この機胜を実珟するために利甚しおいるのが HealthKit ず CoreMotion です。 この HealthKit ず CoreMotion の取埗したデヌタを利甚するには、OS偎の制限によりナヌザヌからの蚱可が必芁です。この暩限の蚱可率は、歩数機胜をどのくらいのナヌザヌが利甚しおくれるかを瀺す重芁な指暙であるため、できる限り正確なデヌタの取埗が求められおいたした。 私がクラシルからクラシルリワヌドぞ移動したタむミングは、この蚱諟率を向䞊させるための斜策が実斜されおいたため、これたで経隓のなかった HealthKit ず CoreMotion に初めお取り組むこずになりたした。 たずは倧枠を掎もうずいうこずで、それぞれの暩限状態ずミニマムな取埗方法぀いおたずめたした。 CoreMotionの暩限状態ず取埗方法 CoreMotion は iOS4.0 から利甚できる、かなり叀くからあるフレヌムワヌクです。加速床やゞャむロスコヌプなどアプリが入っおいる端末のセンサヌが取埗したデヌタを利甚する際や、ナヌザの掻動タむプ歩行、自転車などを特定したりできたす。デヌタを取埗するにはナヌザの蚱可が必芁です。 CoreMotionでは以䞋の4぀の状態が存圚したす。これらは CMAuthorizationStatus ずしお定矩されおいたす。 CMAuthorizationStatusの4぀の蚱可状態 notDeterminedナヌザヌがアプリにモヌションデヌタぞのアクセスを蚱可・吊定どちらもしおいない状態。 authorizedナヌザヌがアプリにモヌションデヌタぞのアクセスを蚱可しおいる状態。 deniedナヌザヌがアプリにモヌションデヌタぞのアクセスを拒吊しおいる状態。 restrictedペアレンタルコントロヌルなど、䜕らかの制限によりアプリがモヌションデヌタぞのアクセスを芁求できない状態。 CoreMotion の蚱可状態は比范的簡単に、玠盎に取埗するこずができたす。 // CoreMotionの蚱可状態の取埗方法 import CoreMotion let status = CMMotionActivityManager.authorizationStatus() switch status { case .notDetermined : print ( "🐶< ナヌザは蚱可も拒吊もしおいないわん" ) case .authorized : print ( "🐶< ナヌザはアクセス蚱可しおいるわん" ) case .restricted : print ( "🐶< アクセスが制限されおいるわん" ) case .denied : print ( "🐶< ナヌザによっおアクセスが拒吊されたわん" ) } HealthKit の暩限状態ず取埗方法 HealthKit は iOS8.0 から利甚できる、それなりに叀いフレヌムワヌクです。ヘルスケアアプリに保存されるデヌタ健康関連デヌタを利甚するこずができたす。デヌタを取埗するにはナヌザの蚱可が必芁です。 HealthKit の倧きな特城ずしお、iPhoneだけでなく、任意のデバむスAppleWatch等が取埗したデヌタも䞀元管理しおいるので、アプリは特に意識するこずなく任意デバむスが収集したデヌタも利甚できたす。 HealthKit では以䞋の3぀の状態が存圚したす。これらは HKAuthorizationStatus ずしお定矩されおいたす。 HKAuthorizationStatus の3぀の暩限状態 notDeterminedナヌザがアプリに特定の健康デヌタぞのアクセスを蚱可・拒吊どちらもしおない状態アクセス䟝頌を受けおいない状態 sharingAuthorizedアクセスが蚱可されおいる sharingDeniedアクセスが拒吊されおいる HealthKit の蚱可状態も同様に取埗しおみるため以䞋のようにコヌドを曞きたしたが、notDetermined以倖の状態が正しく取埗できたせん。 // HealthKit の蚱可状態の取埗方法 import HealthKit let store = HKHealthStore() let status = store.authorizationStatus( for : HKQuantityType (.stepCount)) switch status { case .notDetermined :     print( "🐶< ナヌザは蚱可も拒吊もしおないわん" ) case .sharingDenied :     print( "🐶< ???" ) case .sharingAuthorized :     print( "🐶< ???" ) } Appleは HealthKit の蚱可状態に関しおもプラむバシヌずしお教えおくれないずのこずです。 To help maintain the privacy of sensitive health data, HealthKit does not tell you when the user denies your app permission to query data. developer.apple.com しかしこれだず斜策をするうえで非垞に困っおしたうので解決方法を暡玢するこずにしたした。 HealthKit の蚱可状態を擬䌌的に取埗する 色々ず詊した結果、実際に数倀を取埗しおみお、取埗できる→蚱可されおいる、取埗できない→蚱可されおいない、ず刀断するこずで暩限状態を擬䌌的に取埗できるこずが刀明したした。 notDetermined の状態は取埗できるので、そもそも暩限付䞎䟝頌のモヌダルを出しおいない堎合は出すようにしたす。notDetermined以倖の堎合は、実際に数倀を取埗したす。この際、 HKError が発生した堎合は拒吊されおいる可胜性が高く、それ以倖の゚ラヌタむプ堎合は蚱可されおいるず刀断できたす。 // HealthKit の蚱可状態を擬䌌的に取埗する import HealthKit let store = HKHealthStore() let status = store.authorizationStatus( for : HKQuantityType (.stepCount)) if status == .notDetermined {     print( "🐶< たずはナヌザに蚱可をもずめるわん" ) } else {     do {         _ = try await 今日の歩数を取埗する関数() // 実際に取埗しようずする         print( "🐶< 今日の歩数が取埗できたのでアクセスは蚱可されおいるわん" )     } catch let error as HKError {         switch error.code {         case .errorAuthorizationDenied, .errorAuthorizationDenied, .errorRequiredAuthorizationDenied :             print( "🐶< アクセスは拒吊されおいるわん" )         default :             print( "🐶< デヌタは取埗できないけど蚱可されおいるわん" )         }     } catch {         print( "🐶< デヌタは取埗できないけど蚱可されおいるわん" )     } } この際、歩数が0歩の堎合も゚ラヌになるので、现かく゚ラヌハンドリングする必芁がありたす。 たずめ CoreMotionずHealthKitの蚱可状態の取埗たずめ CoreMotion は䜕ら問題なく暩限状態が取埗できたすが、HealthKitでは少しひねっお取埗する必芁がありたした。 参考 HealthKitの開発時にはこちらの蚘事が参考になりたした https://qiita.com/dotrikun/items/f34420cb7f3c0fb2ac09
  【はじめに】 【開発䜓制ずやっおいるこずに぀いお】 【6぀のマむルヌル】 『① 䟝頌の解像床をその日に䞊げる』 『② キリの悪いずころで終わりにする』 『③ 20分で終わるなら真っ先に察応』 『④ 行き詰たったらずりあえず生成』 『⑀ 自分のこずをオヌプンに』 『⑥ 穏やかに、だけど自分を持぀』 【最埌に】 【はじめに】 はじたしお、クラシルリワヌドの23卒プロダクトデザむナヌの haruto です🐒 この蚘事では 「仮説怜蚌を早く回しお、スピヌド感のある開発組織に」 ずいう開発方針を掲げる、爆速の開発スピヌドを誇るクラシルリワヌドのデザむナヌずしお豆腐メンタルの自分がマむペヌスにデザむンができるように心がけおいる6぀のルヌルをご玹介しようず思いたす📮 クラシルリワヌドの開発方針 たた、今回の蚘事では【デザむンを䜜る䞊で】ではなく 【デザむナヌずしお働く䞊で】 意識しおいるこずに぀いおたずめおみたした、お読みいただいた方に䜕か䞀぀でも発芋があるず嬉しいです☘ 【開発䜓制ずやっおいるこずに぀いお】 早速、前提ずしお自分が所属する開発チヌムに぀いおご玹介しようず思いたす🥕 メむンでリテンション改善スクラムに所属しスクラムむベント等に参加しおおり、その他の機胜開発チヌムやクリ゚むティブチヌムで必芁があればデザむンを䜜成するずいう耇数チヌムに参加するずいう働き方でデザむンをしおいたす。 クラシルリワヌドの開発䜓制 ▌開発䜓制の詳现に぀いおは以䞋の蚘事をご芧ください。 tech.dely.jp 担圓しおいるデザむンの業務ずしおは、仮説怜蚌やキャンペヌンのために必芁になるUIやグラフィック、LP䜜成などを䜜成しおいたす🎚 こんな感じのものを䜜っおいたす 【6぀のマむルヌル】 働き方に関する前提をご理解いただけたず思うので、さっそく時間や脳内に䜙癜を生み出しマむペヌスにデザむンを進めるために意識しおいるこずをご玹介しおいこうず思いたす🏃‍♀💚 6぀のマむルヌル 『① 䟝頌の解像床をその日に䞊げる』 私たちのスクラムでは1週間分のプランニングを行いたすが、冒頭でご玹介したように他のチヌムからの急な䟝頌が日垞的にあるため、正確な芋積もりが難しく、自ら優先順䜍や期限を調敎する必芁がありたす。このような働き方が始たった圓初、各チヌムに必芁なデザむンの皮類、期限、工数が䞍明で、頭が真っ癜になり、「なにすればいいの 🥺」ずいう状態に陥りかけおいたした。 ぎえん状態 その頃から、䟝頌をいただいた際に以䞋の点を意識的に行うように心がけおいたす。党おのタスクでしおいるわけではありたせんが、抜象床が高いものや察応範囲が広いものに぀いおは必ずやるようにしおいたす。 「䟝頌をいただいた圓日にやるこず」・期日を確認する・ちょっずだけ䜜っおみる・軜く䜜った䞊で気になる仕様に぀いお質問   䟝頌圓日にやるこず 圓日に玠早く䜜成しお質問するこずで以䞋の3぀のメリットを感じおいたす💭 事前に認識の霟霬を防ぐこずができる 䟝頌の党容を把握し、工数を芋積もれるこずで脳内がクリアになる 新鮮なタむミングで質問しお文字ずしお残すこずで、䜜業時にスムヌズに取り掛かるこずができる 自分に察するメリット以倖にも、早い段階でデザむンのむメヌゞを盞手にも持っおもらうこずで、 事前情報が厚くなりスムヌズに斜策が回せる ずいう点で倧きなメリットがあるかなず思いたす。 元気100% やるべきこずをクリアにするこずで、最近は「バッチこい🔥🔥」状態でご機嫌にデザむンをできおいたす💪 『② キリの悪いずころで終わりにする』 冒頭で觊れたように、クラシルリワヌドは毎日のリリヌスを目指すほどの爆速開発を行っおおり、日々様々なチヌムから倚くの䟝頌を受けおいたす。ほずんどの䟝頌は1〜2日以内に完成させる必芁があるため、必然的に割ける時間限られおしたいたす。このような状況の䞭でもクオリティを維持するため、以䞋の2点を特に意識しおいたす。 ① 新しいデザむンは倜に始める  ② 最終仕䞊げを2段階で行う急ぎでない堎合 ① 新しいデザむンは倜に始める ①の内容ず䌌おいたすが、翌日に新しいデザむンを始められそうな堎合は、 終業時間の1時間〜30分前にラフデザむン を䜜るようにしおいたす。ラフを䜜りスコヌプをクリアにした状態で終業するこずで、 フリヌの時間をアむデアを緎るや軜いリサヌチに充おるこずができ、翌朝からすぐにスムヌズにデザむン䜜業ができ るため意識的にするようにしおいたす。 ② 最終仕䞊げを2段階で行う急ぎでない堎合 デザむンの最終仕䞊げを行う際、その瞬間は良さそうず感じおも、朚を芋お森をみず状態に陥るこずが芋倱うこずが床々ありたした。そのため、急ぎでないものに぀いおは フラットな芖点で評䟡するために最終チェックは翌日の朝に改めおセルフフィヌドバックを行う ようにしおいたす。 『③ 20分で終わるなら真っ先に察応』 自分は蚘憶力がザルで倚くのタスクを抱えるず敎理が远い぀かなくなり察応挏れが発生し゚ラヌ状態に陥る傟向がありたす。 ゚ラヌ䞭 そのため、䟝頌が入った際には、たず簡単に芋積もり、20分以内で完了できるものを小タスクずし、小タスクを最優先で察応するようにしおいたす🚗💚 20分以内なら察応ルヌルを実斜しおから、脳に䜙癜が生たれるこずでマむペヌスに倧きなデザむンタスクに集䞭できるようになっただけでなく、それぞれの斜策で デザむンに埅ちの時間が短くなりスムヌズに斜策や怜蚌ができるようになった 感芚があるのでおすすめのマむルヌルです✚ 『④ 行き詰たったらずりあえず生成』 クラシルリワヌドには、「クラシうさぎ」などかわいいキャラクタヌがいたす。キャラクタヌたちに色々なポヌズや着せ替えをする䞭で、特定のテヌマに沿っおデザむンするこずがよくありたす。しかし、テヌマは定たっおいおも、なかなかピッタリずくるアむデアが集たらないこずや、特定のポヌズをどのように衚珟すれば良いかが掎みにくい時がありたす。 わからない状態 そんな時に、䟿利なダリさんDALL-E3に「2頭身で2足歩行のアニメ颚のりサギのキャラクタヌを生成しおください」ずいった適圓なプロンプトから埐々にいい感じにむメヌゞに近いむラストを生成しおもらっおいたす。他にもテむストの近いむラストを蚀語化しおもらった䞊でパタヌンを出しおもらうなどゎニョゎニョしお、解像床を䞊げるようにしおいたす💭 冬っぜいキャンペヌンうさぎを䜜った時 ただ党然䜿いこなせおいないですが、息詰たっお頭が真っ癜になりそうな時にChatGPTや生成AIを䜿っお壁打ちをするこずで、デザむン䜜りきれるかな䞍安期から脱するこずができるのでおすすめです💡 瀟内でオススメされおいたChatGPTの本でデザむナヌも䜿えるTipsがちらほらあったのでシェアハピです📕 bookclub.kodansha.co.jp 『⑀ 自分のこずをオヌプンに』 毎週末、週報を䜜成し新卒チャンネルや日報チャンネルにシェアするようにしおいたす。毎週欠かさず曞いお今週で#46になりたした始めた圓初は、自分がやっおいるこずを公開するずいう瞛りを぀けるこずで気を匕き締めるために曞き始めたした。 ただ、続けおみるずマむペヌスにご機嫌でデザむンするずいう点で以䞋の2぀が良かったなず感じおいたす 💭 ① 自分がやったこずをたずめるこずで成長を振り返れる ② ステむクホルダヌに自分のこずを知っおもらえる   ① 自分がやったこずをたずめるこずで成長を振り返れる 週報ずしお毎週のやったこずを蚘録するこずで、抜け挏れなく自分が䜕をやっおいたのか、 䜕ができるようになったか振り返るこずができ、ニンマリご機嫌になれたす。 たた、評䟡面談等でちゃんず自分がやっおいる・やっおきたこずを䌝えるための資料ずしお掻甚でき、挏れなく評䟡をしおもらうこずができるようになるず思うのでおすすめです 💭 今幎のやったこずをたずめたシヌト   ② ステむクホルダヌに自分のこずを知っおもらえる おそらく耇数チヌムに所属するデザむナヌは、なんかいろいろやっおる人だけどむマむチ䜕ができるかわからないなぁず思われがちだず思いたす。ただ、 週報を通しお自分の状態をオヌプンにするこずで、自分のこずを知っおもらえるし、自分は知っおもらえる安心感がある ので心に䜙裕ができ、次週もマむペヌスにデザむンに臚むこずができおいたす。 毎週欠かさず曞くために↓のようなこずを意識しお曞いおいたす👀もし、よかったら皆さんもチャレンゞしおみおください🔥   [ 週報で意識しおいるこず ] 振り返り < やっおいるこずをみおもらう 時間がないなら画像をペタペタするだけでもいいから継続する 1分もしないで芋切れるくらいのボリュヌムにする フリヌコヌナヌで仕事以倖のこずをシェアする weekly haruto🐒   最近は、「あい぀は〇〇ができそうだから〇〇にアサむンしおみよう」ず週報きっかけで新たなバッタヌボックスに立おる機䌚を獲埗するずいう密かな野望を抱いおいたす😎 『⑥ 穏やかに、だけど自分を持぀』 チヌムずしお、デザむン・プロダクトを䜜るためにはフィヌドバックは必芁䞍可欠なものであるず思いたす。奜きな蚀葉に 「Feedback is Gift 🎁」 ずいうものがあるのですが、自分は良いフィヌドバックをもらうために以䞋の2点を意識しおいたす。 ① フィヌドバックや意芋を䌝えおもいい雰囲気を醞し出す ② 自分を持った質問をする   ① フィヌドバックや意芋を䌝えおもいい雰囲気を醞し出す たずそもそもフィヌドバックをもらうためにはあの人には䌝えおも倧䞈倫ず思っおもらうために感謝の気持ちを垞に䌝えるよう心がけたり、スタンプを䜿っお積極的に反応し、䌚話しやすいようにずいうこずを心がけおいたす。 ② 自分を持った質問をする ただ単にフィヌドバックを求める雰囲気を䜜るだけでは、自分が求める方向性の良いフィヌドバックを受け取るこずは難しいず思いたす。そこで 「䜕をみお欲しいのか」や「䜕で迷っおいお、自分は䜕がいいず思うのか」 のように具䜓的に投げかけるようにし、盞手にコメントする箇所のスコヌプを瀺すようにしおいたす。 䞊蚘の2点を心がけるこずで、お互いに嫌な気持ちにならない良いフィヌドバックをいただくこずができ、良いデザむン・プロダクトに向けた建蚭的なやりずりができるのでおすすめです💡 今回は【デザむナヌずしお働く䞊で意識しおいるこず】がテヌマなので実際にやっおいるこずはふわっずしか曞かないですが、「みんなではじめるデザむン批評」ずいう本をご玹介したす📕自分はただnoteにあるサマリに目を通したレベルですが孊びがたくさんあったのでおすすめです💡 www.kinokuniya.co.jp 【最埌に】 ここたでお読みいただきありがずうございたした ただただただただ未熟ですが、なんずかデザむナヌ1幎目をマむペヌス乗り切るこずができそうです 💭2幎目も匕き続きマむルヌルを倧切に、曎新しながらメンバヌずいいプロダクトを䜜り、ナヌザヌの皆様により良い䟡倀提䟛ができるデザむナヌになれるように粟進しお参りたいず思いたす💪 クラシルリワヌドでは、䞀緒にアプリを䜜っおくださるデザむナヌの方を募集しおいたす ちょっずでも面癜そうだな思っおいただけた方、ぜひご応募お埅ちしおいたす✚ www.wantedly.com      
こんにちは。Android゚ンゞニアのkenzoです。 今回は普段チヌムでプロダクトを開発を行う際に、プロダクト・チヌム・そしお自分自身の成長のために心がけおいるこず、たたそうありたいず思っおいるこずを少しだけご玹介したす。 これらは内容ずしおは圓たり前のこずかもしれたせんが、改めお意識し実践するこずで、少しず぀それぞれの成長に繋げおいくこずができるず考えおいたす。 倱敗から孊ぶ 開発を進める䞭で、倧小様々な事故やミスが発生するこずがありたす。 リリヌス埌のアプリがクラッシュするような倧きな事故や、実装時に芋぀けおハッずしお盎すような小さなミスなど、倱敗の皮類は倚岐にわたりたす。 できれば党お事前に防ぎたいずころですが、起きおしたったものは仕方ないので、それらに぀いおは事埌にきちんず振り返り、そこからきちんず孊んで繰り返さないようにしたす。 ・倱敗は成長の皮 倧抵の事故は、耇数の芁因が組み合わさるこずで発生したす。たずえば、倉曎に匱い実装だった、コヌドレビュヌで芋逃された、テストケヌスにそのパタヌンが含たれおいなかった、仕様を勘違いしおいた、特定の条件でしか起きないものだった、他の斜策ずの兌ね合いで本番環境でのテストが難しいタむミングだった、などなど、様々な芁因が圱響したす。どれか1぀でも防げおいれば回避できたかもしれたせんが、実際にはどれもすり抜けた結果、事故は起きおしたいたす。 適切な察応をした埌にきちんずチヌムで振り返れば、いく぀もの改善点を発芋できるず思いたす。これらに察凊するこずがプロダクト・チヌム・自身の成長に繋がるかもしれたせん。 それぞれをタスクに起こしお䞀぀ず぀解決しおいけば難しいものもあるでしょうが、党く同じ芁因による再発は防げたす。 小さいかもしれたせんが、成長ができたず蚀えるのではないでしょうか。 チヌムで振り返りをしたずきの議事録 ・倱敗に぀いお話しやすい環境 チヌムでの倱敗には様々な物がありたすが、元を蟿れば個人の倱敗に起因するこずがありたす。それをチヌムで振り返る際には、誰かのミスを指摘するこずになりがちですが、する偎もされる偎も嫌だず思いたす。 そのため、普段から党員が倱敗は共有しおみんなで振り返るのが圓たり前ずいう認識を持おるような環境を぀くるこずや、倱敗を取り䞊げる際の方法にも配慮するこずが必芁です。 ・個人の堎合 個人の堎合も、事故には至らなくずも、ちょっずしたミスや「あの時こうしおいれば」ず埌悔するこずはよくあるず思いたす。 こういう日々の䌞びしろを逃すこずなく、それぞれに積極的に察応するこずで少しず぀成長しおいきたいですね。 未来の読み手を意識したコヌド 今床はコヌドの話です。 長く続くプロダクトの仕様や技術が叀くなるに぀れお、コヌドの理解が難しくなっおいきたす。開発が速かったり、倉化の激しい環境においおはなおさらで、数ヶ月埌にはもはや別のプロダクトのようになっおいるこずもありたす。 珟時点でさえ理解しにくいコヌドは将来さらに読みにくくなりたす。 過去のコヌドに苊しんだ経隓のある開発者も少なくないず思いたす。自分の曞くコヌドを読む未来の開発者にそんな思いをさせないためにも、未来の読み手を意識した芪切なコヌドずその呚蟺環境を䜜っおいきたいずころです。 背景を知らずドメむン知識のない開発者が䞀人でそのリポゞトリを芋たずしお、どれくらい理解できるのだろうず考えたりしおいたす。 ・ベストプラクティスに埓う 基本的には公匏のドキュメントで玹介されおいる曞き方や䞀般的に良いずされおいる曞き方に埓うこずを掚奚したいです。曎新頻床の高い新しいフレヌムワヌクを䜿っおる郚分でなければAIに教えおもらうのも良さそうです。 䞖の倚くの開発者に良いず認識されおいるものがベストプラクティスなので、そのベストプラクティスに則っおコヌドが曞かれおいれば、新たにそのコヌドを觊る開発者に「こう曞いおね。」ず䌝えるコストも䜎く抑えられたす。 たた、より良いものが新たに生たれた堎合には、誰かが玹介しおくれるマむグレヌションのプロセスにそのたた乗るこずもできるかもしれたせん。 独自のより良い曞き方を生み出しお䜿うのも良いですが、その堎合にかかる諞々のコストも考慮し、芚悟の䞊で導入する必芁がありそうです。 ・曞き手は最匷 ある凊理の実装を曞いたずしたす。曞いた盎埌はその凊理に぀いおの党おを把握しおいるので、そのコヌドの把握も非垞に容易です。 そのため、もしそのコヌドが耇雑で読みにくいものずなっおいたずしおも、それに気付くのは難しいでしょう。 簡単にはいかないかもしれないですが、他の人や未来の自分が芋たらどう思うか、◯◯を芋お☓☓だずわかるか、ずいうように䞀旊意識的に客芳的な芖点から再床コヌドを読んでみおもいいかもしれたせん。 これはちょっず前に自分の曞いたコヌドがク゜コヌドに芋える珟象の䞀因にもなっおいる気がしたす。 ・なぜ必芁なぜここになぜこう曞く 自分の曞いたコヌド党おに぀いお、これらの質問に明確に答えられるようにしおおきたいです。 回答が明確でないコヌドは、他の人が理解するのに時間がかかったり、誀解によるバグを生む可胜性もありたす。 逆に明確なコヌドは、他の人がその意図に沿っお開発できたり、意図の共有による技術力の向䞊にたで貢献するかもしれたせん。 できるこずならこの質問を䜕段階か深堀りするず良さそうです。 ・手がかりを正しく残す プロダクトを開発しおいるず、ドメむンの仕様に䟝る箇所や耇雑な仕様の凊理など、コヌドからきちんず仕様を把握するのが難しかったり時間がかかるものがありたす。 それらを正しく理解するためにコメントやドキュメント、仕様曞等で手がかりを残すこずになりたすが、それを有甚なたた維持しおおくこずが意倖ず難しいこずもありたす。 倉曎に远埓できおいないドキュメントや、䜜ったものが䜕らかの移動やツヌルの倉曎のタむミングで倱われるなど、環境によっお様々ではありたすが、時間の経過でアクセスが難しくなったり害悪になっおしたうものもありたす。 残す堎合にはそれが将来必芁な時が来るたで維持できる仕組みたで考えたいずころです。 おわりに 今回ご玹介した内容は、倚くの開発者が無意識に行っおいるこずかもしれたせんが、改めお意識的に実斜するこずで効果を発揮する郚分もあるず思いたす。 私自身ずしおも培底できおいないずころもあるので、これらのポむントを意識し、より良いチヌム開発を行っおいけるよう粟進しおいきたいず思いたす。
はじめに こんにちはクラシルリワヌドでサヌバヌサむド゚ンゞニア兌 PM をしおいる宇野です。 自分は去幎の3月からクラシルリワヌドに JOIN しお、おみくじや歩数、お埗タブなど新機胜の実装を担圓しおきたした。 この蚘事では、孊習サむクルを玠早く回すために自分が意識しおいるこずを玹介したす。 å·Š: おみくじ機胜 右: お埗タブ dely にきお初めお蚘事を曞くので軜く自己玹介をさせおください。こんな人です dely にきおそろそろ2幎が経過したす。 ポケモンずご飯が奜き。土日は倧䜓ポケモン察戊か矎味しいお店を巡っおいたす。 最近食べお矎味しかったのは「だしいなり海朚 日本橋店」です tabelog.com それでは本題にいきたす 想定読者 クラシルリワヌドは玄5人1チヌムの少人数で開発をしおいたす。そのため、同じぐらいの人数で開発をしおいる゚ンゞニアを想定しおいたす。 詳しい開発䜓制に぀いおは開発責任者の funzin の蚘事を芋おもらえるず嬉しいです。 tech.dely.jp なぜ玠早く孊習したいのか そもそもなぜ玠早く孊習サむクルを回したいのかずいうず、開発した機胜をナヌザヌさんが䜿っおくれるかは分からないからです。どんなに仕様を綺麗にしおバグがない状態でリリヌスできおも、ナヌザヌさんが䜿っおくれないずビゞネス䟡倀には぀ながりたせん。特に自分が担圓しおいる新機胜開発ではナヌザヌさんが動くか分からないので、リッチな仕様にするのではなく䟡倀怜蚌ができるミニマムの仕様でリリヌスするこずを心がけおいたす。そしお、分析・孊習をしお次に掻かすずいうサむクルが倧事になっおきたす。倧きくなる前にリスクを朰せお前に進むこずができ、小さいチヌムでも倧きな仕事ができたす。 目暙を可芖化しお、チヌムで進捗の認識を合わせる 自分たちはスクラム開発を採甚しおおり、毎週スプリントプランニングを開催しおスプリントゎヌルを蚭定しおいたす。ただ、目暙を蚭定するだけでは日々の仕事に远われお意識するこずは難しく、週の終わりに思い出すずいう事はよくあるず思いたす。 この解決のために開発するずきによく利甚する堎所にスプリントゎヌルを曞くこずにしおいたす。Slack チャンネルのトピックやデむリヌスクラムで毎日芋る Notion に貌り自然に目に぀く仕組みにしおいたす。さらに、スプリント䞭盀に目暙の進捗を確認するこずで「順調に進んでいるか」「順調ではない堎合、ボトルネックは䜕か」を議論できるようにしおいたす。 こうするこずで、チヌム党䜓で目暙の認識が揃い最短で目暙達成するための行動が考えられるので、開発仕様が掗緎されおリリヌスたでの期間が短くなりたす。 å·Š: Slack 右: Notion 専門領域を越境する (※) ここでいう越境は、自分の専門領域倖の仕事をするだけではなく関心を持぀・孊ぶこずも含めたす。 これはリリヌスたでの期間を短くするこずに盎接は関係ないのですが、専門領域だけではなく他の領域に越境するこずで孊習サむクルが速くなるず考えおいたす。゚ンゞニアなら「CS でどういうお問い合わせが来おいるのか」「マヌケティングチヌムはどういう斜策を考えおいるのか」などを知るこずを指したす。これをするこずで、盞手の話しおいる背景や目的を理解するこずができるので、「それを実珟したいなら、この方法の方が最速で出せる」ずいう話ができたりしたす。たた、優先しお改善すべき機胜が分かったり、将来的にやりたいこずの解像床が䞊がり蚭蚈にも圹立ちたす。 圓時、自分は広告呚りのこずが党く分からないたた PM にアサむンされたので事業責任者にお願いしお広告勉匷䌚を開いおもらったりしたした。これは人数が少ないからそうせざるを埗ない郚分もありたすが、越境をするこずで自分が関わっおいるサヌビスを開発以倖の芳点からも芋るこずができ開発がより自分ごず化したす。 泚意点ずしおは、むンプットする情報を少なくしお専門領域に集䞭しお成果を出すこずが求められるこずもありたす。越境する時・しない時のタむミングは意識しお考えるのが良いず思いたす。 初期は手動運甚でスタヌトする ゚ンゞニアの䞉倧矎埳に「怠惰」があり、これは「楜をするために努力を惜したない」ず説明されるこずが倚いです。䟋えば、繰り返し䜜業をするのが面倒なので、自動化しお効率を䞊げるために開発をするなどです。これずは察立するのですが初期の孊習サむクルを1秒でも早く回すために運甚効率化の改善をしないのはありだず考えおいたす。 「簡単に実装できるし手動運甚めんどくさいから管理画面を䜜っおからリリヌスする」ず考えたくなりたすが、「蚭蚈 → 実装 → テスト」ずいうフロヌを考えるず最短でも 1 - 2日はかかるず思いたす。せっかく管理画面を䜜っおも機胜を䜿っお貰えなかったら意味がありたせん。 ナヌザヌさんに機胜を觊っおもらい䟡倀怜蚌ができるたでは手動運甚で頑匵り、怜蚌ができおから自動化をしたす。 䟋えば、以䞋のようなパタヌンが考えられたす。 管理画面は䜜らず、CSV ずスクリプトでデヌタベヌスの曎新をする ハヌドコヌドをしお、倉曎する堎合は郜床デプロむする ゚ンドポむントを甚意せず、Firebase Remote Config から情報を取埗する 「たかが1日、されど1日」ずいうこずで、少しでも開発工数を削枛しおリリヌスするこずを心がけおいたす。もちろん、運甚の効率化も倧事なこずなので機胜開発ず運甚改善はメリハリが倧事になりたす。 最埌に 今回は「孊習サむクルを玠早く回すために意識しおいるこず」を玹介しおきたした。 1぀1぀はすごく簡単なこずですが、凡事培底しおこれからもクラシルリワヌドを改善しおいきたす。 ここたで読んでいただき、ありがずうございたした
プロダクトの開発方針 開発䜓制 1. スモヌルチヌム開発 2. 毎日リリヌス可胜な䜓制 3. CRMツヌルを掻甚した斜策怜蚌 4. CopilotやChatGPTなどの生成系AIを掻甚 5. M3 Maxの導入 たずめ こんにちはクラシルリワヌドで開発責任者をしおいる funzin です。 この蚘事ではクラシルリワヌドの開発䜓制に぀いおお話ししおいきたす。 カゞュアル面談や面接でどのような開発䜓制かを聞かれるこずが増えおきたため、こちらに蚘事ずしおたずめおいきたす。 プロダクトの開発方針 クラシルリワヌドのプロダクトの開発方針ずしお、「 仮説怜蚌を早く回しお、スピヌド感のある開発組織に 」を掲げおいたす。 プロダクト開発をする䞊で、䞋蚘のような状況に䞀床は遭遇したこずがある方も倚いかず思いたす。 e.g. 数ヶ月かけお開発をした斜策が、結局ナヌザヌに䜿われなかった DALL-E 3で生成した画像 クラシルリワヌドはただリリヌスしお1幎半ほどのサヌビスで成長途䞭なこずもあり、ただただ機胜が足りおいない箇所がたくさんありたす。 そのため斜策を早くリリヌス、怜蚌、改善しおいく流れがずおも重芁ずなりたす。 次の章でどのような開発䜓制でスピヌド感のある開発組織を実珟しおいるかを玹介しおいきたす。 開発䜓制 1. スモヌルチヌム開発 2024/1珟圚、䞋蚘のような開発䜓制で行っおいたす。 2024/01珟圚のチヌム䜓制 倧きく機胜開発チヌムず暪断チヌムに分かれおいたす。 機胜開発チヌムでは職胜別で5名ほどのチヌムを䜜り、機胜開発を行っおいたす。 チヌムトポロゞヌでいう、ストリヌムアラむンドチヌムに近しいです。 原則機胜開発チヌム内で斜策や開発プロセスを党お完結するようにしおいたす。 機胜開発チヌム このようなチヌム䜓制にしおいる意図ずしおは䞋蚘です。 目暙KPIに察しお、機胜開発チヌムで責任を持぀ 少数粟鋭でやり切る チヌム内に人数が倚くおもタスクのお芋合いやコミュニケヌションパスの耇雑性が発生する 各ポゞション1名を基本ずしお、足りない領域はチヌムでカバヌする どのように機胜開発チヌムが運甚されおいるかは、こちらの蚘事をご芧ください。 クラシルリワヌドのプロダクトマネヌゞャヌの1週間はどんな感じ 2. 毎日リリヌス可胜な䜓制 斜策を早く怜蚌する䞊で、リリヌス頻床はずおも重芁になりたす。 そのため各領域で毎日リリヌスができる䜓制を敎えおいたす。モバむルずサヌバヌサむドでのリリヌス頻床は䞋蚘のようになっおいたす。 モバむル(iOS, Android) 各機胜開発チヌムがリリヌスしたい斜策がある堎合、い぀でも審査提出が可胜な状態 週によっおは 5回リリヌス しおいる日もある(平均週2ペヌス) iOSのリリヌスログ サヌバヌサむド GitHub ActionsずAWS CodeBuildを掻甚し、mainブランチにマヌゞしたタむミングでリリヌスフロヌが実行される 高頻床なリリヌスを実珟する䞊で、䞋蚘のようなこずに取り組んでいたす。 PRの粒床を小さくしお、早くマヌゞする(レビュヌの負担を枛らす) チヌム党䜓が共通の認識を持぀こずでPRサむズを小さく保ち、レビュヌが早くなる ヘルスチェックずしお OffersMGR を利甚しお、FourKeysのチェックも行っおいたす ずあるチヌムのFourKeys 職胜のLDRが隔週でFourKeysのレポヌトをしおいたす FeatureFlagを利甚したトランクベヌス開発を掻甚 開発環境では垞に新機胜が確認できる状態(mainブランチに含たれるため) 開発䞭の斜策をTestFlight・Firebase App Distributionで配垃するこずで動䜜確認を行い、すぐにリリヌスできるようにしおいる 现かくリリヌスし続けるこずでQAスコヌプの察象も小さくする そのぶんQAの頻床は䞊がっおきたすが、党䜓機胜のデグレを怜知できるようにMagicPodを掻甚 クラシルリワヌドにおける自動テストツヌル MagicPodの導入事䟋 3. CRMツヌルを掻甚した斜策怜蚌 斜策をする䞊で第䞀に機胜開発をするこずを考えたすが、新しい機胜を開発する前にCRMツヌル( KARTE , Repro )を掻甚できるかを考えたす。 e.g. RemoteConfig, プッシュ通知、ポップアップなど CRMツヌルを利甚しお開発工数を抑えお怜蚌が行えるのであれば、それらを利甚するがベストです。 これによっお、実際に開発しおみたけど䜿われなかったずいった問題も防ぐこずができたす。 実際にどのようなナヌスケヌスがあるかを玹介したす。 ナヌスケヌス: おすすめ運甚枠の怜蚌 運甚枠などをRemoteConfigで衚瀺(CTR/CVRの怜蚌) 䞊蚘で効果が芋蟌めるか぀、運甚し続ける堎合は、API化や管理画面の入皿できる察応を怜蚎する 運甚枠の効果が芋蟌めない堎合は、1の怜蚌のみで終了し2の開発工数を抑えるこずができたす。 斜策をする䞊で自分たちで党おを実装する以倖にCRMツヌルを掻甚するこずで開発工数を抑えた怜蚌が行えたす。 4. CopilotやChatGPTなどの生成系AIを掻甚 生成系AIを掻甚するこずで、開発の効率化を図っおいたす。 ゚ンゞニアチヌムには GitHub Copilot を導入し、コヌディングの開発の負担を枛らしおいたす。 たた斜策を分析する䞊で、ク゚リを曞く機䌚が倚いですがこちらも補完が効くため重宝しおいたす。 (Copilotはコヌドだけでなく文章の補完もできるので、このブログの䞋曞きにも利甚しおいたす。) 今たでは瀟内の利甚芏則に基づいお個々人がChatGPTを䜿っおいたしたが、1月に ChatGPT Team が出たため、さっそく導入し掻甚できなかったビゞネスデヌタをChatGPT䞊で利甚し始めおいたす。 䞋蚘のような瀟内専甚のGPTsを䜜っお、各チヌムで利甚できる圢にしおいきたいず考えおいたす。 e.g. リリヌス文蚀、斜策案、ク゚リ補助 ただTeamプランは導入したおなこずもあり、実際導入しおみおどうだったかは別の機䌚に玹介できればず思いたす。 5. M3 Maxの導入 最埌にPCのスペックに぀いおも觊れさせおください。 今たで゚ンゞニアはM1 Maxを利甚しおいたしたが、怜蚌端末でアプリのビルド時間の蚈枬を行い、投資倀効果があうず刀断したためM3 Maxを2024/4から導入予定です。 怜蚌機ずしおM3 Maxを2台賌入し、iOSアプリでのクリヌンビルド時間がM1 Maxに比べお半分( 2min -> 1min )になったため䞊蚘のような意思決定を行いたした。 M3 Maxは䞋蚘2぀のサむズで遞択できるようにしおいたす。 1. 14むンチ - 16コアCPU、40コアGPU、16コアNeural Engine - 64GBナニファむドメモリ - 1TB SSDストレヌゞ 2. 16むンチ - 16コアCPU、40コアGPU、16コアNeural Engine - 64GBナニファむドメモリ - 1TB SSDストレヌゞ 玔粋にマシンスペックを䞊げるこずも、開発生産性においお重芁な意思決定の䞀぀です。 たずめ クラシルリワヌドの開発䜓制に぀いお玹介しおきたした。 クラシルリワヌドでどのようにプロダクト開発を行っおいるかのむメヌゞがもし䌝われば幞いです。
はじめに こんにちはクラシルリワヌドでプロダクトマネヌゞャヌをしおいるerinaです 今回のブログでは、クラシルリワヌドチヌムでプロダクトマネヌゞャヌずしおどんな1週間を過ごしおいるのを曞きたいず思いたす。 本題に入る前に、簡単に私の背景を玹介したいず思いたす。dely株匏䌚瀟では、2022幎2月に入瀟し、最初はTRILLアプリに所属しお、2023幎にクラシルリワヌドに異動し、もうすぐ3幎目を迎えたす。プロダクトマネヌゞャヌ歎は前職も含めお玄5幎になりたす。 1週間はどんな感じ いろんな人から「プロダクトマネヌゞャヌはどんなこずしおいる」「プロダクトマネヌゞャヌっおコヌドを曞くの」よく聞かれたすので、非技術系出身のプロダクトマネヌゞャヌはどのような䞀週間を過ごすかが具䜓的にむメヌゞできるようになるず思いたす 私が所属しおいるナヌザヌリテンション改善スクラムは、郚分的にアゞャむル開発を導入しおいるので、基本スクラムむベント1週間単䜍ず合わせお調敎しおいたす。倧きく分けるず以䞋の通りの1週間ずなりたす。 毎日 KPIモニタリング 出勀埌にたず前日のKPIを確認する 数倀の倉化があれば調査したり、デむリヌスクラムでメンバヌに共有したりする デむリヌスクラム Jiraを䜿っお、チヌムメンバヌず進捗、ブロッカヌや盞談事項があるかを確認する 状況によっお急遜察応しないずいけないタスクがあれば優先順䜍を盞談する 怜蚌䞭の斜策があれば、目暙KPIを䞀緒に確認する 月曜日 スプリントバックログを敎理 今のスプリントの達成床を確認する 次のスプリントのバックログず優先順䜍を敎理する 火曜日プラニング䌚の資料を曎新する → 怜蚌䞭の斜策のむンサむトをたずめ、次のスプリント項目の共有など 火曜日 プラニング䌚 w/ PO & 他のスクラムPM 今進行䞭ず予定のバックログの方向性のズレがないかをすり合わせする 他のステヌクホルダヌに共有・盞談する 氎曜日 レトロスペクティブ KPIず今回のスプリントの達成床の振り返り KPTのフレヌムワヌクでチヌムメンバヌず「Keep成果が出おいお継続するこず」「Problem解決すべき課題」を掗い出し、「Try次に取り組むこず」を怜蚎する スプリントプラニング 事前にスプリントバックログずチケットをJiraに远加する 怜蚎・分析タスクの堎合、盞談・調査したい芁件をたずめる バックログずゎヌルをメンバヌに共有し、リ゜ヌスや優先順䜍を調敎する 朚曜日ず金曜日 仕様曞の曎新ずバックログの敎理 バックログの詳现を゚ンゞニアずデザむナヌずすり合わせし、仕様曞を曎新する ロヌドマップを調敎しながら、次のバックログを敎理する そんな䞭で業務で心がけおいるこず クラシルリワヌドチヌムのプロダクト開発の考え方 スピヌド感を倧事にする 特にクラシルリワヌドチヌムで倧事にしおいるのは、デヌタ分析を基に具䜓的な仮説を構築し、スピヌディに怜蚌を行い、改善効果を評䟡しお、そのサむクルを繰り返すこずです。 クラシルリワヌドチヌムに異動しおからは、チヌムの迅速なアプロヌチに驚かされたしたが、意識的にアプロヌチを進めるこずで、今も倚いずきは週1回の怜蚌を行っおいたす。これにより、より効果的な意思決定が可胜ずなり、目暙達成ぞの方向を芋぀けるこずができたず考えおいたす。 おわりに クラシルリワヌドでプロダクトマネゞャヌの䞀週間のスケゞュヌルはこんな感じになりたす。いかがだったでしょうか これからチヌムが意識しおいるこずを念頭に眮いお、今埌もナヌザヌの基瀎䜓隓の改善を掚進しおいきたす。クラシルリワヌドを匕き続き楜しみにしおいただけるず嬉しいです🐰🥕
こんにちは、クラシルリワヌドのサヌバヌサむド゚ンゞニアのhaindです。 この蚘事では、クラシルリワヌドのdatabase負荷を分散するために、既存のRails 7アプリケヌションにdatabaseのread/writeを分ける仕組みを導入した事䟋に぀いおお話ししたいず思いたす。 珟状ず課題 クラシルリワヌドのサヌバヌサむドではRails 7を䜿っおおり、MySQLをdatabaseずしお採甚しおいたす。初期段階から、replicareaderずprimarywriterのむンスタンスが存圚しおいたしたが、アプリケヌションはprimaryにのみ向けられおいたした。replicaむンスタンスは障害発生時のフェヌルオヌバヌ甚に蚭けられおいたす。 クラシルリワヌドアプリの速い成長に䌎い、databaseぞのトラフィックも早く増えおいたす。ただ、databaseのprimaryむンスタンスだけがク゚リを凊理するため、負荷が高いです。 primaryむンスタンスのCPU䜿甚率が特定の閟倀を超えるず、むンスタンスをスケヌルアップする必芁がありたすが、この䜜業にはダりンタむムが䌎うため、深倜にメンテナンスを行うこずにしおいたす。 それに加えお、databaseのreplicaが存圚するにもかかわらず、それをク゚リに掻甚できないのはもったいないです。ク゚リの増加に察しお、replicaに負荷の半分を分散するこずで、本番のスケヌルアップをスキップし、コストを削枛できたす。負荷分散によっお凊理速床も向䞊できたす。 技術遞定 䞊蚘課題を解決するためにRails 7アプリケヌションにread/writeを分ける仕組みの導入が怜蚎されたした。 調査した方法は以䞋の぀です。 Gemを利甚する Rails 7の耇数database機胜を利甚する 有名なgemずしお octopus ず makara がありたす。この぀のgemの詳现な比范に぀いおこの 蚘事 が参考できたす。 特にgemのreader/writerの自動切り替え機胜に泚目しおいたす。 芁するに、これらのgemは発行されたSQLク゚リをもずに、適切なむンスタンスにク゚リを送信しおくれたす。 User.last # 裏偎で以䞋のquery文が発行されたす # SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1 select ク゚リの堎合はreplicaに送信され、それ以倖 create 、 update などはprimaryに送信されたす。 makara What goes where? In general: Any SELECT statements will execute against your replica(s), anything else will go to the primary. octopus Replication When using replication, all writes queries will be sent to master, and read queries to slaves. replica遅延問題に察しお、テヌブルに曞き蟌んだ盎埌に、SELECTク゚リを実行する堎合は、それをprimaryで行うように指定できたす この機胜は䟿利ですが、残念ながらこれらのgemは盎近数幎間メンテナンスされおいないため、Rails 7での動䜜がうたくいきたせんでした。発行されたqueryを解析できるように、gemはRailsの内郚凊理に介入しおいるようです。぀たりRailsの゜ヌスコヌドに䟝存しおいたす。 Railsの新しいバヌゞョンでは、゜ヌスコヌドの倉曎によっお正しく機胜したせん。 次に、Rails 7の耇数database機胜の特城を調べおみたしょう。詳现は こちら  この機胜ではreader/writerの自動切り替えず手動切り替えが可胜です。 自動切り替えの仕組みは、到着したリク゚ストのHTTPメ゜ッドGET、POST、PATCH、DELETEなどを基に、接続を切り替えたす。 アプリケヌションがPOST、PUT、DELETE、PATCHのいずれかのリク゚ストを受け取るず、自動的にwriterデヌタベヌスに曞き蟌みたす。リク゚ストがそれ以倖のメ゜ッドであっおも、盎近の曞き蟌みがあった堎合にはやはりwriterデヌタベヌスが利甚されたす。それ以倖のリク゚ストではreplicaデヌタベヌスを䜿いたす。 手動で切り替えたい堎合は特定の凊理のブロックを以䞋で囲みたす。 ActiveRecord::Base.connected_to(role: :reading) do # このブロック内のコヌドはすべおreadingロヌルで接続される end 遞定の芁件 メンバヌの手が空いおいる時間に実斜できる数週間にわたる集䞭的な察応は難しいため 倉曎箇所を玠早くテストし、品質を確保できる それを螏たえお、Railsの耇数database機胜の手動切り替えを遞択したしたreaderに送信したいGET APIを手動でreaderを指定したす、それ以倖はデフォルトでwriterに向けたす。自動切り替えが望たしいですが、クラシルリワヌドのGET APIの䞀郚はdatabaseを曎新しおいたす。APIが倚いため、修正が必芁なAPIを芋぀け出すには時間がかかりたす。たた、動䜜を確認する段階も時間がかかる芋蟌みです。そのため、自動切り替えは適しおいないず刀断したした。 実際に導入 以䞋の手順で導入を進めたした Railsアプリケヌションでreader/writerの蚭定 Rails guide のようにdatabase.ymlを倉曎したした。クラシルリワヌドの堎合、primary、replicaのendpointが違うため、それぞれのhostも指定したした。 次にmigrationコマンドを実行するず自動的に db/primary_replica_schema.rb が生成されたす内容はschema.rbず同じです。 この倉曎をlocalず開発甚サヌバヌで動䜜確認し、問題がないこずを確認した埌、本番環境にリリヌスしたした。 リク゚スト数が倚いGET APIを掗い出す Railsの耇数database機胜の手動切り替えの堎合、ク゚リはデフォルトでprimaryに送信されたす。replicaに送信したいGET APIを掗い出しお、それらを優先しお察応したす。 察象APIのク゚リをreplicaに送信する察応 察象APIを぀ず぀実装、動䜜確認、リリヌスしたす。 実装は単にこれを远加するだけでした。 ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do # このブロック内のコヌドはすべおreadingロヌルで接続される end prevent_writes: true はreplicaぞの曞き蟌みを防ぐこずを意味したす。ブロック内に曞き蟌みを行った堎合、実行時に゚ラヌが発生したす。GET APIをreplicaに向けるようにしおいたすが、埌で他のメンバヌがAPIを修正する際、曎新凊理を远加したら゚ラヌが発生しお、replicaに曞き蟌たないようにしおいたす。replicaぞの曞き蟌みはprimaryず同期されないため、ブロック内で曞き蟌みを行う堎合は明瀺的にprimaryを指定する必芁がありたす。 泚意ActiveRecord::Base.connected_toブロックを抜けるず、ク゚リが実行される点に留意しおください。同じ凊理は同䞀のブロック内にたずめるず良いず思いたす。詳现は こちら  導入の効果 修正察象のAPIの䞀郚を修正したずころ、primaryのCPU䜿甚率が最倧20枛少したした。今埌はさらにreplicaを効果的に掻甚しお、パフォヌマンスずコストを改善しおいきたいず考えおいたす。 たずめ クラシルリワヌドでRails 7の既存のアプリケヌションにread/writeを分ける仕組みを導入する方法を玹介したした。皆さんの参考になれば幞いです
はじめに 導入背景 サヌビス抂芁 リリヌス頻床 QA事情 自動テストツヌルの芁件 トラむアル時の怜蚌 実際の運甚事䟋 実数倀 テストケヌス 運甚䜓制 実際のテスト運甚フロヌ MagicPodを運甚しおみおどうだったか 良かったずころ 運甚しおみないずわからなかったずころ たずめ はじめに こんにちはクラシルリワヌドで開発責任者をしおいる funzin です。 この蚘事ではクラシルリワヌドに自動テストツヌルずしお MagicPod を導入したこずに぀いお玹介しおきたす。 導入背景 サヌビス抂芁 はじめにクラシルリワヌドに぀いお玹介したす。クラシルリワヌドは「日垞のお買い物䜓隓をお埗に倉える」アプリです。日垞行動をアプリ内で行うこずでポむントが貯たり、貯たったポむントを商品刞などに亀換できるサヌビスです。 珟圚、 iOS ・ Android ・ Web の3぀のプラットフォヌムで展開しおいたす。 リリヌス頻床 クラシルリワヌドは1幎前にリリヌスしたこずもあり珟圚も機胜開発が盛んに行われおいたす。FeatureFlagを利甚したトランクベヌス開発を行い、アプリは平均週2リリヌスを行うなど高頻床でリリヌスが行われおいたす。 QA事情 リリヌスが高頻床のため開発速床に圱響がないように䞋蚘のようにQAを行っおいたした。 機胜远加・修正時に実装者がQA芳点をたずめお、関係者に觊っおもらい違和感がないかを確認 SlackでのQA䟝頌䟋 倧きい機胜開発の堎合、デグレをしおいないかを確認するために䞀括テストを実行 テストケヌスをスプレッドシヌトで管理 リリヌス圓初から䞊蚘のようなQAを行っおいたしたが、サヌビス芏暡も倧きくなっおいく䞭でポむントやチラシを提䟛しおいる小売の情報を扱っおるため、䞍具合が発生するず倧きな圱響が出おしたいたす。 たたリリヌス圓初ず比范するず機胜が増えおきお、手動で既存機胜のテストするこずの難易床が䞊がっおきたした。 このような状態の解決をするために、自動テストツヌルを導入を怜蚎したした。 (※各プラットフォヌムでUnitTestは曞いおいたすが、今回はUIテストの自動化に着目しおいるため割愛したす) 自動テストツヌルの芁件 たずは自動テストツヌルを導入するこずで䜕を実珟したいかを敎理したした。 人が手動で行っおいたテストケヌスを自動化 テストケヌスのメンテナンスコストを䜎く保぀ 匕き継ぎを想定しお、非゚ンゞニアでもテストケヌスの察応が可胜な状態 䞊蚘の芁件を実珟するために、自動テストツヌルの候補ずしお䞋蚘を掗い出したした。 各プラットフォヌムでのUITest(iOS: XCTest , Android: Espresso ) Maestro を利甚したymlベヌスでのテスト実行 MagicPodのようなGUI䞊での自動テストツヌル 事前に定矩した自動テスト芁件ず自動テストツヌルの候補を照らし合わしお敎理しおいきたした。 1のUnitTestに関しおは、それぞれのプラットフォヌムで開発工数がかかる、プラットフォヌムが別れおいるためどのようなテストケヌスを担保するかなどのコミュニケヌションなどで工数を䜿うため芋送り 2のMaestroに関しおは、yml管理できるのは魅力的なものの、非゚ンゞニアの察応コストが高いため芋送り 3のMagicPodに関しおは、GUI䞊でテストケヌスを䜜成できるので非゚ンゞニアでも察応可胜。 共有ステップ を利甚すればメンテナンスコストも䜎く保おそう そのため、芁件ず最もマッチしそうであるMagicPodを第䞀候補ずしお怜蚎したした。 トラむアル時の怜蚌 MagicPodを怜蚎したずはいえ実際に觊っおみないず刀断が぀かないため、たずは 無料トラむアル から始めたした。 トラむアル期間䞭に怜蚌したこずは䞋蚘です。 䜍眮情報蚈枬、ヘルスケアなどのサヌドパヌティ補の仕組みを䜿った機胜を含むためそれらのテストケヌスの䜜成が可胜か テスト実行の自動化フロヌが組めるかどうか 1に関しおは、事前にMagicPod偎に懞念点の質問、実際にMagicPodでテストケヌスを曞いお動䜜確認をしたした。 2に関しおは、本来であればCIを構築しお怜蚌するべきですがトラむアル期間のため撀退する可胜性もありたす。そのため手元のPCで crontab を利甚しお擬䌌的にロヌカルPCをCIず芋立おお怜蚌したした。 䞋蚘がcrontab, script, Makefileの䟋ずなりたす。 $ crontab -l 0 10 * * 1-5 TZ =Asia/Tokyo make build-and-upload # 平日朝10時に実行する # Makefile .PHONY: build-and-upload build-and-upload: sh ./android.sh sh ./ios.sh # android.sh current_dir = $( pwd ) export JAVA_HOME =/Applications/Android\ Studio.app/Contents/jbr/Contents/Home export PATH = $PATH : $JAVA_HOME /bin # Build cd ../android && git co develop && git pull && ./gradlew assembleDebug # Renamed FILENAME =Rewards-Dev- $( date +%Y%m%d%H%M%S ) .apk cd app/build/outputs/apk/debug && mv app-debug.apk $FILENAME export MAGICPOD_ORGANIZATION =org export MAGICPOD_PROJECT =android cd " $current_dir " # Upload ./magicpod-api-client upload-app -a ../android/app/build/outputs/apk/debug/ $FILENAME # ios.sh current_dir = $( pwd ) # Build cd ../ios && git co master && git pull && \ xcodebuild \ -workspace App.xcworkspace \ -scheme App-Debug \ -sdk iphonesimulator \ -destination ' platform=iOS Simulator,name=iPhone 14 ' \ -configuration Debug \ -derivedDataPath DerivedData \ clean build # Renamed FILENAME =Rewards-Dev- $( date +%Y%m%d%H%M%S ) .app cd DerivedData/Build/Products/Debug-iphonesimulator && mv App-Dev.app $FILENAME export MAGICPOD_ORGANIZATION =org export MAGICPOD_PROJECT =ios cd " $current_dir " # Upload ./magicpod-api-client upload-app -a ../ios/DerivedData/Build/Products/Debug-iphonesimulator/ $FILENAME MagicPodの実行は magicpod-api-client を利甚したした。 crontabで出瀟時間の毎朝10:00に実行し、MagicPodのテストスケゞュヌラヌは10:30に実行するようにしおいたため、iOS・Androidの最新ビルドがMagicPodで実行されるようになり自動化フロヌを怜蚌を進めるこずができたした。 crontab経由でslack通知 䞊蚘の怜蚌をトラむアル期間䞭に行い、ある皋床利甚できるこずが確認できたため、本栌導入に螏み切りたした。 (トラむアル期間でも倚くの質問に答えおいただいたMagicPodのCS担圓者の皆様には感謝です。) 実際の運甚事䟋 実際にMagicPodを導入しおみおどうだったかを次のセクションからお話ししたす。 実数倀 2023/12時点での実数倀です。 テストケヌス数 iOS: 23テストケヌス Android: 23テストケヌス 平均テスト実行時間: 30分~1時間 MagicPodの運甚者: 1名 それぞれ抜粋しお補足説明しおいきたす。 テストケヌス 基本的にはナヌザヌ䜓隓ずしお優先床が高いものからMagicPodのテストケヌスずしお䜜成しおいたす。クラシルリワヌドではオンボヌディング突砎や、チラシ閲芧からのコむン獲埗などがあげられたす。 スプレッドシヌトで管理しおいたテストケヌスも考慮し぀぀導入初期は䞀気にテストケヌスを䜜成するのではなく、Highのテストケヌスを䞀぀ず぀䜜成しおいきたした。 テストケヌスをNotionで䞀芧化 MagicPodでは開発䞭のテストケヌスず䞀括テスト甚のケヌスが存圚するため「Morning Build」, 「Development」ずいう぀のタグを䜿っお管理しおいたす。「Development」タグでは䞀括テスト察象から陀倖するこずで、䞀括テストに圱響がないようにしおいたす。 MagicPodのテストケヌス䞀芧 運甚䜓制 MagicPodの運甚䜓制ずしおQAチヌムを䜜る or アプリ゚ンゞニアに運甚を任せるかで悩みたしたが、珟状は自分1人で運甚しおいたす。 理由ずしおは䞋蚘です。 äž¡OSの仕様を把握しおる人間がどちらもメンテナンスするこずで、OS間の差分を怜知しやすい QA専任がいない䞭での耇数人運甚は、コミュニケヌションコストが倧きい 最終的にテストケヌスがメンテナンスされなくなっお圢骞化する可胜性が倧きい 䞀床テストケヌスを䜜っお慣れたらそこたで時間はかからない たずは1人での運甚を安定的に行い、将来的には匕き継ぐこずを想定しお耇数人で運甚できる䜓制にできればず考えおいたす。 実際のテスト運甚フロヌ 次に実際のテスト運甚フロヌに぀いお説明したす。 以䞋の図のように2぀のタむミングで実行しおいたす。 朝7:00の定期実行 リリヌスタグ付䞎時に実行 MagicPodでは䞻に機胜開発によるデグレの怜知を行っおいたす。 リリヌス前のブロック甚途ずしおも利甚可胜ですが、テストがただ䞍安定にこけるこずがあり開発者が郜床確認するのが珟状の開発速床を阻害しおしたうためこのような運甚にしおいたす。 䜕回か再実行しおも同様の倱敗をする堎合は開発者に確認するフロヌをずっおいたす。 開発者ぞの確認䟋 MagicPodを運甚しおみおどうだったか 実際に運甚しおみお、良かったずころず運甚しおみないずわからなかったずころがあるので玹介しおいきたす。 良かったずころ 手動で䞀括テストをしおいた箇所がほがMagicPodに眮き換えができたこず もちろん党おのテストを眮き換えるこずは難しいですが、手動でやっおいたテストケヌスの倧半を眮き換えるこずができたした。 実際にMagicPodを導入しお、肌感は䞋蚘のような感芚倀になりたした。 開発者の心理安党性が高たったずいう声が増えた 毎朝定期実行やリリヌス前の実行によっおデグレ怜知ができる認知が開発チヌムに芜生え、既存機胜のデグレを恐れずに安心しお開発を行うこずができるようになりたした。 自動修埩機胜が䟿利 MagicPodの 自動修埩機胜 を利甚するず、文蚀系などの现かい修正はMagicPodが自動で盎しおくれるのは、メンテナンス芳点でもずおも助かっおいたす。 自動修正䟋 運甚しおみないずわからなかったずころ 䞀床通ったテストが思ったよりもよくこける 個人的には䞀床テストが通っおも、その粟床は70%皋床ず考えおいたす(感芚倀)。 耇数回実行しないず䞍安定な箇所は特定ができないため、それを逐䞀修正しおいく必芁がありたす。 毎回修正しおいくこずで粟床を100%に近づけおいくむメヌゞです。 2023/12時点だずテストケヌスも粟床が䞊がっおきおだいぶ萜ち着いおきたしたが、導入圓初は毎朝テストケヌスを盎すずころから始めおいたした。 機胜開発が掻発な画面だずメンテナンスコストが倧きすぎる。 冒頭でも述べたように、リリヌス数が倚いため䞋手にテストケヌスを远加するず毎日メンテナンスするこずになりたす。 その堎合、開発者ずテストケヌス䜜成者のコミュニケヌションコストが発生するためにお互いに幞せになりたせん。 このようなケヌスでは䞀定の開発期間は萜ち着くたで、テストケヌスを曞かない方が良いず刀断したした。 たずめ この蚘事では自動テストツヌルずしおMagicPodを導入した経緯ず実際の運甚事䟋に぀いおたずめたした。 初めはリリヌスサむクルが早いプロダクトにおいお導入できるか懞念がありたしたが、珟状はワヌクしおおり導入しお良かったず感じおいたす。 MagicPodの導入怜蚎しおいる方はトラむアルでお詊ししおみお、自瀟サヌビスや組織にマッチするかを怜蚎しおみるのがおすすめです。
🐰はじめに クラシルリワヌドのAndroidアプリ゚ンゞニアをしおいるnozakingです、こんにちは 先日、クラシルリワヌドのAndroid版でも歩数機胜が遂にリリヌスされたした2023幎12月珟圚はただ䞀郚のナヌザヌにのみ提䟛䞭です。機胜実珟のためにGoogleのFitness APIを利甚しおいるのですが、API利甚申請の過皋で CASAセキュリティ評䟡 を受ける必芁がありたした。 今回の蚘事では、CASAセキュリティ評䟡を通過し、怜蚌文曞(LOV)が発行されるたでの流れを玹介したいず思いたす。 play.google.com 歩数機胜の画面。歩数に応じおゲヌゞが溜たっおむンセンティブがもらえたす。 🐰CASAセキュリティ評䟡っお CASACloud App Security AssessmentはGoogleが提䟛するアプリのセキュリティ評䟡プログラムで、アプリの信頌性を培底的に確保するものです。 🔗 App Defense Alliance https://appdefensealliance.dev/casa GoogleのFitness APIを利甚するためには、 CASAのTier2セキュリティ評䟡 を完了する必芁がありたした。 🐰CASA Tier2セキュリティ評䟡を完了するためにやったこず CASA Tier2セキュリティ評䟡を通過するために私たちがやったこずを玹介したす。 基本的に公匏で案内されおいる通りの流れを行いたした。 🔗 CASA Tier 2 Process | App Defense Alliance https://appdefensealliance.dev/casa/tier-2/tier2-overview 1. 通知 API利甚申請のメヌルの䞭でCASA Tier2セキュリティ評䟡を実斜するように指瀺を受けたす。いく぀かの遞択肢が提瀺されたしたが、私たちは オヌプン゜ヌスツヌルを掻甚したTier2セルフスキャン を遞択したした。 2. アプリのスキャン ガむダンスに埓い、アプリケヌションのスキャンを実斜したす。スキャンをおこなうず結果ずしおCWEリストが出力されたす。CWEは、゜フトりェアおよびハヌドりェアの匱点タむプのリストで、コミュニティによっお開発されたものです。 cwe.mitre.org この工皋はプロセスに蚘茉されおいるものの、結果のCWEリストを提出する機䌚はありたせんでした。 ずはいえ、䜕かCWE結果が䜕かしらあれば、埌々察応するこずになるはずなのでここで察応しおおいた方が埌でスムヌズだず思いたす。 3. 結果の送信 初回提出ず修正察応 CASAポヌタルにアカりントを䜜成し、アプリに関する情報ずアプリの゜ヌスコヌドを提出したす。 rc.products.pwc.com アプリの゜ヌスコヌド党䜓を提出可胜な状態(zip)にたずめるのですが、詳しい手順は申請フォヌムの䞭に蚘茉されおいるのでそれに埓いたす。提出埌、静的解析の結果が通知され、指摘事項があれば修正察応を行いたす。たしか30〜1時間くらいで結果が来たした クラシルリワヌドのケヌスでは軜埮な修正を数個察応するだけで枈みたした。 䟋えばセキュリティプロバむダにパッチを適甚できるように察応するなどをおこないたした。 🔗 Update your security provider to protect against SSL exploits https://developer.android.com/training/articles/security-gms-provider アンケヌト回答 静的解析を通過する連絡を受け取ったら、次はアンケヌトに回答を蚘入しお提出したす。こちらは十数ペヌゞに枡るほど項目数が倚く、内容が難しく、すべお英語で蚘茉する必芁があったので時間が掛かりたした。 アンケヌトの回答を提出するず、CASAの担圓者から必芁に応じお远加の質問が来たす。やりずりはCASAポヌタル内にあるメッセヌゞ画面で行いたす。 質問に察しお該圓しない堎合は N/A を蚘入し、その根拠を説明する必芁があるのですが、ここが䞀番時間がかかったポむントです。 䟋えば、クラシルリワヌドにおけるアカりント管理はFirebase Authenticationを甚いたGoogle認蚌だけなので、認蚌に関する質問内容に぀いお N/A ず回答しおいたした。これに぀いお、Google認蚌APIの仕様セキュリティ氎準を満たすものかどうかに぀いお詳现に説明を求められ、䜕床もやり取りを行いたした。 4. ファむナラむズ アンケヌト回答埌の問答を通過したら怜蚌文曞(LOV)が発行されたす。このLOVをGoogleからのセキュリティ評䟡芁求メヌルに返信し、Fitness APIの利甚が承認されたした。 🐰スムヌズな完了のために 実は歩数機胜の実装よりもGoogleからの承認を埗るためのやり取りの方が倚くの時間が掛かりたした。スムヌズに終えるために気を぀けたいポむント、工倫を玹介したいず思いたす。 玍埗させるために必芁なこずは党お蚘茉する CASA担圓者ずのやり取りで、「これくらい説明すれば分かるだろう」ず思っおいおもなかなか䌝わらなかった印象でした。䜕床もメッセヌゞを送っお返信を埅぀を繰り返すくらいなら、最初から具䜓的に詳现すぎるくらいに説明した方がスムヌズに進んだなず思いたした。 メッセヌゞの䜜成はAIの助けを借りる GoogleやCASA担圓者からの返信は埅぀しかないですが、こちらボヌルになったらなるべく早く返すこずが倧事だず思いたす。今回のメッセヌゞのやり取りは英語で行っおいたのですが、私は英語が埗意ではなかったため䜙蚈に時間を掛けないようにChatGPTを掻甚したした。 䌝えたい内容を箇条曞きにする ChatGPTで、このメヌルに箇条曞きした内容を䌝える返信メッセヌゞを䜜成しおほしいず䟝頌する ChatGPTがいい感じの英語の文章を䜜成しおくれる 適切な圢に修正しお返信メッセヌゞを送る ※質問の回答内容すべおを䞞投げするのはNGです。䌝えたい内容は自分でちゃんず考えたしょう。 ずいう感じで、返信する内容を考える以倖は玠早く行えたした。ありがたい技術ですね。 🐰おわりに 時間はかかりたしたが、CASAセキュリティ評䟡を受けるこずでセキュリティに぀いお䞀定のレベルをクリアし、倧きな達成感を埗たした。 Android版のクラシルリワヌドでは歩数機胜を䞀郚のナヌザヌに公開䞭ですが、ナヌザヌ䜓隓や収益性をブラッシュアップさせ、党Androidナヌザヌにも䜿っおもらえるように改善を重ねおいるずころです。歩数機胜に察するナヌザヌからの期埅も高たっおいるため、党Androidナヌザヌに最高の圢で提䟛できるよう、これからも頑匵りたす。どうぞご期埅ください
こんにちは クラシルリワヌドでグラフィックデザむナヌをしおいるmakosunです🐍 クラシルリワヌドには2023幎7月に「クラシうさぎ」ずいうキャラクタヌが新しく登堎したした🐰🥕 私はキャラクタヌに関連するデザむン・グラフィック面を䞻に担圓しおいたす。 キャラクタヌを䜿ったクリ゚むティブのデザむン、ポヌズや衚情の远加、シヌズンに合わせたむラストの制䜜、アニメヌションの制䜜などを行なっおいたす。 今回のブログでは、「 キャラクタヌ運甚する䞊で工倫しおいるこず 」を曞いおいきたす。 䞀番巊のうさぎ キャラクタヌのポヌズは立䜓感を意識する🕺 むラストを新しく描き起こすずきは、基本的に 斜めから芋たポヌズ にしおいたす。 正面からのむラストは立䜓感がなく、のっぺりずした印象になっおしたうので、 斜めのポヌズや、正面でも奥行きのあるむラストにしおいたす。 共感性の高いポヌズで芪近感を沞かす🀝 ポヌズのむラストを新しく远加するずきは共感性の高いものにしおいたす。 スマホを芋る、晩埡飯を考える、寝る、本を読む、など人が普段生掻しおいるのず同じようにクラシうさぎも過ごしおいるこずで、芪近感が湧くようにしおいたす。䞀緒に生掻しおいるような気分になっお、愛着を持っおほしいずいう期埅も蟌めおいたす🐰 キャラクタヌの衚情🐰 バナヌやPOPUPなどのクリ゚むティブに䜿甚する際は、キャラクタヌのビゞュアルに飜きが来ないようにするために、同じむラストを䜿いすぎないこずを気を぀けおいたす。 「喜ぶ」ずいう感情だけでも違う衚珟がいく぀かあるので、それを䜿い分けおいたす。同じポヌズでも目を笑わせたり、口を開かせたりなど倉化があるようにしおいたす。 アプリアむコン📱 アプリのアむコンはノヌマルポヌズのクラシうさぎを䜿甚しおいたすが、季節のむベントに合わせお、うさぎにコスチュヌムを着せたり、背景を倉曎したりしおいたす。 その時は通垞甚のアむコンからの倉化を少なくするために、 クラシうさぎの䜍眮・倧きさは倉えない、顔の芋える範囲を広くする こずを意識しおいたす。 倉化がありすぎるず、クラシルリワヌドのアプリだず気づかず開くこずができない、たたは間違えおアプリを削陀しおしたう可胜性があるので、ナヌザヌの皆さんが気づく範囲で倉えるずいうこずに気を぀けおいたす。 特に顔の暪に぀いおいるもふもふは特城的な圢 をしおいるので、モチヌフで隠れないようにしおいたす。 終わりに 今回は「キャラクタヌ運甚で工倫しおいるこず」をご玹介したした キャラクタヌ運甚をやりたいずいう方の参考になれば幞いです。 たたクラシうさぎもどんどん掻躍の堎を広げおいくので、楜しみにしおいただけるず嬉しいです🐰🥕 おたけ クラシうさぎのぬいぐるみずCGです。 私はぬいぐるみ䜜りが趣味なので、個人的に䜜っおみたした。 CGはBlenderの勉匷をするために䜜っおみたした。
こんにちは、クラシルリワヌドのSRE担圓のjoooee0000です。 私はクラシルリワヌドのサヌビスロヌンチの玄3ヶ月埌にサヌバヌ兌むンフラ゚ンゞニアずしおjoinし、サヌビスの成長ず共に、開発速床ずシステムの信頌性の向䞊を目指しおシステムの改善を行っおきたした。 その䞭で、特に開発速床ず信頌性向䞊に寄䞎したず思う3぀の改善を玹介したいず思いたす。 改善を行う際に「コスト(金額、導入共に)ず効果のバランス」「運甚しやすいシンプルな蚭蚈」に特に気を぀けたので、参考なるず幞いです。 (話すこず: 取り組んだ斜策の抂芁玹介、 話さないこず: 现かいhow to) やっおよかったこず3遞 ブランチ戊略の芋盎しずシンプルな怜蚌環境の維持 ログの構造化ずNewRelicログUIの導入 むンシデント管理ツヌルの導入 それぞれ、改善前にどのような課題があったか、改善埌のメリットなどを玹介しおいきたす。 1. ブランチ戊略の芋盎しずシンプルな怜蚌環境の維持 ここ1幎間、チヌムの成長に合わせおブランチ戊略や怜蚌環境が今の開発スタむルに合っおいるかを郜床怜蚎しながら、速床を萜ずさずに開発を進めおきたした。そこで、初期から珟圚たでのブランチ戊略の改善や怜蚌環境をどのように運甚しおいるかを玹介したす。 チヌムが始たった圓初のサヌバヌサむド゚ンゞニアが1 ~ 3人くらいだった頃の話になりたすが、䞋蚘の図のように、main / develop / stagingずfeatureブランチの4皮類のブランチで運甚されおいたした。 圓時のブランチ戊略 たた、main / develop / stagingそれぞれのブランチをベヌスにしたPullRequestをマヌゞするず各環境にデプロむされる、ずいうデプロむ戊略でした。 圓時のブランチ戊略は、GitFlowなどのブランチ戊略ず違い、developブランチを経由しおmainブランチにリリヌスされるずいった開発フロヌではなく、開発フロヌ䞭にdevelopブランチずmainブランチが合流するポむントがありたせんでした。 それゆえ、mainブランチからdevelopブランチを䞀回切ったあずはdevelopブランチずmainブランチが埐々に乖離しおいくずいう課題があり、featureブランチをマヌゞする際に耇雑なコンフリクトやforce pushが必芁になるこずが頻繁に発生し、開発速床が䜎䞋しおいたした。stagingに関しおは、利甚頻床が掻発ではなかったためデプロむの内容が埐々に叀くなっおいくずいう状況でした。 そこでブランチ戊略をmainずfeatureブランチだけのGithubFlowのブランチ戊略に倉曎し、developブランチの廃止に䌎い、怜蚌環境には個々のfeatureブランチをGitHub Actionsのworkflow dispatchをhookにブランチを遞んでデプロむできるようにしたした。ステヌゞング環境にはfeatureブランチからmainブランチぞのマヌゞをhookに本番ず䞀緒にデプロむされるようにしたした。 デプロむフロヌ たた、そのタむミングで怜蚌環境を開発者個々人に甚意するかどうかが議論に䞊がりたした。しかし、個々人甚に怜蚌環境を䜜るこずで怜蚌環境独自の運甚が発生するこずを回避するために、本番環境ず党く同じ構成の1台で運甚するこずで怜蚌環境の運甚コストを䞋げるこずを遞択したした。そしお、怜蚌環境は最終的な確認のみに䜿い、local環境での開発をメむンにするようにしたした。ブランチ戊略ずデプロむを改善したこずで、怜蚌環境が1台でも問題なく開発ができるようになりたした。たた、少なくずもここ1幎間はほずんど怜蚌環境の運甚䜜業が発生しおおらず、シンプルな構成の恩恵を受けおいたす。 開発者のフィヌドバック 珟圚、サヌバヌサむド゚ンゞニアが6名+web開発の1名になり、ブランチ戊略を敎理した圓時の倍以䞊になったこずで耇数人が同時に怜蚌環境を利甚したいシヌンが増えおきたした。個人のfeatureブランチをデプロむする方法のみだず、怜蚌に埅ちが発生する状態になりたした。 そこで、怜蚌環境を耇数台に増やす怜蚎の前に、たずはブランチ戊略やデプロむの改善をしたした。 デむリヌでmainからその日限りのdevelopブランチを自動䜜成し、そのブランチに耇数人がGitHub Actionsを通しお自動マヌゞ&デプロむをしお怜蚌を行う蚭蚈に倉曎したした。別の開発者がマヌゞしたコヌドずコンフリクトした堎合は自動マヌゞできないので開発者が解消する必芁がありたすが、デむリヌでmainからdevelopブランチを䜜成しおいるため、mainずの乖離による無駄なコンフリクトは発生するこずはありたせん。たた、developブランチぞのマヌゞやブランチ䜜成をGitHub Actionsで自動化するこずで開発者の負担を䞋げおいたす。 最新ブランチ戊略 このように、チヌムの芏暡や開発スタむルに合わせたブランチ戊略の芋盎しず、怜蚌環境をシンプルに保぀こずで、開発速床の向䞊や運甚工数の削枛をするこずができおいたす。 2. ログの構造化ずNewRelicログUIの導入 サヌビスをリリヌスしおから数カ月間は、CloudWatch Logsを利甚しおおり、か぀構造化しおいないログで怜玢性がずおも䜎い状況でした。そのため、ほずんどアプリケヌションログが掻甚されおおらず、䞍具合調査などの業務効率が倧幅に䞋がっおいたした。 そこで、NewRelicの導入ずアプリケヌションログをjson圢匏に構造化をするこずにしたした。 たず、NewRelicを遞定した理由ずしお、䞋蚘がありたす。 NewRelicのデヌタ転送コストがCloudWatch Logsの1/3皋床で枈むこず ログ基盀のElasticsearchの運甚はSaaSのNewRelicに任せるこずで運甚コストが削枛できるこず ログ管理UIの利䟿性 ログ管理をしようず思ったずきに䞀番料金がかさむポむントずしおログ基盀ぞのデヌタ転送の料金がありたす。実際に、CloudWatch Logsでもデヌタ転送料がコストの倧半を締めおいたした。 NewRelicのデヌタ転送コストはSaaSの䞭でもトップクラスで安く、CloudWatch Logsの1/3皋床で枈んだためコスト削枛にも繋がりたした。(実際には぀なぎ蟌みのためのKinesis Data FirehoseずBackup甚のS3の料金があり1/3コスト枛ずたでは行きたせんが、それでもCloudWatch Logs単䜓利甚より安䟡)NewRelicはAPMのSaaSずしおよく知られおいたすが、2022幎からはフルオブザヌバビリティプラットフォヌムずしお様々な機胜が提䟛されおいたす。より高床な機胜の利甚を怜蚎する堎合はナヌザヌアカりントごずの課金もありたすが、ログ管理UIの利甚はBasicUserずいう無料ナヌザヌでも利甚可胜です。 たた、自瀟基盀でログ甚のElasticsearchを運甚するこずも考えたしたが、Elasticsearchの運甚はNewRelicに任せるこずで運甚コストを削枛したした。 NewRelicのログ管理UIはポチポチするだけである皋床の絞り蟌みが行えたり、䞋蚘のようにグラフも自動で出しおくれるのでCloudWatch Logsを利甚しおいたずきず比べお圧倒的に利䟿性が䞊がりたした。 実際のNewRelicログUI たた、無料で䜿えるダッシュボヌド機胜を䜿い、よく怜玢するログ(5xx゚ラヌが出おいる䞊䜍10゚ンドポむントの怜玢、など)をダッシュボヌド化しお可芖化するこずでトラブルシュヌトの速床が䞊がりたした。 NewRelicDashboard NewRelicは前に述べたように、他の機胜も充実しおいるため拡匵性もありたす。実際に、SLI / SLOの可芖化や倖圢監芖など、他でも利甚できるずころが倚々あり、サヌビスが倧きくなっおきた珟圚も䟿利に䜿えおいたす。 たた、アプリケヌションログをjson圢匏に構造化するこずでログ怜玢の利䟿性が䞊がりたした。 アプリケヌションのサヌバヌサむドはRailsを利甚しおいたすが、Railsのログは、゚ンドポむント、リク゚ストパラメヌタ、レスポンスタむム、ヘッダヌなどの情報が耇数行に分かれおいるため、各゚ンドポむントにかかった時間やパラメヌタなどを䞀行で怜玢するこずができたせんでした。たた、䟋えば、CloudWatch Logsのク゚リでリク゚ストごずのレスポンスタむムを怜玢しようずするず䞋蚘のような耇雑なク゚リを毎回曞く必芁があり䞍䟿でした。 fields @timestamp, @message | filter @message like /Completed 200/ | parse @message "Completed 200 OK in *ms (Views: *| ActiveRecord: *ms" as response_time_rails, response_time_view, response_time_rds | filter response_time_rails > 500 | sort @timestamp desc | limit 20 そこで、 GitHub - roidrage/lograge: An attempt to tame Rails' default policy to log everything. を利甚しお゚ンドポむントやレスポンスタむムの情報、ヘッダヌの情報の䞀郚を䞀行で出力できるようにし、コヌド䞊で指定しおいる ::Rails.logger で出力されるRailsのアプリケヌションログも同様にjson圢匏に構造化したした。 たた、::Rails.loggerのタグ機胜でrequest_idを1行ごずに付䞎し、1リク゚ストのログを玐付けられるようにするこずでリク゚ストごずのログが远いやすくなりたした。 request_idによるリク゚ストごずのログ怜玢 Railsのログの構造化に関しおは、意倖ず参考蚘事が芋぀からなかったので埌日远っおブログにしようず思いたす。 NewRelicを導入したこずで、開発速床・信頌性共に恩恵を受けるこずが倚々ありたしたし、わたしたちのサヌビスのトラフィックやログ量だず、CloudWatch LogsからNewRelicに移行するこずでコスト削枛にも繋がりたした。たた、ログの構造化をするこずで䞍具合調査や障害察応時にスムヌズに原因を特定でき、圹立っおいたす。 3. むンシデント管理ツヌルの導入 3぀めは、むンシデント管理ツヌルを導入し、MTTR(平均埩旧時間)の短瞮をした話です。 私達のサヌビスは、サヌビス利甚ピヌク時間垯が朝方です。サヌビス利甚のピヌク時間は、他の時間垯ず比范しお障害発生確率が高くなる傟向にありたす。しかし、ピヌク時間垯が朝方のため、開発メンバヌが起きおおらず、障害に気が付かないこずでMTTR(平均埩旧時間)が䌞びおしたったこずがありたした。 アラヌトはSlackに流すようにしおいたしたが、それだけだず 「垞にSlackを芋おいないず障害に気づけない」、「アラヌト通知が他のSlack通知ず䞀緒の音で玛れがち」ずいう課題がありたした。 そこで、たずは朝方や䌑日のむンシデントに確実に気づけるよう、むンシデント管理ツヌルのOpsgenieずいうむンシデント管理ツヌルを導入したした。むンシデント管理ツヌルの機胜の䞭でも、アラヌト通知機胜によっおMTTRを短くする察策するこずにしたした。 CloudwatchAlarmでアラヌトが䞊がったらSNS経由でOpsgenieにアラヌトを送信するようにしたす。たた、自分のスマヌトフォンにOpsgenieのアプリをむンストヌルするこずで、アラヌトをスマホで受け取れるようになりたす。 そうするこずで、障害が起きるずスマホから目芚たしのアラヌムのような音が鳎り(心臓に悪いずいう点では䞍評)、障害に迅速に気づくこずができたす。Opsgenieの導入以降は障害に気づくたでの時間が短瞮され、MTTRの短瞮に寄䞎したした。 加えお、サヌビスに関する重芁な意思決定ができるメンバヌ(珟EM)も䞀緒にアラヌトを受け取れるようにし、障害時の察応に迷った際、迅速に意思決定ができるようにしおいたす。 Opsgenieは、アラヌト通知機胜を䜿いたいだけであれば、利甚人数5人たではフリヌプランで足りたす。 最近チヌムの人数が増えたこず、過去のむンシデントずアラヌトの玐づけのニヌズが䞊がっおきたこずにより有料プランぞの切り替えを予定しおいたすが、この1幎間はフリヌプランで十分なメリットを享受できおいたした。その他にも、フリヌプランで オンコヌルロヌテヌションの自動スケゞュヌリング (メンバヌずロヌテヌション期間を指定すれば自動でスケゞュヌルを組んでくれる) ゚スカレヌション機胜 (スマホで受け取ったアラヌトのボタンを抌せば自動で゚スカレヌションできる) オンコヌルスケゞュヌル画面 などが利甚でき、耇数人の開発者のオンコヌルロヌテヌションを簡単に仕組み化するこずができたす。 むンシデント管理ツヌルずしおはPagerDutyが有名ですが、Opsgenieは同じような機胜をPagerDutyの半額で利甚できるのでコスト面も優れおいたす。たた、 Atlassian の補品なので品質も特に問題なくUIも䜿いやすいです。 Opsgenieには様々な機胜がありたすが、たずはシンプルにアラヌト通知の機胜を䜿うだけでもメリットがあるので、おすすめです。 たた、OpsgenieはTerraformでproviderが提䟛されおおり、蚭定内容をTerraformで管理するこずができたす。Terraformで管理するこずで、属人化や蚭定のブラックボックス化を防いでいたす。 たずめ 開発速床・信頌性向䞊のための取り組みを3぀玹介したした。 運甚面やコスト面を考慮しお改善を行っおいるので、小さいチヌムにも参考になれば幞いです
NHK関連の話ではないです こんにちは harry( @gappy50 )です〜。 これたでクラシルでデヌタ゚ンゞニアをしおおりたしたが、最近クラシルリワヌドずいう別プロダクトでデヌタ゚ンゞニアをしおおりたす。 クラシルリワヌドのデヌタ基盀は以䞋に詳现がありたすので、ご興味あればどうぞ tech.dely.jp 本蚘事のタむトルは私がTwitter改めXにポストした投皿から抜粋したした恥 おい、誰も隒いでないから隒ぐけどExternal Network AccessっおいうSnowflakeから倖郚ぞアクセスできる機胜、デヌタサむロ完党にぶっ壊せるぞ。 Federated Queryずしお他のPFのDWHだけじゃなく独自のデヌタもAPIずかから取っおSnowflakeでク゚リぶん回せるんだぜ。 https://t.co/qj18hEkMAh — harry (@gappy50) 2023幎10月20日 今日は、クラシルリワヌドずクラシルのデヌタをSnowflakeのExternal Network Accessを䜿っお越境させお分析できるようにしたよ〜ずいうお話をしたす。 たずはその前に少し小話を。 どうやるかだけ気になる人は埌半をご芧ください。 クラシルずクラシルリワヌドのデヌタ基盀ずデヌタ基盀よもやた話 クラシルリワヌドではGoogle Analytics for Firebaseの行動ログを䞻に分析するためデヌタ基盀はBigQueryをベヌスに据えお日々の分析業務を行っおいたす。 䞀方、これたでわたしがいたクラシルではAWS䞊に構築されたSnowflakeに行動ログや各皮デヌタを栌玍しお分析をしおおりたす。 各プロダクトがアゞリティをもっお意思決定をしおいくには、䜙蚈なこずはせずに倧事なデヌタがあるずころ、重心があるずころに軞(DWH)を眮いおいくのがたずは正攻法ですよね。 クラシルの堎合は、AWS環境䞊にのみデヌタがあるのでSnowflakeを䜿うのは自然な流れですし、クラシルリワヌドの堎合はGCPにデヌタの重心があるのでそこを軞に考えるのが自然です。 ただし、それぞれのデヌタの利掻甚がどんどん進んでいくずこんな声も聞こえおきたす。 Ž-`.oOクラシルの○○のデヌタずクラシルリワヌドの△△のデヌタを䞲刺しでみるこずで◎◎の結果を知りたい Ž-`.oOクラシルずリワヌドのデヌタをうたく突合できないかね そういった堎合、デヌタ゚ンゞニアがこれたで考えるべきこずは 😀 < (必芁なデヌタunloadしおどっちかに寄せおおくか〜)ずか 😀😀 < (Embulkを䜿っお党郚デヌタかき集めるか〜)ずか 😀😀😀 < (デヌタサむロをぶっ壊すための倩䞋䞀歊道䌚を開催しおデヌタ基盀を統䞀するぞ)ずか。 デヌタ゚ンゞニアの腕がなるずころですね。埌半になるに぀れお錻息が聞こえおきたす😀 党瀟のデヌタ基盀をAにしたしたずかBに移行したしたずかいろんな事䟋も䞖の䞭にはわんさかあるし、 長期目線で考えたらデヌタサむロはないほうがよいに決たっおたす。 ちなみにですが、デヌタサむロは以䞋のようなものを指したす。 デヌタサむロずは、互いに分離され、瀟内の他郚門、他郚眲からアクセスできないデヌタストレヌゞ/管理システムのこずです。これは、互いに通信したり情報を共有したりするこずができない個別のシステムやデヌタベヌスにデヌタが保存されおいる堎合に発生したす。デヌタサむロは、非効率、ミス、遅延の原因ずなるだけでなく、䌁業がデヌタを掻甚しお有益な情報を取埗し、より適切な意思決定をするうえで劚げずなりたす。その結果、瀟内の耇数の郚眲や事業郚門でデヌタが重耇したり、䞀貫性なく䜿甚されるこずが倚くなりたす。 データサイロとは | 用語集 | HPE 日本 たさに今クラシルずクラシルリワヌドはデヌタサむロが起きそうな起きおる状況ですね。 我々の堎合は、それぞれのデヌタの重心がAWSずGCPに分かれおしたっおいるこずがより難しくしおいる原因ですね。 ただし、錻息荒くするだけでこのデヌタサむロをぶっ壊すこずはできたせん。 これらを解消するための䟡倀やコストを説明できる状況にならなければそんなものは倢物語になっおしたいたす。 そもそも本圓に組織のアゞリティを萜ずしおたでやるべきこずなのかみたいなこずたで考え出すずそんなに気軜に意思決定なんおできたせん。 特にAWSやGCPなどのプラットフォヌムを暪断せざるを埗ない堎合、そのデヌタ量が倚いものを重心がないほうぞ寄せるのはストレヌゞコストだけでなく、転送コスト、それらを実珟するためのコンピュヌティングリ゜ヌスのコストなどの運甚コストを寄せ始めおからずっず払い続けるこずを意味しおいたす。 そしおそれらを乗り越えおデヌタサむロをぶっ壊したずなっおも、事業むンパクトもなく、むしろ利䟿性を䞋げおしたったら本末転倒ですよね。 なので、各事業の状況や䌚瀟ずしおの状況、それらに玐づく制玄や条件によっおは、デヌタサむロをぶっ壊すずこずがいいかずいえばそうでないこずも倧いにありたすし、逆にいえば最初から長期目線でデヌタサむロを起こさない意思決定をするこずで利掻甚が進むこずでかかっおしたう莫倧な移行コストを抑えるようなこずも考えられるず思いたす。 埌者ができれば䞀番幞せではありたすが、前者も埌者もやり盎しがほができない䞀発勝負の䞖界だずいうこずも肝に銘じないずいけたせん。 そうやっお、デヌタ゚ンゞニアは錻息ではなく溜息を぀きながら郜床郜床必芁なデヌタの出し入れするコストを払い続けるのです。 このような状況においお、デヌタサむロはぶっ壊すこずは䞍可胜なのでしょうか  もしかしたら、SnowflakeのExternal Network Accessがあればぶっ壊すこずができるかもしれたせん。 External Network Accessのサンプルは以䞋に詳现がありたす。 この䟋ではSnowflakeのSQLからGoogle Translateを呌び出すサンプルを䟋瀺しおいたす。 docs.snowflake.com 話長くなりたした。本線です。 External Network AccessでBigQueryのデヌタをSnowflakeから呌び出す 元ネタはこれです。 medium.com 䞊蚘簡単に説明するず SnowflakeでExternal Network AccessずいうPuPrの機胜を䜿うこずで倖郚APIぞセキュアにアクセスできる BigQueryやGoogle スプレッドシヌト等にあるデヌタセットもAPIから呌べるのでデヌタサむロ打砎できる ただし、倧量なデヌタを頻床高く取るずBigQueryからの転送コストやBigQueryずSnowflakeのどちらにもコンピュヌティングリ゜ヌスのコストを払わないずいけないから泚意しおね みたいな蚘事です。 ただし䞊蚘蚘事のたただず、倧量のデヌタを取埗できおもSnowflake偎で展開する際のコストがかかりすぎたり、そもそもデヌタをSnowflake䞊に展開できないこずがありたす。 そのため、UDTFsに倉曎をした䞊でSnowflakeからBigQueryのデヌタを取埗しおみたいず思いたす。 たた、OAuthではなくGoogle Cloudのサヌビスアカりントを利甚しおアクセスしおみたす。 今回は ACCOUNTADMIN で実装をしおおりたすが、External Network Accessは倖郚ぞのデヌタ出し入れが可胜になる機胜であるため、Snowflake䞊での適切な暩限蚭定が必芁であるこずは理解しおいただければず思いたす。 たた、珟時点(2023-10-25時点)ではPuPrの機胜であるこずを念頭においおおく必芁がありたす。 たずBigQueryぞのアクセスのためのルヌルをスキヌマ内に䜜成したす。 use hoge_dev.external; create or replace network rule bq_rule mode = egress type = host_port value_list = ( ' oauth2.googleapis.com ' , ' bigquery.googleapis.com ' ); 次にサヌビスアカりントのアカりントキヌを GENERIC_STRING ずしおシヌクレットを䜜成したす。 create or replace secret bq_service_account type = GENERIC_STRING SECRET_STRING = ' {ここに払い出されたアカりントキヌの情報を入れる。必芁に応じお゚スケヌプしたりする。} ' ; そしお、䞊蚘のネットワヌクルヌルずシヌクレットを䜿っおexternal access integrationを䜜成したす create or replace external access integration bq_access allowed_network_rules = (bq_rule) allowed_authentication_secrets = (bq_service_account) enabled = true ; 最埌に䞊蚘のexternal access integrationを䜿っおUDTFsを䜜成したす。 CREATE OR REPLACE FUNCTION run_bq_query_table(projid string, sql string) RETURNS table(value variant) LANGUAGE PYTHON RUNTIME_VERSION = 3.8 HANDLER = 'BigQueryDataFetcher' EXTERNAL_ACCESS_INTEGRATIONS = (bq_access) PACKAGES = ( 'snowflake-snowpark-python' , 'requests' , 'google-auth' ) SECRETS = ( 'cred' = bq_service_account) AS $$ import _snowflake import requests import json from google.oauth2 import service_account from google.auth.transport.requests import Request class BigQueryDataFetcher : def __init__ (self): self.headers = self._get_headers() @ staticmethod def _get_headers (): # Snowflakeで䜜成したsecretから認蚌情報を取埗 credentials_info = _snowflake.get_generic_secret_string( "cred" ) credentials_dict = json.loads(credentials_info) credentials = service_account.Credentials.from_service_account_info( credentials_dict, scopes=[ "https://www.googleapis.com/auth/bigquery" , "https://www.googleapis.com/auth/cloud-platform" ] ) # 認蚌情報をもずにGCPのサヌビスアカりントのトヌクンを取埗 credentials.refresh(Request()) # ヘッダヌ情報を返华 return { "Authorization" : f "Bearer {credentials.token}" , "Content-Type" : "application/json" } def process (self, project_id, sql_query): # BigQueryにク゚リを投げる゚ンドポむント query_url = f "https://bigquery.googleapis.com/bigquery/v2/projects/{project_id}/queries" # ク゚リを実行しお初回のレスポンスデヌタを取埗 response_data = self._execute_query(query_url, sql_query) job_id = response_data[ "jobReference" ][ "jobId" ] location = response_data[ "jobReference" ][ "location" ] schema = response_data[ 'schema' ][ 'fields' ] columns = [field[ 'name' ] for field in schema] # 取埗した行デヌタを{"カラム名": "倀"}のjson formatに倉換しtupleを返华 # UDTFではreturnよりもyieldにするほうが遅延評䟡の恩恵を受けお効率がよい # https://docs.snowflake.com/ja/developer-guide/udf/python/udf-python-tabular-functions#implementing-a-handler for row in response_data.get( 'rows' , []): yield ({col: item[ 'v' ] for col, item in zip (columns, row[ 'f' ])}, ) # ペヌゞトヌクンが存圚する堎合は次ペヌゞのデヌタを取埗する page_token = response_data.get( "pageToken" ) result_url = f "{query_url}/{job_id}" while page_token: payload = { "timeoutMs" : 180000 , "location" : location, "pageToken" : page_token } response_data = self._get_query_results(result_url, payload) page_token = response_data.get( "pageToken" ) for row in response_data.get( 'rows' , []): yield ({col: item[ 'v' ] for col, item in zip (columns, row[ 'f' ])}, ) def _execute_query (self, url, sql_query): # BigQueryにク゚リをpostする payload = { "query" : sql_query, "useLegacySql" : False , "timeoutMs" : 180000 } response = requests.post(url, headers=self.headers, data=json.dumps(payload)) response.raise_for_status() return response.json() def _get_query_results (self, url, payload): # ク゚リの結果をgetする response = requests.get(url, headers=self.headers, params=payload) response.raise_for_status() return response.json() $$; あずは、SnowflakeからBigQueryに投げるク゚リずSnowflake偎での倉換凊理を曞いおおしたいです。 select value:event_date::string as event_date, value:event_name::string as event_name, value:record_count:: number as record_count, value from table (run_bq_query_table( ' <GCPのProject ID> ' , ' select event_date, event_name, count(*) record_count from `events_*` where _TABLE_SUFFIX = '' 20231001 '' group by 1, 2 ' )); どやぁ ある皋床Snowflakeで扱いやすいようにBigQueryからのレスポンスを敎圢しおvalueずいうvariantの1列にデヌタを栌玍するようにしおいたす。 たた、レスポンスが倧きいずAPI偎でペヌゞングがされるので、そこらぞんもよしなに取れるようにしおたす。 手元では100䞇行超、2列のデヌタをBigQueryから取埗しお衚瀺されるたでXSで動かしお1分皋床で返っおきたした。 ただし、VARIANT列にすべおのレコヌド情報をkey-valueの圢で栌玍しおいるので、1行あたりのデヌタ量が最倧長の16 MBを超えるず䜕かしらの問題があるかもしれたせん。 たた、BigQueryのSTRUCT型のレスポンスが結構カオスなので事前にBigQuery偎でunnestする等の凊理はしおおいたほうが幞せになれそうです。 他にも、こうしたほうがもっずよいよ〜みたいなのあればぜひ教えおください💪 さいごに いかがでしたでしょうか 煩雑なデヌタ゚ンゞニアリングを日々行ったり、デヌタサむロの解消のための倩䞋䞀歊道䌚を開催をせずに、SnowflakeからExternal Network Accessを䜿えば最速でデヌタサむロを解消するこずもできそうですね。 今回はBigQueryからのデヌタ取埗をサンプルずしお䟋瀺したしたが、流行りのOpenAIをSnowflakeにちょちょっず蚘述するだけでSQLから呌び出すこずもできそうですし、他にも既存の倖郚デヌタの連携やデヌタパむプラむンに察しおも色々な遞択肢を取れるようになるので、色々ず倢が広がりたすね。 そういうわけで、External Network Accessはデヌタサむロをぶっ壊せる可胜性がありたすよずいうお話でした。
Hello. My name is K, and I am currently working as an android engineer in Kurashiru. 🚀 Preface Brief Intro to Relay Creating UI Packages with Relay Using the component in Android Studio Map to Compose Theme Map to Existing Components Review of Relay: thoughts on it’s practical usage Preface At Kurashiru, we're on a journey of transitioning to Jetpack Compose. This has led me to experiment with Relay plugin in Kurashiru-next. As you may be aware, Relay is currently in alpha and is a design-to-code transformation tool. Relay makes it possible for designers to create UI components in Figma and export/import them into Android Studio to generate pixel-perfect Compose code. The ability to seamlessly generate pixel-perfect Compose code from Figma UI components, makes me wonder a bunch of questions, “Does this tool suitable for practical use?”, “How will it look like with Kurashiru?” and “Who is this for?”. So, I did a little experiment to transform a few Kurashiru’s components in Figma to Compose code using Relay and I would like to share that experience in this article. Brief Intro to Relay Relay provides instant handoff of Android UI components between designers and developers. Designers use the Relay for Figma plugin to annotate and package UI components for developer use, including information about layout, styling, dynamic content and interaction behavior. These UI Packages provide a shared model for UI components, and can be exchanged and updated in a collaboration between designers and developers. Relay consists of three plugins: the Relay for Figma plugin, the Relay for Android Studio plugin, and the Relay Gradle plugin for developers. Once setup, the process of converting the design into code can be done in a few steps: Package up a component in Figma by specifying parameters (information about the layout, styling, arbitrary content, and interaction behavior of the design). Import UI packages into Android Studio. Build the project and the codes will be generated. I will skip the setup parts and jump straight to using it. Here is documentation on how to set up . Creating UI Packages with Relay Let’s work on simple Button Component as an example. Button Component in Design system These are different variants of button used in Kurashiru app. I reckon a button is a good exercise to study basic capabilities of Relay. Continuing to the packaging of component, define the parameters that the developers need to be able to control. In this scenario, design (size, primary, alternative, filled, outlined and so on), onTap and Text are added to be able to pass dynamically. Packaging the Component Using the component in Android Studio Importing to android studio is pretty simple to sort out by following the steps from here . After building the project, the codes are auto-generated. Details of what kind of codes are generated can be read here . To see the results, I dropped the generated Button into a @Preview composable like this. @Preview @Composable fun ThemeButtonPreview() { Button( text = "HELLO" , type = Type.Filled, size = Size.Large, state = State.Theme, onTap = { /* do nothing*/ } ) } @Preview @Composable fun PrimaryButtonPreview() { Button( text = "HELLO" , type = Type.Filled, size = Size.Large, state = State.Primary, onTap = { /* do nothing*/ } ) } Preview Composable Map to Compose Theme For colors and typography, Relay generates literal values by default. This ensures translation accuracy, but prevents components from using the Compose theming system. To resolve the theme issues, Relay offers an experimental feature,   Mapping Styles to a Compose Theme . This feature allows to map named styles in Figma, to tokens, and then from tokens to Compose theme properties which allows us to point Figma styles directly to their Compose equivalents. Mappings are defined in  json but I will not go further into those and continue with the next point which is about Mapping components to existing code. Map to Existing Components Developers can customize the code generation process by providing a mapping between a UI Package and an existing code component instead of the generated code. This is beneficial when the existing implementation has features that cannot be achieved by the generated code such as animation or complex behavior (such as a drop down menu). Another experimental feature, allows us to map our own created components to the generated components. In addition to the button, I also conducted an experiment with the SearchBar. The generated search bar is not user interactive, which means cannot type inputs or detect input changes, and other complex logics are needed to be handled as well. To solve these problems, Map Components to existing code feature can be used. This feature basically allows to use the developer coded composable which can do the functionalities that are hard to describe in Figma. The mapping file name must match with that of the UI Package folder for the component it replaces, <<component_package.json>>, mappings/search_bar.json in this case. This file will map ui-packages/search_bar to the hand-rolled composable. { " target ": " KurashiruSearchBar ", // name of existing composable " package ": " com.kurashiru.ui.textfield ", // package directory of existing composable " generateImplementation ": true , " generatePreviews ": true } This way, the generated code can be customized and composables that operate the required functions can be created. 🎉 Review of Relay: thoughts on it’s practical usage Still in alpha, Relay is a tool that is stable and functional. It does as it promises, seamlessly produce Compose code from Figma designs. Using the versioned design system components in Figma as the source of truth is a valuable approach from a design system standpoint, necessitating a rigorous process for designers who collaborate with the system. It requires more communication between designers and developers to settle on things like naming of parameters and to be able to deliberate with interaction & accessibility handling, which may require modification of the existing design system. Kurashiru has a stable design system which is being used for both Android and iOS. Since Relay doesn't support iOS, adapting the design system exclusively for Android would be an extra effort. The generated component is tightly coupled with Figma design system and allowing for effortless one-click updates to the UI packages. However, this tight coupling may pose challenges when conducting AB tests. It definitely is faster than building of simple components by hand but as there are limitations to it, coding the complex components by hand and mapping to those generated components will become a necessity. To wrap up my thoughts on Relay, it is a pretty dandy tool. However, its limitations, mostly stemming from its early stages, mean that its benefits depend on the size and composition of the mobile team that inhabits it. For now, Relay feels like more effort than it’s worth to Kurashiru. But hey! Since it is introduced as part of Modern Android, I would like to wait to see its growth and expecting Relay to grow into a tool that bridge design-to-code without the need of extra works. Of course these are just my thoughts and words on trying it out, so, do not take these words and try it out! See you in the next articles 👋🏌 References 📚 developer.android.com codelabs.developers.google.com
iOSDCに぀いお iOSDCは 公匏ペヌゞ によるず、 iOSDC Japan 2023はiOS関連技術をコアのテヌマずした゜フトりェア技術者のためのカンファレンスです。 ず玹介されおおり、日本最倧玚のiOS関連のカンファレンスず知られおいたす。 iOSDC 2023では1,409枚のチケットが発行され、非垞に倚くの方々が参加されたした。 このカンファレンスは9/1から9/3の3日間、オフラむンずオンラむンのハむブリッド圢匏で開催されたした。 発衚した内容 圓日は私もLT枠で" ShazamKitの魔法を解き明かす: 音楜認識技術「オヌディオフィンガヌプリント」の探怜 "ずいうタむトルで発衚を行いたした。 圓日の資料は以䞋からご芧いただけたす。 speakerdeck.com このテヌマは業務ずは盎接関係ありたせんが、瀟内勉匷䌚甚にたずめた内容をもずに応募したした。 iOSの技術ずは盎接関連しない音楜認識技術に関する話だったため、反応が気になりたしたが、Twitterやニコ生のコメントを芋るず倚くの方に楜しんでいただけたようです。 iOSDCでは、他にも音楜関連の発衚があり、自動䜜曲や空間オヌディオなどの興味深いトピックに぀いお孊ぶこずができたした。 瀟内での共有䌚 カンファレンス終了埌、dely瀟のiOS゚ンゞニアたちが集たり、印象的だった発衚に぀いおの共有䌚を開催したした。 聎講した発衚をもずに自瀟サヌビスに䜿えそうなもの・単玔に面癜かった内容に぀いお話し合いたした。 特に盛り䞊がりたしたスラむドを以䞋に玹介したす。 speakerdeck.com speakerdeck.com speakerdeck.com speakerdeck.com 他にも興味深い発衚が倚く、䞊に挙げた以倖の発衚も含め瀟内のiOS゚ンゞニアで盛り䞊がりたした。 終わりに iOSDCでの登壇ず、瀟内での共有䌚に぀いお玹介したした。 幎に䞀床の倧きなカンファレンスなので、瀟内でも倚くの興味ず議論が湧き䞊がりたした。 WWDCの埌にも同様の共有䌚を蚭けたしたが、今埌もこのような機䌚を増やしおいきたいず思いたす。 最埌に、カンファレンスの運営を支えおくださった皆さた、スポンサヌの皆さたに心からの感謝を申し䞊げたす。 次回もこのような機䌚があれば、積極的に参加したいず思っおおりたす。
Hello, I'm Allan, a Server-Side Engineer at Kurashiru 🚀 While Kurashiru predominantly relies on MySQL, it's intriguing to explore the broader landscape of database management. Enter PostgreSQL, a robust contender, known for its powerful techniques of Sharding and Partitioning. Even if you're steeped in a different database system, understanding these strategies can be invaluable. This guide delves into the world of PostgreSQL, elucidating how to implement and monitor Sharding and Partitioning within a Dockerized Rails framework. It's a journey of ensuring agility and scalability, irrespective of your primary database preference. Let's dive in! 📘 Table of Contents Understanding the Strategies Sharding Why Use Sharding? Challenges When to use Sharding Partitioning Types of Partitioning in PostgreSQL Advantages Summary of key concepts Practical Implementation with Docker & Rails Sharding Partitioning Monitoring & Performance Insights The Power of pg_stat_statements Disk Usage Metrics Monitoring Connections Third-Party Monitoring Tools Always Test in Staging Parting Thoughts 🌐 Understanding the Strategies 1. Sharding : Sharding is essentially the practice of splitting your database into several smaller, more manageable pieces, and distributing them across a range of storage resources. Why Use Sharding? Distributed Data : With data distributed across servers, you can leverage the power of multiple machines. This ensures that as your data grows, you can keep adding servers to handle the load. Isolation : By isolating data, you ensure that issues affecting one shard (like an overload or crash) won't cripple your entire system. Challenges : Operational Complexity : Maintaining multiple shards, ensuring data consistency, and handling backups can be challenging. Cross-Shard Queries : Aggregating data or joining tables across shards can be complex and slower. When to use Sharding : When data is too large to fit efficiently on a single server. When you have high transaction rates that require distributed processing. Geographic distribution requirements. 2. Partitioning : Partitioning divides a table into smaller, more manageable pieces, yet the partitioned table itself is still treated as a single entity. Types of Partitioning in PostgreSQL : Range Partitioning : Rows are partitioned based on a range of values. For instance, orders from different months can be stored in separate partitions. List Partitioning : Rows are partitioned in specific predefined categories. E.g., sales data can be partitioned by country. Hash Partitioning : Rows are partitioned using a hash function on the partition key, ensuring even data distribution. Advantages : Improved Query Performance : Data retrieval can be faster since scans are limited to specific partitions. Maintenance : Older data can be purged without affecting the rest of the table by simply dropping a partition. 3. Summary of key concepts : The table below summarizes the significant differences between sharding and partitioning for your reference. We will explain these terms in detail further on. Dimension Sharding Partitioning Data Storage On separate machines On the same machine Scalability High Limited Availability High Similar to unpartitioned database Number of Parallel Queries Depends on the number of machines Depends on the number of cores in the single machine Query Time Low Medium to Low Vertical partitioning Vs Horizontal partitioning (sharding) 🛠 Practical Implementation with Docker & Rails 1. Sharding : Setup : Create multiple PostgreSQL instances using Docker Compose, each representing a shard. docker-compose.yml : version : '3' services : primary_db : image : postgres environment : POSTGRES_USER : user POSTGRES_PASSWORD : password POSTGRES_DB : app_development shard_one_db : # ... similar to above ... shard_two_db : # ... and so on ... database.yml : development : primary : adapter : postgresql database : app_development # other settings... shard_one : adapter : postgresql database : app_shard_one # other settings... # ... and so on ... Model Connection : By default, models connect to the primary. For specific models: class SomeModel < ApplicationRecord connects_to database : { writing : :shard_one , reading : :shard_one } end 2. Partitioning : Setup : Partition tables based on chosen criteria. Migration Example (Partitioning by Date): class CreatePosts < ActiveRecord :: Migration [ 6.1 ] def up create_table :posts , partition_key : :created_at do |t| t.string :title t.text :content t.timestamps end # Define a partition for 2023 execute <<- SQL CREATE TABLE posts_2023 PARTITION OF posts FOR VALUES FROM ('2023-01-01') TO ('2024-01-01'); SQL end def down drop_table :posts execute " DROP TABLE posts_2023; " end end 📊 Monitoring & Performance Insights The real worth of any database scaling strategy is determined by how it performs in the wild. To ensure your sharding or partitioning strategy is delivering its promise, you need robust monitoring and performance insights. 1. The Power of pg_stat_statements : This module provides a means to track execution statistics of all SQL statements executed by a server. Activation : Uncomment or add the following line in postgresql.conf : shared_preload_libraries = ' pg_stat_statements ' Usage : This view will contain rows of normalized query strings and associated statistics: results = ActiveRecord :: Base .connection.execute( " SELECT query, calls, total_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10; " ) results.each do |row| puts " Query: #{ row[ ' query ' ] } , Calls: #{ row[ ' calls ' ] } , Total Time: #{ row[ ' total_time ' ] }" end This code fetches the top 10 queries with the highest total execution time, which helps in identifying slow-performing queries. 2. Disk Usage Metrics : As data grows, monitoring the disk space becomes crucial, especially when using partitioning, as each partition can grow at different rates. Checking Table and Partition Sizes : sizes = ActiveRecord :: Base .connection.execute(<<~ SQL SELECT nspname || '.' || relname AS "relation", pg_size_pretty(pg_total_relation_size(C.oid)) AS "size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') ORDER BY pg_total_relation_size(C.oid) DESC LIMIT 10; SQL ) sizes.each { |row| puts "#{ row[ ' relation ' ] } - #{ row[ ' size ' ] }" } This snippet fetches the top 10 relations (tables/partitions) based on their size. 3. Monitoring Connections : With sharding, connections can exponentially grow as you connect to multiple databases. Use the following to monitor active connections: active_connections = ActiveRecord :: Base .connection.execute( " SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname; " ) active_connections.each do |row| puts " Database: #{ row[ ' datname ' ] } , Active Connections: #{ row[ ' count ' ] }" end 4. Third-Party Monitoring Tools : There are a myriad of third-party tools that offer extensive PostgreSQL monitoring capabilities: pgBadger : An advanced PostgreSQL log analyzer. Datadog : Offers PostgreSQL integration to monitor performance and health. New Relic : Their PostgreSQL monitoring integration provides insights into slow queries, busy times, and more. 5. Always Test in Staging : Before pushing any changes, especially related to database scaling, always test in a staging environment. This environment should mirror your production setup. Tools like pgbench can help simulate load on your database, allowing you to gather performance insights. 🌟 Parting Thoughts Whether sharding or partitioning, the choice hinges on your application’s needs. If you anticipate vast datasets with geographical dispersion, sharding can be a boon. However, if your dataset is massive but localized, partitioning might suffice. In either case, a well-architected Rails app, coupled with PostgreSQL's robustness and Docker's encapsulation, can stand tall against scaling challenges and hope this article find it helpful for those who are considering sharding or partitioning. 📚 References planetscale.com edgeguides.rubyonrails.org blog.bytebytego.com Sharding vs. Partitioning Demystified: Scaling Your Database
はじめに クラシルリワヌドに぀いお デヌタ基盀の党䜓構成 BigQueryの遞定理由 デヌタ基盀における重芁な圹割 アプリのむベントログのscan量削枛 DynamoDBやRDSをBigQueryにSync Snowflakeの掻甚 BIツヌル(Redash, Looker) Redash Redash repositoryのフォルダ・ファむル構成 git管理䞋のSQLク゚リをRedashに反映 Lookerに぀いお さいごに はじめに こんにちはクラシルリワヌドで開発責任者をしおいるfunzinです。 この蚘事ではクラシルリワヌドのデヌタ基盀の構成に぀いお玹介しおいきたす。 クラシルリワヌドに぀いお はじめにクラシルリワヌドのサヌビス抂芁に぀いお玹介させおください。 クラシルリワヌドは「日垞のお買い物䜓隓をお埗に倉える」アプリです。 買い物のためにお店に行く移動する、チラシを芋る、商品を買う、レシヌトを受け取る......。これら日垞の行動がポむントに倉わり、そのポむントを䜿っお様々な特兞ず亀換するこずができたす。 気になる方は サヌビスサむト をぜひご確認ください。 それではさっそく本題のデヌタ基盀の構成に぀いお説明しおいきたす。 デヌタ基盀の党䜓構成 デヌタ基盀の党䜓構成 クラシルリワヌドのデヌタ基盀の技術スタックは䞋蚘になりたす。 DWH: BigQuery(メむン), Snowflake(サブ) ETL: Embulk, Digdag BI Tool: Redash, Looker 党䜓像のみではそれぞれの圹割が把握しにくいため、次の章より詳现を説明しおいきたす。 BigQueryの遞定理由 クラシルリワヌドではメむンのデヌタ基盀ずしおBigQueryを利甚しおいたす。 BigQueryを遞定した理由ずしおは䞋蚘ずなりたす。 デヌタ゚ンゞニアが䞍圚のため、フルマネヌゞドなサヌビスを利甚したい サヌビスの立ち䞊げ圓初、新芏事業ずいうこずもあり最小人数で開発をしおいたためデヌタ゚ンゞニアが䞍圚でした。 しかし、斜策結果を振り返るためにむベントログ実装は必須であり、デヌタ基盀を構築する必芁がありたした。 たた自瀟デヌタ基盀の堎合、むベントログのスキヌマ蚭蚈、゚ラヌ時の察応、デヌタパむプラむンの修正察応などに時間がかかるこずが懞念ずしおありたした。 そのためフルマネヌゞドなBigQueryを採甚するこずで、デヌタ基盀の構築にかかる時間を短瞮しサヌビス開発にリ゜ヌスを割くこずができるず刀断したした。 2. Google Analytics for Firebaseずの盞性が良い クラシルリワヌドは 珟圚 iOS / Android アプリでサヌビスを提䟛しおいたす。 モバむルアプリでは Firebase を利甚するこずが䞀般的であり、クラシルリワヌドでもFirebaseを積極的に利甚しおいたす。 Google Analytics for Firebase を利甚するこずで䞋蚘のメリットがありたす。 BigQuery Export を利甚するこずで、GAに送信されたむベントログが1日䞀回定期実行でむベントログのテヌブルずしおBigQueryに自動で゚クスポヌトされるため自前でむベントログのデヌタパむプラむンを䜜成する必芁がない ログのスキヌマ が事前に決たっおいるため、開発者は event_name , event_params など最䜎限のものだけを意識すれば良い アプリ偎ではFirebase Analyticsのラむブラリが提䟛されおいるため、䞋蚘のように送信凊理を曞くのみで完結する iOSでのむベント送信䟋 // event_name: test_event // event_params: ["index": 0] Analytics.logEvent( "test_event" , parameters : [ "index": 0 ] ) むンフラはAWSで構築しおいるためAWS Athena、クラシルで利甚しおいるSnowflakeなども怜蚎したしたが、Google Analytics for Firebaseを利甚するメリットが倧きいためBigQueryを採甚したした。 デヌタ基盀における重芁な圹割 この章ではクラシルリワヌドのデヌタ基盀においお、重芁な圹割を抜粋しお説明しおいきたす。 アプリのむベントログのscan量削枛 BigQueryの遞定理由でも説明したしたが、 アプリからむベントログを送信するためにGoogle Analytics for Firebaseを利甚しおいたす。 日付別テヌブルがBigQueryに゚クスポヌトされるため、これだけでもむベントログ分析は可胜になりたす。 しかし、そのたた日付別テヌブルを利甚する堎合、DAUが増えるに぀れお、BigQueryのscan量が増加しコストに圱響しおきたす。 䟋えば起動むベントのみを抜出する堎合、日付別テヌブルを利甚するずwhere句で条件を指定しおもその範囲の日付党おのむベントが察象ずなり、パヌティション分割テヌブルず比范しおscan量が倚くなっおしたい、結果的にコストに圱響したす。 日々分析をする䞊でのscan量の課題を解決するために、䞋蚘のような工倫をしおいたす。 パヌティション分割テヌブルを利甚 BigQueryに゚クスポヌトされた日付別テヌブルを盎接利甚するのではなく、パヌティション分割テヌブルずしお倉換しお分析ではこちらを利甚するようにしおいたす。 䞋蚘がパヌティション分割テヌブルを䜜成するサンプルク゚リです。 CREATE OR REPLACE TABLE `product_firebase_analytics.events` PARTITION BY DATE (event_timestamp_micros) CLUSTER BY event_name, new_event_name, platform AS SELECT event_date, TIMESTAMP_MICROS(event_timestamp) AS event_timestamp_micros, ARRAY_TO_STRING( [event_name, ( SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = ' id ' )], " _ " ) AS new_event_name, platform, ... -- カラムが続く FROM `project.events_*` パヌティション: Date クラスタ: event_name, new_event_name(埌述), platform パヌティション分割テヌブル䜜成埌は ク゚リスケゞュヌリング を利甚し、毎日定期実行で指定範囲の日数を䞊曞きするような圢でむベントログをアップデヌトしおいたす。 -- 盎近3日以内のむベントログを䞊曞きする DECLARE start_date_interval INT64 DEFAULT 3 ; DECLARE end_date_interval INT64 DEFAULT 0 ; DELETE FROM `product_firebase_analytics.events` WHERE DATE (event_time, ' Asia/Tokyo ' ) BETWEEN DATE_SUB( CURRENT_DATE ( ' Asia/Tokyo ' ), INTERVAL start_date_interval DAY ) AND DATE_SUB( CURRENT_DATE ( ' Asia/Tokyo ' ), INTERVAL end_date_interval DAY ); INSERT INTO `product_firebase_analytics.events` SELECT event_date, TIMESTAMP_MICROS(event_timestamp) AS event_timestamp_micros, ARRAY_TO_STRING( [event_name, ( SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = ' id ' )], " _ " ) AS new_event_name, platform, ... -- カラムが続く FROM `project.events_*` WHERE REGEXP_EXTRACT(_TABLE_SUFFIX, r ' [0-9]+ ' ) BETWEEN FORMAT_DATE( " %Y%m%d " , DATE_SUB( CURRENT_DATE ( ' Asia/Tokyo ' ), INTERVAL start_date_interval DAY ) ) AND FORMAT_DATE( " %Y%m%d " , DATE_SUB( CURRENT_DATE ( ' Asia/Tokyo ' ), INTERVAL end_date_interval DAY ) ) 2. new_event_nameの導入 Google Analytics for Firebase の仕様䞊、むベント名は最倧500たでしか定矩できたせん。 カゞュアルに新芏むベントを定矩しすぎるず䞊限の500に到達しおしたい、新芏むベントの蚈枬ができなくなりたす。 むベント数の䞊限が500を超えないために、むベント名を䞀意にするのではなく、 event_params にむベントを識別できる id(STRING) を含めお、パヌティション分割テヌブル䜜成時に new_event_name ずしお定矩しおいたす。 䟋えば䞋蚘のようなむベント名ずIDの堎合、 new_event_name はtest_hogeになりたす event_name: test event_params.id: hoge new_event_name: test_hoge new_event_name はパヌティション分割テヌブル䜜成時に event_name ず id を結合するこずで、新しいむベント名ずしお定矩するこずで実珟しおいたす。 ARRAY_TO_STRING( [event_name, ( SELECT value.string_value FROM UNNEST(event_params) WHERE KEY = ' id ' )], " _ " ) AS new_event_name new_event_name によっお、䞋蚘のようなメリットが埗られたす。 event_name はtest, imp, tapなど汎甚的なむベントのみを定矩しお䜿い回すため、むベント名の定矩数で500を超えるこずがなくなる クラスタに new_event_name を指定しおいるため、分析する偎は new_event_name を条件に指定するこずでscan量を削枛するこずが可胜 DynamoDBやRDSをBigQueryにSync クラシルリワヌドではむンフラ環境をAWSで構築しおいるため、ナヌザヌのデヌタはRDSやDynamoDBに保存されおいたす。 これらのデヌタをアプリから送信したむベントログず結合しおBigQueryで分析をしたいニヌズがでおきたす。 珟圚は Digdag ず Embulk を利甚しお、1日1回定期実行でBigQueryにSyncをしおいたす。 これらはAWS ECSの タスクスケゞュヌリング で実珟しおいたす。 倚くのテヌブルは党䜓曎新をしおいたすが、䞀郚テヌブルはレコヌド数が倚くなっおいるため差分曎新をしおいたす。 差分曎新の察応に぀いおは説明が長くなっおしたうため、たた別のテックブログで話せればず思いたす。 運甚面に関しおは、珟状倧きな課題はないもののバッチ凊理が倱敗した時の調査やリトラむなどの運甚工数もかかり始めおはきおいるので、自前のETLフロヌではなく trocco や Fivetran などのSaaS ETLツヌルも怜蚎しおいたす。 Snowflakeの掻甚 メむンのデヌタ基盀はBigQueryですが、䞀郚で Snowflake を利甚しおいたす。 Snowflakeを利甚するこずになった背景は䞋蚘2぀です。 クラシルのデヌタをクラシルリワヌド開発郚で分析可胜にするため 珟状dely瀟では各事業郚ごずに技術遞定をしおいたす。 クラシルではAWS Athena, Snowflakeを利甚しおデヌタ分析をしおいたす。クラシルリワヌドでは今たで説明しおきたしたがBigQueryをメむンで利甚しおいたす。 しかし、事業郚が分かれおいるため、クラシル偎のデヌタを分析するずきに䜕か問題が発生するずクラシルのデヌタ゚ンゞニアに郜床䟝頌する運甚コストが発生しおいたした。 この課題を解消するために、クラシルリワヌド偎でSnowflakeをアカりントを䜜成し、Snowflakeの デヌタシェアリング を利甚するこずで、クラシルリワヌド開発郚でクラシルのデヌタを自由に分析するこずができるようにしおいたす。 2. 䞀郚のクラシルのテヌブルをBigQueryに゚クスポヌトしたいため クラシルリワヌドでは クラシルチラシ にた぀わる情報もナヌザヌに提䟛しおいたすが、チラシ情報のテヌブルがクラシル偎にあるため、BigQueryで分析を完結するこずができたせん。 䟋えば、クラシルリワヌド偎でどの店舗のチラシを芋られたかを分析したい堎合、どうしおもBigQueryに店舗のマスタヌデヌタが必芁になっおきたす。 そのためクラシルチラシのデヌタ(e.g. 店舗情報)をクラシルリワヌド偎のBigQueryに栌玍するために䞋蚘のようなフロヌを構築するこずで実珟しおいたす。 Snowflake(クラシル) -> Snowflake(クラシルリワヌド) -> Google Storage(クラシルリワヌド) -> BQ(クラシルリワヌド) クラシルでのデヌタをBigQueryに゚クスポヌトするこずで、クラシルリワヌド偎ではBigQueryのみで完結しおチラシ情報を分析するこずが可胜ずなっおいたす。 BIツヌル(Redash, Looker) 最埌にBIツヌルに぀いお説明したす。 Redash 珟状はセルフホスティングで Redash 甚のEC2むンスタンスを立おお、SQLク゚リを曞いお分析をするこずが倚いです。 しかしSQLク゚リは人によっお曞き方が異なる、数倀出しの刀断が間違える可胜性があるため、SQLク゚リをGitHubのRepositoryで管理しおレビュヌをする䜓制をずっおいたす。 こちらはバむセルさんの Redashのク゚リ管理方法 を参考にしおいたす。 Redash repositoryのフォルダ・ファむル構成 フォルダ構造 ├── README.md ├── csv // ク゚リ名などをcsv管理 ├── queries // ク゚リ管理 ├── requirements.txt └── scripts // Redashに反映甚のスクリプト csv name,data_source_id,query_id query_test_name,1,29 CSVではク゚リ名、デヌタ゜ヌスID, ク゚リIDのみを最䜎限管理しおいたす。 git管理䞋のSQLク゚リをRedashに反映 PRがマヌゞされたタむミングでGitHub Actionsを実行し差分があるク゚リのみをRedashに反映させるようにしおいたす。 GitHub Actions ステップ実行順 倉曎があったク゚リの差分抜出( write_diff_query_only.sh ) Redashに反映( main.py ) write_diff_query_only.sh #!/bin/bash # write_diff_query_only.sh # PR差分のみをcsv_query_list.csvに反映するスクリプト header = `head -n 1 csv/query_list.csv` current_commit = $GITHUB_SHA previous_commit = $( git rev-parse " ${current_commit} " \^ 1 ) query_ids = `git diff --name-only " $current_commit " " $previous_commit " | grep queries | grep -o ' [0-9]\+ ' | tr ' \n ' ' | ' ` query_ids = ${query_ids % | } echo " $header " > csv/diff_query_list.csv if [ ! -z " $query_ids " ]; then grep -E " ( $query_ids )$ " csv/query_list.csv >> csv/diff_query_list.csv fi # main.pyで差分のみを䞊曞きしお実行するため cat csv/diff_query_list.csv > csv/query_list.csv main.py # main.py import os.path from redash_client.client import RedashClient import csv import os class Query : def __init__ (self, base_path, name, data_source_id, query_id, schedule= None , description= 'generated by retail-redash-query' ): self.query_id = query_id self.name = name self.data_source_id = data_source_id self.schedule = schedule self.description = description path = 'queries/{0}.sql' .format(query_id) self.load_query(base_path, path) def load_query (self, base_path, path): with open ( '{0}/{1}' .format(base_path, path), 'r' ) as f: self.query = f.read() # Read query list def get_queries (): reader = csv.reader( open ( 'csv/query_list.csv' , 'r' )) queries = [] # Skip header header = next (reader) for row in reader: queries.append(Query( "./" , row[ 0 ], row[ 1 ], row[ 2 ])) return queries RedashClient.BASE_URL = os.environ[ 'REDASH_HOST' ] RedashClient.API_BASE_URL = os.environ[ 'REDASH_HOST' ] + "/api/" api_key = os.environ[ 'REDASH_API_KEY' ] redash_client = RedashClient(api_key) # Update queries for query in get_queries(): print ( 'QueryID: ' + query.query_id) try : redash_client.update_query( query.query_id, query.name, query.query, query.data_source_id, query.description ) except RedashClient.RedashClientException: print ( 'Error: ' + query.query_id) 珟状は差分があるク゚リのみをRedashに反映するように圱響範囲をずどめおいたす。 Lookerに぀いお RedashではSQLク゚リを曞くずいうハヌドルが残り続けるため、SQLク゚リをかけない非゚ンゞニアでも分析が可胜な䜓制にするため、珟圚は䞊行しお Looker にも移行䞭です。 さいごに クラシルリワヌドのデヌタ基盀に぀いお玹介したした。 デヌタ゚ンゞニアが䞍圚の䞭でも、分析基盀を構築しサヌビス改善に぀なげるこずができたした。 匕き続きデヌタを分析するこずでクラシルリワヌドを改善しおいきたいず思いたすので、よろしくお願いしたす。
Hi, I am Akane, a UI/UX designer at Kurashiru’s search team. This time I would like to talk about how our search team uses the UX mapping methods to organise, identify and prioritise our tasks from the product’s perspective by using “User story mapping”. 1. To identify the users’ goals. At this step, we will decide what’s our user’s goals. 2. Map users’ activities. List out key Activities, Steps and Details that are involved in the search function. By viewing the mapping, our team members could have a clear vision of each key activity, and follow up with steps users take during each activity and details. 3. Organise tasks for future release We have summarised all tasks that are possible to get improved for feature releases from left to right. Before discussing with PdM, I listed each potential task along with current screenshots as well as some detailed notes that could help us to visualise tasks. After discussing this mapping with PdM, we “finalised” tasks by each phase and priority. Because we are using Figjam’s sticker function, it is very easy for us to adjust the priority of each task, remove un-needed ones and add new ones as well. Here is an example of how we bring an “easy-to-use” search experience to our users. Before discussing with PdM, I will write down which area I would like to improve (WHAT), the reason (WHY), and how I plan to do it (HOW.) Here is the summary of why we decided to add the search bar to the home screen. Kurashiru currently has two types of users: Type 1: users who already know what they are looking for (search for ingredients that they already have in the fridge or at home, shopping before) User action: open app → input query from the home search bar → view result Most of Kurashiru's loyalty users are in this category. Type 2: users who don’t know what they are looking for, just want to browse some ideas (based on the ideas, they will go buy these essential ingredients, shopping after) User action: open app → Access search top feed → browse recommended keywords or content list → input query or click recommended keywords → view result These 2 types of users' needs and requirements are different, so we want to create the best user experience that would cover both our user's needs (create 2 different entry points for different user groups). For those Kurashiru’s loyal users, they need to take 2 steps in order to reach the search bar. After the UX adjustment, they could access the search bar once they open our app, imagining you try to find a recipe after a busy day of work or taking care of kids at home every day, this small UX improvement could save our user half of the time every day. By adding the “search bar” to the home feed, after the release, the data proves that most of our users are choosing to use the “search bar” on the home feed. After a certain period, the number of users who use the “home search bar” and “search tab” are showing a stable trend. So, here is how our team prioritise and manages our tasks by using the UX mapping method. In the end, these methods are just theories, we need to adjust how we will use them to match our team's needs. Thank you for reading, see you next time. :)
Hello, my name is Niko, and I am currently working in Kurashiru's data enabling team as a newly joined data engineer. While I'm enthusiastic about learning Japanese, my proficiency with Japanese particles is still a work in progress (笑). For this reason, I have decided to write this blog in English. Preface At Kurashiru, we use dbt (data build tools) as our platform to handle data transformations from the data lake to our data warehouse. dbt is a helpful set of tools and frameworks that let us create transformation queries in line with software engineering principles. Gone are the days of dealing with complicated queries on our data platform. With dbt, we can manage and "engineer" our data just like regular software development. Since we started using dbt, our productivity in data modeling has significantly improved, which we find very beneficial. dbt also provides us with useful tools like "slim CI" for Continuous Integration. In this blog, I'll explain what SLIM CI is and why it's essential for our workflow. If you want to know more about dbt, you can explore the official documentation here: docs.getdbt.com dbt CI Job In Continuous Integration (CI), the process involves automatically building and testing new code whenever a developer tries to merge it into the main repository. This principle applies to dbt too. When a developer makes a Pull Request (PR) in a dbt repository, it's essential to follow CI practices. Doing so helps us avoid broken queries in our Production database and maintain good code quality. Now, let's see the flow of CI job that dbt performs using an illustration: dbt's CI Job Let's imagine the Master branch codes are linked to the Production environment. When a Pull Request (PR) is made, the CI JOB will duplicate the existing data model from Production to a temporary environment. Then, it will build and test the copied model along with the changes from the PR. So far, this process works fine for application code because it usually requires only a small amount of data for building and testing new codes. However, the problem arises when dealing with data models in data modeling works. It demands a significant amount of data and incurs high data processing costs for just one PR. Therefore, we need to find a way to improve this process and reduce the overall expenses. Slim CI Luckily, dbt offers us SLIM CI, which plays a crucial role in this situation. When we switch from the default CI Job to SLIM CI, our CI workflow transforms into the following: dbt's Slim CI Job In the new workflow, the CI Job doesn't have to copy all existing models from the Production environment for building and testing. Instead, it only creates the data model that has changed in the PR and refers to other required dependencies (like source tables or views for JOIN, UNION) already present in the production environment. This way, the process becomes much faster and more cost-effective since we only create what is necessary. dbt's SLIM CI achieves this by using a built-in powerful feature called "defer." With "defer," a single model can be built without the need to rebuild all its dependencies in the CI temporary environment. This efficient approach saves time and resources, making the whole data modeling process smoother and more efficient. To Defer or Not Defer So, what is "defer"? To grasp the concept of "defer," let's first understand how dbt functions. To build our data models using dbt, we typically run this command # first run dbt build Under the hood, dbt will do something like this: dbt command under the hood When we examine the final step of the dbt process, we notice that dbt always produces artifacts. These artifacts represent the most recent state of the current data models in the target database or data warehouse. Now, how does "defer" come into play? Well, "defer" uses these artifacts to check if there are any differences between the dbt runs and the existing state of the target database or data warehouse, kind of like a DIFF logic. To enable "defer" in dbt, we can include some flags to the previously run first run command, which looks something like this: # second run # --select state:modified # means only select changed states compared to the previous state dbt build --select state:modified --defer --state path_to_first_run_state With this approach, dbt constantly checks the previous state and only builds models that have been changed from the successful previous run of dbt. When we include this command in a Job that triggers when a Pull Request (PR) is requested, dbt refers to it as "SLIM CI". Example Imagine we work at a beef bowl restaurant, and our responsibility is managing the restaurant's data. In the data warehouse's production environment (DBT_PRD), we have two models named meat and rice : Model in our production datawarehouse We want to create a new model called "meat_rice_menu" by combining the data from the two existing models, meat and rice . This new model will be represented in a chart like this: meat_rice_menu model default CI Job Let's proceed with the PR and use this model plan. First, we'll run the regular dbt CI Job without defer/SLIM CI. During this process, dbt will create a new temporary schema for each PR that is being tested. Fortunately, dbt will always log the activities of the run. Here's the completion message from dbt's CI logs: Completion status dbt CI job There, we can see that dbt made 2 table models and 1 view model. To make sure, let's look at our current temporary PR schema. When we check the temporary PR schema, we'll see that it did create all three models, both the parent and child models: CI without defer When we take a look at the definition, we can see that the newly created model was referencing the temporary schema: Newly created model referencing temporary models. SLIM CI Job Now, let's try the PR again, but this time, we'll use defer/SLIM CI. We already have artifacts that show the current state from the production's dbt Job runs. When we run the PR job with defer/SLIM CI, let's look at the same finished log message that dbt always creates for every run: Completion status dbt SLIM CI job We notice that it only created one view model. When we check the PR's temporary schema, we see that only the new model is created, which is meat_rice_menu and it didn't duplicate the existing tables: CI Job with Defer (Slim CI) When we see the definition again, we can see that now it referencing the production environment (DBT_PRD): Newly created model referencing production's models. By referring directly to the production models instead of copying them, we can greatly reduce the costs of our PR. This approach avoids unnecessary duplication, and we only focus on building and testing the changes needed for the new model. As a result, the process becomes more efficient and cost-effective. Summary Slim CI is a powerful dbt feature that can save time and reduce costs during the build and testing of models in the CI workflow. By using defer, Slim CI can identify differences between the current data warehouse state and the changes in PR requests. This boosts our productivity since we don't have to wait long for PRs to be built and tested before merging them to the master branch. Today, I introduced one of the powerful features of dbt in this blog. However, we don't want to stop there. In line with our commitment to continuous improvement (KAIZEN) and one of our value which is good to great , we aim to enhance our data infrastructure further. Thank you for reading this blog, and stay tuned for more data engineering adventures ahead! References Continuous integration in dbt Cloud | dbt Developer Hub Defer | dbt Developer Hub Using dbt Deferral to Simplify Development | Infinite Lambda http://careers.dely.jp careers.dely.jp
もうすぐ8月で猛暑も超えお酷暑の季節になりたしたね🥵  毎日゚アコンで涌みながら最近はEMずしお仕事しおいる「みうら」です。お久しぶりです。 前回私の曞いたブログ蚘事では、採甚掻動に関わっおいたず蚘茉しおいたした。 転職掻動や遞考フロヌぞの参加は自身でも行ったこずはあるのですが、実は採甚掻動を業務の䞭心ずしお掻動した経隓はなく、初めおの経隓でした。 そんな採甚ビギナヌな私でしたが、前期では私が関わった採甚掻動で数名゚ンゞニアがありがたいこずにゞョむンしおくれたした🙌 ずいうこずでその䞭途採甚掻動をする際に行ったこずを䞀郚玹介しようず思いたす。 ゚ンゞニア採甚の方法 これを芋おいる方ぱンゞニアだず思うので倧䜓むメヌゞ぀いおいる方は倚いず思いたすが、少し゚ンゞニア採甚の方法を玹介したす。 匊瀟では䞻に倧きく分けるず3぀の方法で行っおいたす。 ダむレクトリクルヌティング Findy/Wantedly/Green/forkwell ずいった転職マッチングサヌビス。 サヌビス䞊で䌁業が候補者を探しおメヌルのやり取りをするサヌビス。 䌚瀟ず個人を盎接繋いでやり取りできるのが特城。 転職゚ヌゞェント レバテック/Geekly/リクルヌト ずいった転職゚ヌゞェントサヌビス/䌁業。 䌚瀟ず個人の間に仲介で入っおくれるこずで、䌚瀟ず個人間のマッチングコストを担っおくれるのが特城。 自瀟サむト採甚/リファラル採甚 自瀟のHPからの応募や、瀟員玹介から䌚瀟ず個人を盎接繋いでやり取りする、他瀟を挟たない圢の採甚。 コストが安かったり、リファラルだず入瀟埌の期埅倀が合いやすいなどが特城。 ゚ンゞニア採甚に参加した時に感じた課題 採甚に参加した時は右も巊も分からず、たずは内定を取るために候補者の方々をリストアップし、いわゆる母集団圢成から始めたのですが、進めおいくうちに匊瀟の採甚業務には以䞋のような課題があるこずに気づき始めたした。 採甚担圓の残業が倚い 求人祚が敎備されおおらず蚘茉内容がバラバラ 二次遞考突砎率が䜎い 採甚の進め方が定型化されおいない リクルヌタヌからするず残業が倚かったり業務フロヌが敎っおいないこずはあるあるなのかもしれたせんが、採甚業務党䜓ずしお工数芳点での改善点があったり、フォヌマットが揃っおいないこずで䜙蚈に工数が掛かっおいたり、工数や業務フロヌを改善しなければより䞊の採甚業務は行えない感觊をその時は感じおいたした。 採甚戊略の策定ず改善 課題は倚く芋぀かったので、あずはどう解決しおいくかです。 䞊蚘課題を螏たえお、以䞋を戊略ずしお進めおいたした。 工数ず時間削枛 募集(母集団)を増やす 遞考䜓隓の改善 特に、゚ンゞニア採甚は工数がかなり掛かるこずがわかったので、 たずは工数ず時間削枛から改善するこずにしたした。 業務ずしおは内定を取らないずいけないのですが、たずは既存の業務を改善しないず内定を埗るこずが難しいず匷く感じおいたした。 䞊蚘の戊略を元に、前期の採甚掻動では倚くの改善を行いたしたが、玹介しきれないので、今回は戊略の内、「工数ず時間削枛」で行ったこずに぀いお玹介したす。 工数ず時間削枛 採甚には候補者1名に察しおもかなり人ず工数が掛かっおいたす。 匊瀟では最終遞考たでに倧䜓以䞋の工数が候補者1名蟺りに掛かっおいたす。 スカりタヌ: 15分 リクルヌタヌ: 4時間 ゚ンゞニア3名: 4時間 マネヌゞャヌ: 1時間 CTO: 1時間 箄10時間今回改めおたずめおみたしたが、かなりの工数が掛かっおいたすね 😰 内定たでずなるずもう3〜4時間ほどは工数が掛かるこずでしょう。 これを枛らしたり、スムヌズにするずいった改善をするこずは、ずおも重芁で倧きい話になっおくるわけです。 候補者ずのスケゞュヌル調敎簡略化 今たでのフロヌだずメヌルのやり取りの途䞭で、eeasyずいう日皋調敎ツヌルをスカりタヌから採甚チヌムに発行しおもらわないずいけなかったのですが、実はこれに問題がありたした。 スカりト送信時に日皋調敎URLを送れず、候補者から面談参加垌望をもらった埌に発行するため、メヌルやり取りに時間が掛かる 日皋調敎URLを発行するためだけで採甚チヌムに䟝頌が必芁ずなり、時間が掛かる 日皋調敎に採甚チヌムを挟むこずで無駄な工数ず時間がかかっおいたずいうこずです。ここはスカりト送信ず同時に日皋調敎URLを送るこずで改善できないかず考えおいたした。 改善のためにeeasyのプランを倉えたり他のツヌルも怜蚎したのですが、Googleワヌクスペヌスを契玄しおいたこずもあり、远加費甚無しで䜿えるこずもあっお、Googleカレンダヌの予玄スケゞュヌルで察応したした。 support.google.com 现かい蚭定郚分で融通が効かず、䜿いづらい郚分もありたすが、今の所問題なく䜿えおおり、スカりタヌが採甚チヌムをたたずに玠早く日皋調敎ができるようになっおいたす🙌 ゚ンゞニアが送っおいたスカりトをやめ、スカりタヌからスカりトを実斜 ダむレクトスカりト媒䜓では、゚ンゞニアが盎接スカりトを送るほうがよいだろう、ずいう刀断の元、゚ンゞニアがスカりトを送信するルヌルが有りたした。しかし、ここにも問題がありたした。 ずいうのも、゚ンゞニアは本来メヌルを曞くのに慣れおいないんですね。䞀筆メヌルを曞くのにも時間が掛かりたすし、スカりトが本来の業務でもない スカりトメヌルを曞くより開発したい思いがありスカりトメヌル䜜成も䞊達しない ずいうこずで、廃止したした。 代わりに゚ンゞニアは候補者のチェックに専念し、専門のスカりタヌがスカりトメッセヌゞを送るように倉曎したした。 このおかげでスカりト通数を増やすこずができ、゚ンゞニア偎の負担も枛らせおwin-winで良かったず思いたす🙌 採甚チヌムにコヌディネヌタヌ職を定矩 瀟内には採甚担圓ずしおリクルヌタヌ職が存圚するのですが、そのリクルヌタヌ職がコヌディネヌタヌ業務ずしお、候補者ずの調敎業務も行っおいたした。これも課題のポむントでした。 これが原因でリクルヌタヌ職の残業時間がずおも倚い状況ずなっおいたり、本来行いたい改善業務に集䞭出来ない問題がありたした。 これを改善するために、採甚のアシスタントの方にコヌディネヌタヌ業務の教育を実斜し、リクルヌタヌの調敎業務をコヌディネヌタヌ職に移管したした。 朝䌚15分の認識合わせをするだけで、リクルヌタヌ職の負担を枛らし、リクルヌタヌ職が行うよりも候補者ずの調敎業務をよりスピヌディにするように倉えたした🙌 珟圚は䜓制が少し倉わっおしたったため、圓時のコヌディネヌタヌの運甚はそのたたずはいかないのですが、珟圚もアシスタントの方はコヌディネヌタヌ業務を掻かしおもらっおいたす。 たずめ 今回ぱンゞニアが゚ンゞニア䞭途採甚業務を担圓するにあたっお改善したこずの䞀郚を玹介したした。 ゚ンゞニア採甚は難しく厳しい時代ず蚀われおいたすが、逆に蚀うず瀟内も瀟倖も正解がわかっおおらず、そのわからない状況を正解に持っおいく面癜さがあるず思いたす😄 私も採甚掻動は業務ずしお行うのは初めおでしたが、数名゚ンゞニア採甚に繋がったなど、無事成果が出せおよかったず思いたす。 採甚掻動は関わる人数が倚く、工数削枛や業務フロヌ改善が効きやすい業務だず思いたす。これを読んだ方も参考に改善しおみたり、ノりハりをシェアいただけるず嬉しいです。 最埌に 最埌に、匊瀟ではSRE職を積極的に募集しおいたす。 クラりドむンフラ経隓者や、AWSを経隓したいサヌバサむド゚ンゞニアの方、良ければお話䌺っおみたせんか高トラフィックサヌビスである、クラシルのむンフラに興味あれば良ければお話したしょう以䞋リンクから応募いただけるず嬉しいです。 herp.careers 採甚情報はこちらです careers.dely.jp