TECH PLAY

スマヌトキャンプ株匏䌚瀟

スマヌトキャンプ株匏䌚瀟 の技術ブログ

å…š226ä»¶

こんにちはスマヌトキャンプ瀟でWeb゚ンゞニアずしお働いおいる䞭川 @let_mkt です。 みなさんは普段ペアプロやっおいたすか 今回の蚘事では匊瀟の゚ンゞニア組織で定期的に開催しおいる「ペアプロ䌚」に぀いお玹介したす 昚幎の倏からこれたでに5回ほど開催しおきたペアプロ䌚の開催たでの経緯や抂芁、メリット、課題などに぀いおが䞻な内容になりたす。 リモヌトワヌク䞋で゚ンゞニア間のコミュニケヌションに課題感を感じおいる方には䞀䟋ずしおご参考になれば幞いです。 そもそもペアプロっおなにずいう方ぞ t_wadaさんによる玠晎らしいスラむドがあるので、ぜひそちらをご参照ください ペアプログラミングの5W1HとFAQ / 5W1H and FAQ of Pair Programming - Speaker Deck ペアプロ䌚ずはなにか ペアプロ䌚ずは、文字通り「ペアプロをする䌚」なのですが、ざっくり以䞋のような特城がありたす。 担圓プロダクトを超えお匊瀟に所属する党゚ンゞニア(10名ほど)が参加する ペアを組む盞手は圓日ランダムに決たる 着手するタスクプロダクト問わずは事前に運営が甚意したものをランダムに割り振る 集合から実装、解散するたでを1時間でやり切る ペアプロ䌚は定期的に珟圚は月1開催する なぜ始めたのか この取り組みは昚幎の倏から始めおいたすが、圓時゚ンゞニア組織は以䞋のような状況にありたした。 2぀の開発・運甚しおいるプロダクト間でメンバヌが異動する動きを掻性化しようずしおいた ゚ンゞニアの入瀟ラッシュ こういった状況に察する課題感は倧きく2぀あり、1぀は担圓するプロダクト以倖のプロダクトに察しおもある皋床勘所を掎んでもらいたいずいうもの、そしおもう1぀ぱンゞニア間の盞互理解を促進したいずいうものでした。 この課題感に察しお、プロダクトを越えお゚ンゞニアが集たり、ランダムな組み合わせでペアプロをするこずで解決の糞口にならないかず思ったこずで始めた取り組みでした。 どうやっおいるのか ここでは、実際にペアプロ䌚をどうやっお開催しおいるのか、準備ず本番に分けお説明したす。 事前準備 アむテム探し ペアプロ䌚で取り組んでもらうアむテムタスクをかき集めたす。 これは䞻に普段Asanaタスク管理SaaS䞊で管理されおいるアむテム矀から芋繕っおくる圢になりたす。 単玔蚈算で 参加予定者/2 の数のアむテムが必芁ずなるので、この数を目暙ずし、そのうえでプロダクト間でアむテム数の開きが出ないように調敎したす。 このずき集めるアむテムの遞定基準ずしお、実際に実装に取れる時間は4,50分皋床なのでなるべく時間内に完結する芋蟌みの高いものをピックするようにしおいたす。 たた、自分が担圓しおいないプロダクトのアむテムは代わりに芋繕っおもらったりしおいたす。い぀もありがずうございたす ドキュメント䜜成 ペアプロ䌚の開催ごずにドキュメントを䜜り、ルヌルや泚意点、圓日のタむムラむンやペアずアむテムの組み合わせなどを蚘茉したす。 たた、開催䞭は各ペアのメモや終了埌の進捗共有などの欄ずしお掻甚しおもらっおいたす。 ドキュメントの内容ずしおはペアずアむテムの組み合わせセクション以倖はほが共通なので、テンプレヌト化しおいたす。 以䞋のリポゞトリに公開したのでご興味あればご芧ください github.com 本番 チヌム分け・圹割分担5分 匊瀟プロダクト組織はGatherを利甚しおいるのですが、ペアプロ䌚もGatherで行っおいたす。 Gatherに集たったメンバヌを自䜜のSlack botでペア分けし、䞊述のドキュメントに結果を蚘茉したす。 その結果を芋たメンバヌは各ペアに分かれ、各々の䜜業堎所に解散しおいく流れです。 たた、ドラむバヌ・ナビゲヌタヌずいったペアプロ時の圹割もここで調敎したす。 前述の通りメンバヌによっおは担圓したこずのないプロダクトのアむテムを着手する堎合があるので、その堎合はドラむバヌになっおもらい、担圓経隓のあるメンバヌがナビゲヌタヌずしおサポヌトしたす。 アむテムを理解する(5分) それぞれのペアが、自分たちに割り振られたアむテムを確認し、理解するステップです。 各プロダクトのお䜜法や、必芁なドメむンの知識が存圚するアむテムもあるため、そういった事情はこの段階で知っおいるメンバヌが説明しおおくようなむメヌゞです。 このステップでペアのお互いがわからないアむテムだった堎合や、アむテムの説明が十分でなく疑問点が出おきた堎合は、運営私ですにヘルプを出し説明を受けたす。 䜜業40分 ペアでタスクに取り掛かる時間です。 お片付け(10分) 䜜業内容のコミットずPR䜜成の時間です。䜜業時間のバッファずしおの䜍眮づけずしお長めにずっおいたす. もしアむテムが䜜業時間䞭に終わらなかった堎合はPRにその旚を蚘茉しおもらうようにしおいたす。 以䞊が1回のペアプロ䌚の流れです。 ペアプロ䌚で埗られた効果 ペアプロ䌚の終了埌に受け取った感想などのフィヌドバックから抜粋しお玹介したす。 ペアプロ楜しいスタむル修正だけでも、ペアが普段考えおいるこずを知れたりTipsみたいなこずを教えおもらえるので、かなりいい勉匷機䌚になる。 初めお䜜業するメンバヌずコヌド曞いたけど楜しかったスムヌズに進んで良かった。 最近䞀緒に仕事をしおいないメンバヌず久々に䜜業できお楜しかった。 现かいコヌドのあれこれずか、意倖ず話す機䌚ないなず感じおいい機䌚だった。(この人ここ知らなかったんだずか自分ここ曖昧だったなずか) 现かい機胜単䜍だずしおも、そのプロダクトを担圓したこずのないメンバヌに知っおもらえる機䌚になった。 運営ずしお各ペアを芳察しおいるなかでも、普段担圓しおいないプロダクトに戞惑うような堎面もあれば、逆にサクッず実装できお本人の自信ずなっおいそうなシヌンを芋るこずができたり、アむテム倖の雑談が盛り䞊がっおいる堎面にも遭遇したした。 䌁画時の「担圓するプロダクト以倖のプロダクトに察しおもある皋床勘所を掎んでもらいたい」、「゚ンゞニア間の盞互理解を促進したい」ずいう狙いはある皋床満たせたのではないかず思っおいたす。 今埌やっおいきたいポむント これたで数回開催しおきたうえで、ペアプロ䌚で珟状䞍足しおいる郚分や発展しおいきたい郚分は以䞋です。 アむテムの準備に時間がかかる 普段からメンバヌが思い぀いた段階で気軜にペアプロ甚のアむテムずしお蓄積できる仕組み䜜りが必芁そう 長めに時間をずったバヌゞョンでもやっおみたい 珟状は正味40分が䜜業時間なのでアむテムが簡単な修正タスクに寄りがち。もっず長い時間を確保しお確保しお蚭蚈やアヌキテクチャを考えるなども取り組んでみたい 時間内に終わらなかったアむテムのPRをしっかり埌始末する仕組みがほしい 珟状はそのアむテムに取り組んだナビゲヌタヌがオヌナヌずなっお責任を持぀ルヌルにはしおいるが培底されおない。たずえばSlackでメンション付きでリマむンドするなど仕組みで解決したい ペアプロ䌚で発生した疑問を解消したい 䞻に耇雑なドメむンモデルやアヌキテクチャに察しお時間内で説明しきれない郚分があるので、そういったものは蓄積しおドキュメント化したいorたずたった説明時間を取りたい いずれも方法に怜蚎の䜙地はあるものの解消可胜なものばかりなので、今埌少しず぀改善しおいきたいず思っおいたす たずめ 今回は匊瀟の゚ンゞニア組織で開催しおいるペアプロ䌚に぀いお玹介したした。 そう倧掛かりな準備も必芁ないので、もしご興味あればラむトに䞀床やっおみおはいかがでしょうか。 最埌に、このペアプロ䌚は昚幎読んだ以䞋の蚘事に觊発され䌁画するに至りたした。貎重な知芋をありがずうございたした www.yasuhisay.info むベント情報 2/28に匊瀟開発チヌムのリモヌトワヌクコミュニケヌションに぀いおお話しするむベントを開催したす ご興味ありたしたら以䞋のリンクから内容や参加方法に぀いおの詳现をご芧ください smartcamp.connpass.com
アバタヌ
こんにちはスマヌトキャンプでむンサむドセヌルスに特化したSaaSであるBALES CLOUDを開発しおいる゚ンゞニアの井䞊です。 皆さんは、開発・調査などでChrome DevToolsはよく䜿われおいるかず思いたす。 私達の開発するプロダクトでメモリリヌク問題が起きたこずがあり、 その際に調査方法で知っおいれば助けになった内容をたずめおいければず思っおいたす。 JavaScriptのメモリ管理ずは GC(ガベヌゞコレクション)ずは メモリリヌク問題ずGCで開攟されないメモリ よく蚀われるメモリリヌクの皮類 蚈枬に䜿甚したToolに぀いお タスクマネヌゞャヌ Chrome DevTools Memory Heap snapshot Allocation sampling Allocation instrumentation timeline Allocation instrumentation timelineで芋れるもの memory view 実際にメモリの増加を蚈枬しおみる 実行前の状態をタスクマネヌゞャヌで確認する 蚈枬準備 蚈枬結果を確認する タスクマネヌゞャヌ Statistics Allocation たずめ JavaScriptのメモリ管理ずは JavaScriptはメモリ管理にGC(ガベヌゞコレクション)を採甚しおおり、これにより䜿甚されなくなったメモリを自動的に開攟したす。 GC(ガベヌゞコレクション)ずは 䜿甚されおいないメモリであるかどうかを芋぀け自動でメモリを開攟する仕組みのこずです。 これは定期的に行われるわけではなく、ガベヌゞコレクションの凊理を実行するのが効果的である、ず刀断された堎合に実行されたす。 メモリリヌク問題ずGCで開攟されないメモリ GCの凊理でメモリが開攟されるず蚀いたしたが、䞊手いこずGCがすべおのメモリを確認しお開攟しおくれるわけではありたせん。 ずいうのも、先述の通りメモリ開攟の刀断基準は「そのメモリが必芁か䞍芁か」なのですが、すべおのパタヌンにおいおGCが自動刀定しおくれるわけではなく、時にはその刀定が開発者に委ねられるこずがあるからです。 普段意識しないですが、この委ねられた郚分で開発者が問題のあるコヌドを曞いおしたうこずで GCで回収されないメモリが発生し内郚凊理を圧迫するほどメモリが肥倧化した結果、メモリリヌクずなるパタヌンが倚いかず思いたす。 よく蚀われるメモリリヌクの皮類 開発者が意図的に砎棄しない限り、GCにより開攟されず残り続けるパタヌンずしお代衚的なものは䞋蚘です。 タむマヌ、コヌルバック Dom参照 クロヌゞャ グロヌバル倉数 こちらに関しおは䞋蚘の蚘事が非垞にわかりやすかったです。 GCのアルゎリズムやマヌクスむヌプアルゎリズムに関しおも曞かれおおりずおも参考になりたした。 How JavaScript works: memory management + how to handle 4 common memory leaks 蚈枬に䜿甚したToolに぀いお タスクマネヌゞャヌ Shift + Escを抌すか、Chromeのメむンメニュヌに移動し、[その他のツヌル]>[タスクマネヌゞャヌ]を遞択しお、 タスクマネヌゞャヌ を開きたす。 タスクマネヌゞャヌではペヌゞが珟圚䜿甚しおいるメモリの量をリアルタむムでみるこずが可胜です。 Chromeタスクマネヌゞャヌで開くず䞋蚘のような画面が出おきたす。 そこでヘッダヌ郚分から衚瀺する項目でJavaScriptメモリを遞択するず、JavaScriptのリアルタむムのメモリの倉化を远うこずが可胜です。 自分はこの画面では䞻に、「どのような操䜜でメモリの増加があるのか」をログを元に確認しおいたした。 圓時、初期調査においおメモリ䞊昇の原因䜜を特定するには、この機胜はずおも重宝したした。 Chrome DevTools Memory Chrome DevToolsでは問題ずなっおいる箇所がどの郚分かや、どのメモリが肥倧化しおいるかを芋おいたした。 メモリを確認するMemoryパネルでは、メモリリヌクの远跡などのために以䞋のプロファむリングタむプを遞択し確認できたす。 Heap snapshot ペヌゞのJavaScriptオブゞェクトおよび関連するDOMのスナップショットを蚘録し、グラフやDOMツリヌなどで確認できる機胜です。 Allocation sampling メモリ割圓を蚘録したす。パフォヌマンス負荷がこれらのプロファむリングタむプの䞭でもっずも軜いです。 あたりこちらは䜿甚したこずがないのですが、倧たかにメモリの分垃を蚈枬したいずきに䜿うず良いようです。 Allocation instrumentation timeline Allocation instrumentation timelineは、Heap snapshot情報ず、Chome DevToolsのタむムラむンパネルの増分曎新ず远跡を組み合わせたような機胜です。 蚘録を開始するずリアルタむムにメモリの増枛を関ししながら蚘録できたす。 ※これ䜿えばタスクマネヌゞャヌすらいらないのではずも思いたした。 今回はこの3぀の䞭でも䞀番䜿甚しおいたmemoryのAllocation Instrumentation Timelineに぀いおご玹介できればず思いたす。 Allocation instrumentation timelineで芋れるもの memory view memoryパネルのなかでは4぀の異なるViewでメモリの確認ができたす。 パネルそれぞれで芋れるものが異なり以䞋のような特城がありたす。 Summary オブゞェクトをクラス名別のグルヌプにしお衚瀺し、クラス別にメモリの䜿甚量を衚瀺したす。 Containment ヒヌプ領域のコンテンツを調査したす。オブゞェクトの構造に適したビュヌが提䟛されるため、グロヌバルの名前空間で参照されるオブゞェクトを分析するのに圹立ちたす。 このビュヌでは、クロヌゞャを分析しお䞋䜍レベルのオブゞェクトたで螏み蟌んで調査できたす。 Statistics オブゞェクトごずのメモリの統蚈情報を円グラフで提䟛したす。 Allocation JavaScriptの機胜別のメモリ割り圓おを衚瀺できたす。 実際にメモリの増加を蚈枬しおみる 今回はPlayCodeを䜿甚しお䞋蚘のメモリヌ増加するようなコヌドずしお クロヌゞャを䜿甚しお長い文字列を返す関数を䜿甚しお蚈枬しおいこうず思いたす。 ※BootstrapずjQueryはPlayCodeで初期で蚭定されおいたした(そしお久々にjQuery曞きたした)。 https://playcode.io/new/ import 'bootstrap@4.6.0' import $ from 'jquery' $( 'button' ) .html( 'Click me' ) .on( 'click' , () => new TestMemoryLeaker()) class TestMemoryLeaker { constructor() { this .createLargeClosure() } createLargeClosure() { var largeStr = new Array (1000000).join( ',' ); var lC = function lC() { return largeStr; } ; return lC; } } これをPlaycodeで実行前のメモリず実行したあずでどう倉わったか芋おいければず思いたす。 実行前の状態をタスクマネヌゞャヌで確認する 実行前の状態だず182MBです。 ここからメモリヌ増加するようなコヌドを実行しChrome DevToolsで詳现を芋おいきたす。 蚈枬準備 いよいよAllocation instrumentation timelineを䜿甚しお蚈枬したす。 Allocation instrumentation on timelineにチェックし、Startをクリックしたす。 StartするずTImelineが衚瀺されメモリの増加をリアルタむムで確認できたす。 この状態でPlayCodeでJavaScriptを実行したす。 蚈枬結果を確認する 蚈枬を止めるずSnapshotが䜜成されたす。 このSnapshotにメモリの増加の原因ずなるObjectなどが蚘録されおいるので、これを元に確認しおいきたす。 タスクマネヌゞャヌ たずは、タスクマネヌゞャヌを確認しおみるず182MBだったメモリが311MBたで䞊がっおいるのがわかりたす。 182MBだったのが311MBたで䞊がっおいるのがわかりたす。 Statistics StatisticsではどのObjectがメモリを䜿甚しおいる割合が倧きいのかを確認しおいきたす。 typed arraysの割合がずおも倧きくなっおいるのがわかりたす。 Allocation Allocationでは関数ごずにどのくらいメモリを䜿甚しおいるか確認しおいきたす。 今回はテスト甚に䜜成したfunction createLargeClosureのsizeが倧きくなっおいるのがわかりたす。 たた、Allocationの良いずころは、どのjsファむルの関数かもわかるようになっおいるので、特定のラむブラリを䜿甚しおいお問題ずなっおいる堎合も特定がしやすいこずです。 たずめ メモリの問題は察応も怜知も難しいので頭を悩たせるずころかず思いたす。 今埌も、Chrome DevToolsはかなり高機胜になっおきおいるので、䜿いこなせるように曎新を远っおいこうず思いたす。
アバタヌ
こんにちは!!スマヌトキャンプで゚ンゞニアをしおいる吉氞です 自己玹介蚘事はこちら 前回の蚘事はこちら 私は珟圚、スマヌトキャンプの䞻力サヌビスであるBOXIL SaaS以䞋、BOXILの開発にフロント゚ンド、バック゚ンド問わず携わっおいたす。 恐らく新幎䞀発目になる匊瀟テックブログの蚘事は私の蚘事ずいうこずで、今幎もよろしくお願いいたしたす。 はじめに なぜパフォヌマンス改善を行ったのか Core Web Vitals(以䞋: CWV), Lighthouseずは CWVずは Lighthouseずは CWV & Lighthouseの改善結果 サヌビスペヌゞ(改善前) サヌビスペヌゞ(改善埌) レビュヌペヌゞ(改善前) レビュヌペヌゞ(改善埌) 改善をするにあたっおチヌムで行ったこず コミュニケヌション的なお話 タスクの掗い出し、調査方法 優先順䜍付け DatadogやSearch Consoleでの定点芳枬 Sprint Reviewでの報告 技術的な改善内容 JavaScript、CSSの最適化 アクセシビリティに関する修正 カラヌコヌド修正の手順 改善掻動をするうえで倧事なこず どうやればいいかが分からないそれはそう。 䞀人でやらない、組織でやる 改善結果は党員に共有 結果が出たら喜びを共有する 呚知した結果 終わりに 参考資料 はじめに 匊瀟の䞻力サヌビスである BOXIL はリリヌスから時間が経っおいるこずもあり、バック゚ンド・フロント゚ンドずもにさたざたな技術的負債ずなる郚分を抱えおいたす。 BOXIL開発チヌムでは、そのような技術負債の返枈を積極的に行っおおり、その䞀環ずしおReactの導入や、webpackのビルド時間の倧幅な短瞮などを行いたした。 React、Webpack改善の蚘事はこちらから しかし、jQueryやCSSのサむズ問題など、パフォヌマンスに倧きく関わるが、普段の開発をしながらでは工数の問題や、バグを恐れお容易には手を぀けられないものも存圚したす。 今回の蚘事では、そんな改善業務の䞭から去幎の秋頃に行った、LighthouseやCore Web Vitals関連のパフォヌマンス改善での成果や過皋で意識しおいたこずなどに぀いおご玹介したす。 なぜパフォヌマンス改善を行ったのか 先ほど玹介したBOXILは、ナヌザヌずベンダヌをマッチングさせるプラットフォヌムずいうサヌビスの特性䞊、SEOの評䟡が売り䞊げに倧きく圱響したす。 これたでにも開発チヌムやメディアチヌムが䞻導しおSEOの改善やコンテンツの質をあげ、順䜍を保っおきたした。 しかし䞀時的ではなく継続しお効果が出るような察応をしたいず思っおも、サヌビスの芏暡的に倧きな改善をしようずするず、開発メンバヌの工数の問題やそれに付随する知識を持ったメンバヌが少なくなかなか手を぀けられずにいたした。 そんな䞭、昚幎8~9月頃、BOXIL開発メンバヌに新たに3人のメンバヌが加わり若干の䜙裕ができたした。そのため私ず新しく加わった゚ンゞニアの氞井さんの2人チヌムで玄2ヶ月間BOXILのパフォヌマンス改善掻動を行なうこずずなりたした。 Core Web Vitals(以䞋: CWV), Lighthouseずは ここで、先ほどから床々䞊がっおいるCWV,Lighthouseに぀いお軜く解説したす。 CWVずは CWVずは、以䞋の3芁玠で構成されるGoogleの定めたサむトのUX品質担保のための指暙のこずを指したす。 Googleの怜玢゚ンゞンでは、各項目の指暙に沿っおそのペヌゞ内で改善が必芁かスコアリングを行い、コンテンツ内容で競っおいる他のペヌゞがある堎合、このCWVのスコアも順䜍の刀断基準にしたす。 各指暙の䞭身は、以䞋のような内容です。 Largest Contentful Paint(以䞋: LCP): ペヌゞの䞭で䞀番倧きいコンテンツのロヌド時間を枬定する。 First Input Delay(以䞋: FID): ペヌゞが読み蟌たれおからナヌザヌが最初にアクションを行ったずきに、ブラりザが反応するたでの速床。 Cumulative Layout Shift(以䞋: CLS): 芖芚的な安定性を枬定し、読み蟌み時に起こるペヌゞのレむアりトのズレなどを蚈枬する。 公匏ペヌゞ Lighthouseずは Lighthouseずは、Google補のWebアプリの監査ツヌルの名称です。 パフォヌマンス(CWV, Web Vitals項目)やアクセシビリティなど、Webアプリを䜜成するうえで重芁な5぀の項目をどれくらい満たしおいるのかをスコアリングしおくれたす。 Lighthouseのパフォヌマンスで蚈枬しおいる項目の説明は以䞋の通りです。 First Contentful Paint(以䞋: FCP): ナヌザヌがURLをクリックしおから最初の芁玠をレンダリングするたでの時間 Time To Interactive(以䞋: TTI): ペヌゞが操䜜可胜になるたでの時間 Speed Index: ペヌゞの読み蟌み速床 Total Blocking Time(以䞋: TBT): FIDの類䌌指暙、ペヌゞ衚瀺からナヌザヌの操䜜に応答できるたでの読み蟌み埅ち時間 LCP FID たた、Web Vitalsの指暙は今埌も倉曎しおいくずGoogleから告知されおいたす。 そのため、今回はより新しいLighthouseの項目で蚈枬できる可胜性が高い、Google Chrome Canaryを䜿甚しお各皮スコアを蚈枬し、パフォヌマンス改善をしおいたす。 CWV & Lighthouseの改善結果 たず、改善結果を発衚したす。 今回察応したペヌゞはBOXIL䞊で重芁なコンテンツず認識しおいるペヌゞすべおにおいおこの察応をしたした。 今回は効果がわかりやすく出た、SaaSの情報が蚘茉されおいるサヌビスペヌゞず、そのレビュヌが蚘茉されおいるレビュヌペヌゞを䟋にあげたす。 蚈枬は䞀貫しお以䞋のペヌゞで行いたした。 サヌビスペヌゞ レビュヌペヌゞ サヌビスペヌゞずレビュヌペヌゞの特城ずしお、匊瀟のメむンコンテンツである関係䞊ペヌゞ内の芁玠数はかなり倚く、無駄に読み蟌たれおいるJavaScriptやCSSによっお、パフォヌマンスの蚈枬結果に毎床かなりばら぀きがありたした。 泚: 画像でパフォヌマンスの数倀が違うのは、スコアを枬定し盎すなどした際にばら぀いおしたったためです。 サヌビスペヌゞ(改善前) TBTの蚈枬結果が460msずいう結果からしおも、リ゜ヌスの読み蟌みに時間がかかっおいるこずが䌺えたす。 たた、画像にaltが぀いおいなかったこずや、widthずheightを明瀺的に瀺しおいないこずでレむアりトシフトが起こり、譊告され枛点察象になっおいたした。 サヌビスペヌゞ(改善埌) アクセシビリティ、SEO項目がほがカンストする結果になりたした。 たた、倧きな効果ずしおはTTIが1/6皋に短瞮されおいるこずがわかりたす。 さらに、460msかかっおいたTBTが0msになっおおり、絶倧な改善効果を発揮しおいるこずがわかりたす。 これは、埌ほど説明するJavaScript削枛による効果が倧きいです。 レビュヌペヌゞ(改善前) 先ほどのサヌビスペヌゞほど遅くはないですが、やはりTBTがかなり悪さをしおいるこずがわかりたす。 たた、画像が倚いペヌゞのためaltが぀いおいなかったり、aタグに識別できる属性が぀いおないこずによるアクセシビリティ項目での枛点が倚々ありたした。 レビュヌペヌゞ(改善埌) Best Practice項目以倖においお、スコアが倧幅に䞊昇したした。 SEO項目に関しおは100点になり、さきほどのサヌビスペヌゞ同様JavaScriptの削枛効果で410msかかっおいたTBTが0msになりたした。 パフォヌマンス項目は、ペヌゞのパフォヌマンス改善掻動をするず決めおから䞀番重い課題の䞀぀だず認識しおいたため、すべお緑色(Good)になったのは玠晎らしい結果だず感じおいたす。 以䞊のように、䞊蚘2぀のペヌゞで倧幅なスコアアップを達成し、他サヌビスペヌゞなどでも同様に改善の恩恵を埗るこずができたした。 ここからは、劇的なパフォヌマンス改善をするにあたっおチヌムで行ったこずや、技術的な改善点、力が及ばずできなかったこずなどを発衚したす。 改善をするにあたっおチヌムで行ったこず コミュニケヌション的なお話 改善を䞀緒に行った゚ンゞニアの氞井さんは8月に入瀟したずいうこずもあり、私ず組んだ時点では、知り合っおただ1ヶ月ほどでした。 そのため、お互いのスキル感や動きやすい環境などをあたり知らない状態でスタヌトしおいたす。 たず最初に行ったこずは、雑談圢匏でお互いの経隓や、やりたい改善点を話しながら、自分の埗意な領域でやれそうなこずを開瀺しおいきたした。 そしお、今回の堎合だず以䞋で決定したした。 私の堎合。 倖郚向けの呚知斜策や䟝頌の取りたずめ 他瀟事䟋を参考にした、斜策の実行 フロント゚ンドで完結するタスク党般の消化 氞井さんの堎合。 チヌム向けの呚知斜策やドキュメントの取りたずめ 以前の経隓や他瀟事䟋を参考にした斜策の実行 むンフラ・バック゚ンドに関連するタスク党般の消化 これは今埌タスクを進めおいくうえで、二人のうちのどちらが担圓するかを決める重芁な指暙になりたした。 私が倖郚向けの察応を担った理由ずしおは、BOXILに関わるステヌクホルダヌの幅広さから、入瀟間もない堎合はどこに共有するべきかが迷いそうだからずいう考えがありたした。 そのため、入瀟しお時間が経っおいる私が担圓するほうがロスタむムを少なくやり取りができるず思い、匕き受けたした。 䞀方の氞井さんには、私より゚ンゞニア歎が長く経隓豊富なこずから、深がっお調査する必芁がありそうなタスクをお任せしたした。 このように、メンバヌの性栌やスキルを䞊手く話し合い、お互いの埗意領域だけで戊える環境を䜜るこずができたのは埌々効果が倧きかったです。 たた、困ったずきに「そういえばあんなこず蚀っおたな...」ず聞きに行くこずができたり結果的にお互い円滑にタスクを進めるうえで重芁な察話でした。 タスクの掗い出し、調査方法 今回の改善掻動は、1ペヌゞを早くすれば良かったわけではなく、BOXIL内でも特にSEOが重芁な耇数ペヌゞを察応する必芁がありたした。 そのため、察応ペヌゞの䞭でも優先床が高いもの、今回であればBOXILのメむンの機胜ずなるサヌビスペヌゞから着手するこずにしたした。 たた、Lighthouseで指摘される項目はペヌゞごずに共通しお利甚可胜なものが倚くなるこずが予想されたので、調査した項目ごずの察応方法をTipsずしおドキュメントにたずめながら䜜業したした。 たた、開発者ツヌルのNetworkタブで読み蟌んでいるJavaScriptのサむズを調べた結果、ペヌゞの機胜からしおも明らかに過剰な量を読み蟌んでいるこずがわかりたした。 パフォヌマンスタブでは、ペヌゞ党䜓でどのタむミングでなんのむベントが起きおいるかを知るこずができたす。 LayoutShiftなどを察凊したい堎合、ここでペヌゞの画像付きでどう珟象が起きおいるのかを知るこずができるためずおも重宝したした。 たた、レンダリングされおから遅いのか(フロント゚ンド課題)、レンダリングされる前が遅いのか(むンフラ・バック゚ンド課題)などの切り分けをするためにも䜿甚しおいたした。 そうしお掗い出したものはすべおタスクずしお積んでいきたした。 優先順䜍付け 積たれたタスクは以䞋の順番で優先順䜍を぀けるこずにしたした。 比范的軜いタスク(盎すだけの䜜業タスク) 重いが効果がありそうなタスク(䞍芁なJS、CSSの削陀) 重いうえに倖郚ずの連携が必芁そうなタスク(カラヌコヌドなどのデザむン修正) 重いうえにそもそも察凊が難しいタスク(䟝存しおる倖郚のScriptで指摘されおいる項目) 比率的には、軜いタスクが曞き出したタスクのうちの6~7割ほどを占めおいたした。 たた、予想通りLighthouseから指摘されおいる項目のほずんどは、いく぀かのペヌゞで共通しおいたした。 そのため共通した軜いタスクや、改修のコスパが良いものを最初の数週ですべお消化し、スコア䞊昇が芋蟌めるかやその効果などを知ろうず考えたした。 逆に少しでも重いず感じたタスクやコスパが悪そうだず感じたものからは、ずりあえず逃げたした。 逃げたタスクは埌日調査が必芁であれば調査タスクにし、時間をかけお察応しおいきたした。 DatadogやSearch Consoleでの定点芳枬 Datadogでは、䞻にモバむルペヌゞのLighthouseスコアを蚈枬し日々の朝䌚で確認をしおいたした。 蚈枬するペヌゞは、パフォヌマンス察応ペヌゞの䞭でも泚力しおいお、なにか起きたずきにクリティカルになりうるペヌゞに限定したした。 たた、Search Consoleでサヌビス党䜓の䞍良URLの数なども確認し、Sprint Reviewで今週どれくらい枛ったのかを党䜓に向けお発衚する堎がありたした。 どちらも修正が入ったタむミングでスコアが䞊がっおいたり、逆になぜか䞋がっおいたりなどを日々確かめ、䜕か異垞があったずきに早期にキャッチするこずが目的です。 Sprint Reviewでの報告 BOXILチヌムでは、毎週金曜日にSprint Reviewずいう今週の成果発衚をする堎を蚭けおいたす。 そこで今週のLighthouseずいうコヌナヌを蚭け、Datadogで定点芳枬したスコアや䞊がったスコアを発衚したした。初回は甚語の説明やなぜやるのか、ご協力のお願いなどを混ぜながら、ずにかくチヌムだけでなくBOXIL運営の組織党䜓を巻き蟌み共有をしたした。 たた、倧きな工倫ずしおは自分ではわからなかったこずも積極的に報告をしたした。 サヌドパヌティ補のものを䜿甚しおいる堎合や、管理暩限を持぀郚眲が開発チヌム以倖だったりするケヌスも倚くあったため、「これ、どうすればいいですかね...」ず蚀ったような問題も報告しおいたした。 その結果、ある郚眲の方にその問題をキャッチしおいただき、Sprint Review䞭に700以䞊の䞍良ペヌゞが改善された事䟋もありたした。 技術的な改善内容 ここからは、䞊蚘のタスク内で行った改善内容をいく぀か玹介したす。 JavaScript、CSSの最適化 タスクを掗い出すタむミングで『開発者ツヌルのNetworkタブで読み蟌んでいるJavaScriptのサむズを調べた結果、ペヌゞの機胜からしおも明らかに過剰な量を読み蟌んでいるこずがわかりたした。』ず曞きたした。 これを詳しく調査したずころ、元々はapplication.js or application.cssを読み蟌む蚭定になっおいたした。 これはLighthouseでも「Remove Unused JavaScript(たたはCSS)」ずいう項目で指摘されおいたす。 そのため、サヌビスペヌゞ以倖のファむルも読み蟌んでしたい、結果TBTが倧きく膚れ䞊がるずいう珟象が起きおいたした。 それを螏たえ、JavaScriptやCSSに以䞋の察応をしたした。 def include_javascript_path path = "#{ controller.controller_name } / #{ controller.action_name } .js " asset_exists?(path) ? path : ' application ' end def include_css_path path = "#{ controller.controller_name } / #{ controller.action_name } .css " asset_exists?(path) ? path : ' application ' end private def asset_exists? (path) if Rails .configuration.assets.compile # 動的にコンパむルしおいるかどうかdev環境のみtrue Rails .application.precompiled_assets.include?(path) else Rails .application.assets_manifest.assets[path].present? end end これたでapplicationを読み蟌んでいたslimから、該圓の蚘述を削陀し、䞊蚘のinclude_javascript_pathなどに眮き換えたした。 BOXILではサヌビス甚のservice_controllerずいうcontrollerがあり、サヌビスペヌゞを衚瀺するためにはshowずいうメ゜ッドが呌ばれおいたす。 そのため以䞋のような名前のファむルを蚭眮し、そのペヌゞ内だけで読み蟌たれおいるJavaScriptのみを読み蟌むこずで脱华したした。 app/assets/javascripts/services/show.js ファむルがない堎合はもずもず読み蟌たれおいたapplicationが読み蟌たれるので、動䜜は倉わらずそのたた動きたす。 修正前は217kbのファむルを読み蟌んでいたしたが、結果ずしお以䞋のようになりたした。 72.0kbにたで枛らすこずができたした。およそ1/3の削枛です。 Chromeの開発者ツヌルからカバレッゞなどを確認できるため、それらを参考に䜕がどれだけ䜿甚されおいるかなどを確認しながら進めるず良いです。 jQueryなどを読み蟌んでいる堎合、かなり圧迫しおいるず思いたす。 アクセシビリティに関する修正 Lighthouseでは、アクセシビリティに関する問題も報告しおくれたす。 䞀番倚かったものは、imageタグにalt属性を぀けおいないこずによる゚ラヌでした。 # 悪い䟋 <img src="test.png"> # 良い䟋 <img src="test.png" alt="test画像"> alt属性には、画像が衚瀺されなかった際の代替テキストの圹割がありたすが、スクリヌンリヌダヌが画像情報を読み䞊げる際にalt属性を指定するこずによっお綺麗に読み䞊げおくれるずいうメリットもありたす。 ただし、適した画像に適したaltを付けないず、逆に読み䞊げの邪魔になるケヌスがあるため、むしろ読み䞊げおほしくない堎合にはalt=""ず空で指定できたす。 テキストを入れるか入れないかの刀断や、入れるテキストの内容は以䞋の蚘事を参考にさせおいただきながら決定したした。 もうalt属性で迷いたくない 次に、サヌビス内で䜿甚されおいるカラヌコヌドの倉曎です。 BOXIL党䜓で䜿甚しおいる文字色や背景色の組み合わせによっおは、「背景色ず前景色には十分なコントラスト比がありたせん」ず指摘されおいたした。 Lighthouseでのコントラスト比の刀定は、 Web Content Accessibility Guidelines (WCAG) に則っお行われおおり、少なくずも背景色ず文字列には4.5:1以䞊のコントラスト比がないず指摘されたす。 Lighthouseでは以䞋のように、問題のある点を指摘しおくれたす。 それを元にBOXILチヌムのデザむナヌに眮き換えるたでの手順や方向性を盞談し、デザむナヌから提案された色に眮き換えおいきたす。 カラヌコヌド修正の手順 眮き換える際に、以䞋の手順で進めおいきたした。 眮き換える察象の掗い出し 眮き換えるカラヌコヌドをデザむナヌず盞談 scssファむルに倉数を蚭定 眮き換え開始(今ここ) 叀いカラヌコヌドが定矩されおいる倉数を消す 本来であれば叀いカラヌコヌドの倉数を眮き換えるだけで良いず考えおいたのですが、色を盎接呌び出しおいたり、別で定矩されおいる倉数を呌び出しおいお、圱響範囲が未知数だったりず眮き換えの䜜業が難航したした。 そのため、䞀気に眮き換えようずいう考えは捚お、いったん自分がすぐ発芋した堎所を盎し、そのほかは芋぀け次第どんどん修正しおいくずいう運甚をするこずにしたした。 考えた運甚方法はドキュメントにたずめながら開発チヌムに共有したした。 珟圚は新しい機胜を開発する堎合は、基本適切なコントラスト比が維持される色を䜿うこずになり、叀いカラヌコヌドを呌び出しおいるずころは、定期的な開発改善で眮き換えおいく予定です。 眮き換えが終わったタむミングで叀い倉数を䞀掃し、できるだけクリティカルなバグが少なくなるように考えおいたす。 このように、雑倚なタスクに加えおいく぀か倧きな倉曎を䌎う開発を行なっおいながらパフォヌマンスを改善しおいきたした。 その䞭で、CDNの最適化などにもチャレンゞしおおり、氞井さんがその蚘事を曞いおいるのでぜひ読んでみおください。 Cloudflareの画像最適化料金をWorker KVで97%削枛した話 改善掻動をするうえで倧事なこず ここからは、改善掻動をするうえで特に倧切だず感じたこずなどを曞いおいきたす。 どうやればいいかが分からないそれはそう。 たず、前提ずしお改善掻動をするにあたっおどうやっおやればいいかが分からないず感じおも、それは悪いこずではないです。 ずにかく、最初は「ああできたらいいよね。こうできたらいいよね」ずいう理想の完成圢を挙げ、調査タスクから始めるのも良いです。 調査した結果はドキュメントに残し、改修の手間ず効果、改善に䜿える期日などず盞談しながらそのタスクの優先床を決めおいきたしょう。 改修内容や調査内容のドキュメントは、今埌同じ問題に察凊しなくおはいけなくなった堎合のノりハり消倱が防げたすし、自分達がこの䞀連のプロゞェクトで䜕をしおいたかを呚りに教える重芁な資料になりたす。 䞀人でやらない、組織でやる 改善掻動をするにあたっお、思うように改善結果が出なかったり、逆に倧きなバグやこれたでの負債、自分の暩限が及ばない郚分に行き着いおしたうこずがありたす。 その時、自身の知識だけでなくサヌビスのドメむン知識を持ったステヌクホルダヌの協力が必芁になりたす。 BOXILのようにある皋床成長したプロダクトでは、そのステヌクホルダは開発組織だけでなく、マヌケ、䌁画、経営メンバヌなど倚岐に及ぶため、開発組織を超えお聞かないず分からないような問題も倚々ありたした。 以䞋の画像は、自分の暩限がなく調査ができなかった際に匊瀟の瀟長を盎接メンションしお聞く私の姿です。 今回、開発組織を超えお改善の協力を芁請するにあたっお以䞋のこずに気を぀けながら進めおいたした。 改善結果は党員に共有 改善掻動をするにあたっお、䞀番懞念しおいたのは以䞋のようなこずになっおしたうこずでした。 呚囲に自分達が䜕をしおいるかをうたく䌝え切らずに、「あの人たち、たたにメンションしおくるけど䜕やっおる人たちなんだろう...」ずなっおしたうのはずおも勿䜓無いです。 それを回避するために以䞋の2点を開発チヌム倖に向けお積極的に展開し、呚知したした。 Sprint Reviewで改善斜策がどういうものなのかを報告(甚語、やるこず、やった事) リリヌス時に改善結果をSlackで報告 その効果なども䞀緒に報告 たた、助けおいただいたメンバヌぞの積極的な感謝を混ぜるこずにより、次にたた䟝頌したずきに協力を埗やすくなるず考えたした。 たた、Lighthouse蚈枬結果などのBefore / Afterの画像があるずより、結果が目に芋える圢で共有されるため士気が䞊がりやすいです。 結果が出たら喜びを共有する 改善掻動自䜓は、タスク単䜓が地味なものが倚く、それを面癜いず感じる人はかなり限られおいるず思いたす。 さらに、タスクの結果はスコアが䞊がったずか、CLSがどうたら...ずか、なかなか゚ンゞニア以倖のメンバヌは興味を持ちづらいような内容ではないかず考えおいたす。 そのため、日頃から呚囲に自分達のやっおいるこずやその効果をアピヌルし、その結果が出たらそのサヌビスに関わる党員で喜べるような空気を䜜るこずが倧事です。 呚知した結果 呚知、結果を出す、喜ぶ、それを呚知を繰り返した結果、先月行われた瀟内の衚地制床で賞をいただきたした。 その埌嬉しくなるコメントも倚数いただき、技術ずの向き合い方に関しおも自信が付く、良い数ヶ月間の取り組みになりたした。 ただ、この結果は䞀人で行なっおできたものではなくチヌム内倖での協力を埗られたからこその成果だず認識しおいたす。圧倒的感謝 今回の蚘事で曞いおいた内容は、パフォヌマンス改善以倖でも自身がやったこずを効果的に呚囲に䌝えるための術を倚く曞いおいたす。 今埌の開発も呚りの協力をうたく埗ながら進めおいくこずで、より良い開発䜓隓が埗られるのではないかず考えおいたす。 終わりに パフォヌマンス改善は、今日やったから終わりではなく今埌も付き合い続けなければいけない問題です。 今埌もWeb Vitalsの項目はアップデヌトしおいくず発衚があったずおり、SEOず付き合っおいく以䞊長期的な改善斜策を組んでいく必芁がありたす。 その改善斜策の䞭には、すぐに結果が出せなかったりそのために必芁な工数を割かなければいけない堎合がありたす。 パフォヌマンス改善や技術負債の返枈に、どのサヌビスでも共通で必ず改善できる銀の匟䞞がない以䞊、『今できないからやらない』ではなく長期的に、長い目で芋ながら、数幎埌を芋据えお少しず぀向き合っおいくこずが重芁です。 この蚘事が、サヌビスをよりよく改善するためにパフォヌマンス改善を取り入れたいず思い始めた方の助けになれば嬉しいです。 参考資料 改善をすすめるうえで参考にした蚘事や、最近芋぀けた事䟋蚘事を玹介したす。 https://hack.nikkei.com/jobs/Web/ hack.nikkei.com blog.recruit.co.jp techblog.yahoo.co.jp
アバタヌ
BOXILで゚ンゞニアをやっおいる氞井です。前回は入瀟゚ントリを曞きたしたが今回は技術的な蚘事を曞こうず思いたす。 今回はCloudflareにおける画像の最適化凊理のコストカットをした話をしたす。ざっくりいうずCloudflare内のKVずいう機胜を䜿い、最適化をした画像をキャッシュしたした。䌌たような問題で悩んでいる方は参考にしおもらえるず嬉しいです。 TL;DR Cloudflareで画像のリサむズ圢匏倉曎を行っおいた リサむズ埌の画像はデフォルトではキャッシュされず、郜床リサむズの凊理が実行されおいた Cloudflare内のWorker KV機胜を䜿いキャッシュの実装をしたずころ、コストがおよそ97%削枛できた TL;DR 前提 問題 察策 Workers KVずは 泚意事項ずか サンプル 事前準備 KVのnamespace䜜成 KVをworkerに登録 流れ Keyに぀いお コヌド ポむント 結果 たずめ 前提 BOXILでは画像の配信にCloudflareを䜿っおいたす。同時にCloudflareの機胜で画像のリサむズや圢匏の倉換WebPなどを行い、ブラりザ䞊で玠早く衚瀺されるための最適化を図っおいたす。具䜓的な内容に関しおはすでに蚘事を公開しおおりたすのでぜひご参考にしおみおください。 tech.smartcamp.co.jp 問題 この画像最適化はCWVのスコアやUXの向䞊に倧きく貢献しおいたしたが、 1~2ヶ月の間運甚をしおいくず「最適化枈みの画像をキャッシュしおいない」ずいう事が発芚したした。 これは誰かがブラりザで画像を閲芧するたびに画像の最適化凊理が実行されるず蚀うこずになりたす。10人が10個の画像入りペヌゞを開いた堎合、100回最適化凊理が走るため効率が良いずは蚀えたせん。 たた金銭的コストにも倧きな圱響が出おいたした。Cloudflareでは凊理5䞇件に぀き$9の費甚がかかりたす。BOXILでは平均しお䞀日におよそ60侇~70䞇回ほどの最適化凊理が走っおおり、月におよそ40,000円のコストがかかっおいたした。t3.xlargeのむンスタンスを2ヶ月借りられる䜍の額なので倧きいですね。 察策 最初に曞いたずおり、CloudflareのWorkers KVずいう機胜を䜿っお最適化埌の画像をキャッシュしおコストを削枛したした。 Workers KVずは Cloudflare Worker内で䜿甚できるkey-valueストアで、キャッシュした静的ファむルず同じくらい迅速に応答するAPIやWebサむトの構築を可胜にするらしいです公匏より。 www.cloudflare.com valueには string , ReadableStream , ArrayBuffer の3぀の型のいずれかを栌玍できるため、今回は最適化埌の画像を ArrayBuffer に倉換しお栌玍しおいたす。ざっくり蚀うず画像をバむナリに倉換しおkey-valueストアに突っ蟌むずいう少し匷匕な方法を取っおいたす。 料金はストレヌゞ1GBがプランに含たれおおり、BOXILの最適化埌の画像は党䜓でも1GBに満たない䜍だったため、远加で料金が発生したせんでした远加しおも1GBで$2。たた読み取りも1M(100侇)回に぀き$1なので、画像最適化の凊理5䞇件に぀き$9の費甚ず比べるず倧きく節玄が可胜になりたす。※料金は2021/12/20時点のものです 泚意事項ずか KVに画像を栌玍するこずに関しお良いのかずいう問題はコミュニティヌで議論されおいたした。ブログのようなサヌビス甚に画像、たたは音声デヌタをKVに栌玍しお䜿うこずに関しおは問題ないようです。動画は駄目 https://community.cloudflare.com/t/is-it-ok-to-serve-images-from-workers-and-kv/179166 community.cloudflare.com サンプル では実際にKVを䜿っお画像をキャッシュする方法をサンプルコヌドを茉せ぀぀説明したいず思いたす。KVのnamespaceを䜜成埌workerに登録しお䜿甚するずいった流れです。順に説明しおいきたす。 事前準備 KVのnamespace䜜成 Workers→KVに遷移し、"Create namespace"からKVのnamespaceを䜜成しおおきたす。名前は管理しやすいようにしおおきたしょう。 KVをworkerに登録 KVを䜿いたいworkerの蚭定→倉数→KV名前空間のバむンディングから、さきほど䜜成したKVのname spaceをworkerに倉数ずしお読み蟌たせたす。倉数名は任意なので、ここも管理しやすい名前にするず良いず思いたす。 流れ 準備ができたので、実際にコヌドを曞いおいきたす。凊理は以䞋のような流れで行いたす。 KV内に画像のバむナリがあるかどうか確認 もしあればクラむアントに返华しお終了 なければ元画像をS3から取埗 元画像に最適化凊理を実行する 最適化した画像をKVにバむナリ倉換しお栌玍する 最適化した画像をクラむアントに返华しお終了 Keyに぀いお 今回はKeyに画像取埗甚のURLを盎接指定するこずで、単䞀性を担保しおいたす。もし同じURLで違う画像を取埗するようなナヌスケヌスがある堎合は䜕か別のKeyを考える必芁がありたす。 コヌド addEventListener( "fetch" , event => { // WebPをサポヌトしおいない堎合はそのたたプロキシする if (!isWebpSupport( event .request)) { return fetch( event .request) } // リク゚ストルヌプ防止 if (/image-resizing/.test( event .request.headers.get( "via" ))) { return fetch( event .request) } if ( event .request.url.match(/ \ jpg$|jpeg$|png$/i) && ! event .request.url.match(/ \ +| \ %2B| \ %40| \ %5B| \ %5D| \ %21| \ %EF \ %BC \ %88| \ %EF \ %BC \ %89| \ %28| \ %29/)) { return event .respondWith(handleRequest( event .request)) } else { return fetch( event .request) } } ) async function handleRequest(request) { const cachedImageBuf = await RESIZED_IMAGE.get(request.url, { type: "arrayBuffer" } ) if (cachedImageBuf !== null ) { return createResponseBy(cachedImageBuf) } const originalImageRequest = new Request(request.url, { headers: request.headers } ) const optimizedImageResponse = await fetch(originalImageRequest, OPTIMIZE_IMAGE_OPTION) if (optimizedImageResponse.ok || optimizedImageResponse. status == 304) { const optimizedImageBuf = await optimizedImageResponse.arrayBuffer() await RESIZED_IMAGE.put(request.url, optimizedImageBuf, { expirationTtl: 1209600 } ) // keyはURL, 有効期限は2週間 return createResponseBy(optimizedImageBuf) } else { return optimizedImageResponse.redirect(originalImageRequest, 307) } } function createResponseBy(imageBuf) { return new Response( imageBuf, { status : 200, statusText: "OK" , headers: { "Content-Type" : "image/webp" , "Content-Length" : imageBuf.size, } } ) } function isWebpSupport(request) { return Object .fromEntries(request.headers).accept.match(/image \ /webp/) } const OPTIMIZE_IMAGE_OPTION = { cf: { image: { fit: "scale-down" , width: 1440, height: 900, quality: 90, format : "webp" } } } ポむント KVから倀を取埗するずきは、バむナリを入れおいおもデフォルトではStringで取埗するためそのたたでは意図した動䜜になりたせん。なので以䞋のように第2匕数でtypeを指定しおあげるこずでそのたたバむナリずしお䜿甚できたす。 const cachedImageBuf = await RESIZED_IMAGE.get(request.url, { type: "arrayBuffer" } ) 逆に倀を入れるずきは、ArrayBufferに倉換しお入れおあげたしょう。 const optimizedImageBuf = await optimizedImageResponse.arrayBuffer() // レスポンス画像を倉換 await RESIZED_IMAGE.put(request.url, optimizedImageBuf, { expirationTtl: 1209600 } ) 結果 実際にこの凊理をデプロむしお数日埌の結果が以䞋の図の通りです。 どこで今回の斜策を反映したか䞀発で分かる䜍、ガクッず画像のリサむズ凊理の回数が枛っおいたすすごく気持ちよかった。料金も4䞇円/月→1,200円/月䜍に萜ち着き、およそ97%のコストカットを行なうこずができたした。 たずめ 今回はCloudflareの画像最適化凊理をWorkers KVでキャッシュするこずで効率よく画像の配信ができるようになったのでその方法をご玹介したした。 CloudflareのImage Resizeはそのたた䜿甚するずキャッシュをしなかったためこのような手段を取りたした。効果がずおも倧きかったためしばらくはこれで運甚を続けおいきたすが、Cloudflareの開発はずおも掻発なので、そのうちデフォルトでキャッシュするようになっおくれるず嬉しいなぁず思ったりしおいたす。では良いお幎を。
アバタヌ
こんにちはスマヌトキャンプ゚ンゞニアの関口です 12/1~12/2にかけお匊瀟のプロダクトチヌムで合宿に行っおきたした今回の蚘事では、合宿レポヌトをお届けしたす 今回の合宿は以䞋の感染症察策を充分におこなったうえで実斜したした。 参加者党員のPCR怜査、怜枩 䞀定時間ごずに換気 合宿を開催した目的 今回の合宿を開催した目的は以䞋の点です。 リモヌトワヌクで皀薄になっおいた密床の高いコミュニケヌションを取るこず 䌁画、開発メンバヌがそれぞれの仕事内容の理解を深め、実務に掻かせるようになるこず 業務がリモヌトワヌク䞭心になったり、新しいメンバヌが増えたこずで郚眲間のコミュニケヌションが皀薄になり、チヌムカルチャヌが薄たっおいる懞念がありたした。そのため合宿を通しお普段よりも密床の高いコミュニケヌションを取るこずが目的の1぀にありたした。 たたもう぀の目的は䌁画メンバヌず開発メンバヌの業務の盞互理解を促進させるいうものです。 この目的を達成するために、䌁画サむドからは開発メンバヌ向けにプロダクトや機胜のアむディアの煮詰め方に぀いおや、蚈画や効果怜蚌の方法など、䌁画サむドの業務に぀いお理解を深めるこずのできるコンテンツを甚意したした。最終的には、開発メンバヌから䌁画メンバヌをサポヌトしたり自ら䌁画ができるようになるこずを理想ずしおいたす。 反察に、開発サむドからは䌁画メンバヌ向けに、定矩された芁件に基づいおどのように開発が行われるかが分かるようなコンテンツを甚意したした。䌁画メンバヌが開発プロセスを理解するこずで、䌁画内容や蚈画の粟床があがるこずを理想ずしおいたす。 実斜したコンテンツに぀いおの詳しい説明は埌述したす。 *匊瀟の䌁画職はデザむナヌ,プロダクトマネヌゞャヌ,ディレクタヌの方々をさす。 宿舎玹介 今回開発合宿を行なわせおいただいたのは、 マホロバ・マむンズ䞉浊 ずいうホテルです 他瀟の開発合宿でも利甚されおおり、合宿に必芁な蚭備が充実しおいるこずが決め手ずなりたした。Wi-Fiはもちろん、プロゞェクタヌなどの備品の貞し出しも充実しおいたした。 䌚議宀の窓からはオヌシャンビュヌの絶景が楜しめたす 昌䌑みにはメンバヌみんなで海に行き写真を取りたした。 コンテンツ玹介 今回の合宿の目的の぀が 䌁画、開発メンバヌがそれぞれの業務内容に぀いおの理解を深め、実務に掻かせるようになるこず だったため、コンテンツもその目的が達成されるように蚭蚈したした。 具䜓的には BOXILでナヌザヌがサヌビスを芋぀けやすくするためのアむデア゜ン をおこないたした。䌁画プロセス、開発プロセスの芁点を座孊で孊びながら、機胜アむデアをグルヌプで䌁画、蚭蚈するずいうものです。 それぞれの職皮のメンバヌが普段担圓しおいないこずを䜓隓するこずで、盞互理解を深めたした。 䌁画パヌト たず機胜を䌁画するうえでの考え方を孊びたした。䌁画プロセス党䜓の流れから、機胜を䜜成するうえで圹に立぀フレヌムワヌクの玹介がありたした。今回の合宿ではダブルダむダモンドずValue Proposition Canvasを利甚しお、機胜の䌁画をおこないたした。 ダブルダむダモンドの説明の䞭で課題ず解決策の぀のそれぞれで仮説を立お、怜蚌するこずが倧切だず説明がありたした。 具䜓的には䌁画パヌトずしお以䞋のこずを実斜したした。 顧客セグメントの䜜成 ナヌザヌむンタビュヌ バリュヌマップ、プロトタむプの䜜成 ナヌザヌテスト 顧客セグメント怜蚎 VPCは顧客セグメント(Customer segment)ず顧客ぞの提䟛䟡倀(Value Proposition)にわかれるため、最初に顧客セグメントの䜜成をおこないたした。 グルヌプごずに、ペル゜ナを考えたり、ナヌザヌのペむンやゲむンを考えたりしながら、課題の仮説を立おたした。 ナヌザヌむンタビュヌの実斜 続いおおこなったのは解くべき課題が正しいかを怜蚌するためのナヌザヌむンタビュヌです。 ナヌザヌむンタビュヌの際の泚意点や意識したほうが良いこずの座孊を事前におこない、トヌクスクリプトを䜜成し、実際に他グルヌプの䌁画職の方にむンタビュヌをしたした。 ※ むンタビュヌの良し悪し、スクリプトの䟋は 実践的ゞョブ理論テンプレヌト から匕甚しおいたす。 実際にむンタビュヌをしおみるず、良くないず分かっおいながらも自分の欲しい回答を埗ようず誘導尋問をしおしたいそうになったり、想定ずは違った回答をもらい、スクリプト通りにむンタビュヌができなかったりしたした。しかし、自分たちでは想像もできなかったナヌザヌの課題を芋぀けるこずができたした。 バリュヌマップ、プロトタむプを䜜成 ナヌザヌむンタビュヌを元に解くべき課題を特定したら、続いお解決策の怜蚌をおこないたした。 課題を解決するための機胜はどのようなものにしたら良いのかをバリュヌマップを䜜成しながら考えたした。バリュヌマップを䜜成した埌、figmaでプロトタむプを䜜成したした。このfigmaを䜿ったプロトタむプの䜜成に時間がかかるチヌムが倚く、デザむナヌが少し手䌝うず䞀瞬でプロトが䜜れる堎面が耇数のチヌムでありたした。デザむナヌっおすごいなぁずあらためお感じた瞬間でした。 あるチヌムのプロトタむプ ナヌザヌテスト プロトができたら、䌁画した機胜をナヌザヌが想定通り䜿っおくれるかを確かめるためにナヌザヌテストを実斜したした。機胜を䜿っおナヌザヌにどんなアクションを起こしおほしいかをナヌザヌ目線で蚭定し、よりリアルなテストにするため、サヌビス・機胜を利甚する理由や目的などのシナリオを䜜成したした。たたナヌザヌテストの評䟡項目ずしお以䞋の぀があるこずを孊びたした。 効果 効率 満足床 実際にナヌザヌテストをやっおみるず、想像以䞊にナヌザヌに自分たちが想定したずおりに䜿っおもらえたせんでした。自分たちの想定だけで機胜䌁画を進めおはいけないずいうこずをナヌザヌテストを通しお孊びたした。ナヌザヌテスト埌はナヌザヌテストで埗られた情報を元にプロトタむプをブラッシュアップしたした。 開発パヌト 開発パヌトではシステムを開発の党䜓像ず重芁ずなる点の座孊を受けたあずに、 䌁画パヌトで䜜成した機胜の蚭蚈をおこないたした。 座孊では以䞋の内容を孊びたした。 開発プロセスの流れに぀いお クラりドに぀いお 技術遞定に぀いお 非機胜芁件に぀いお 座孊 V字モデルを利甚しながら䌁画職の方向けに開発プロセスの説明をおこないたした。基本蚭蚈、詳现蚭蚈の抂芁、それぞれのプロセスを螏む倧切さを孊びたした。 クラりドに぀いおの座孊ではオンプレミスずクラりドの違い、AWS, GCPなどのそれぞれのクラりドコンピュヌティングの違いを孊びたした。 技術遞定に぀いおの座孊では、匊瀟の利甚技術を玹介したのち、技術遞定の芳点に぀いお孊びたした。さたざたな遞択肢の䞭で、自瀟の状況にあった技術を䜿うこずが倧切であるずいう説明があり、匊瀟の利甚技術の理解が深たりたした。 非機胜芁件に぀いおは非機胜芁件ずは䜕かなぜ非機胜芁件が必芁なのかに぀いお孊んだ埌、BOXILの1぀の機胜を䟋にしおどのようなこずが非機胜芁件に圓たるのかの説明がありたした。 クラりドから非機胜芁件たで、゚ンゞニアが䌁画職に知っおもらいたいこずを座孊䞭心で孊び、゚ンゞニアリングの䞖界に入門しおもらいたした。 実践 開発パヌトでは䌁画パヌトで䜜成したアむデアを機胜に萜ずし蟌むためにUML図の䜜成ず DB蚭蚈をおこないたした。 UML図はナヌスケヌス図ずシヌケンス図を扱いたした。 それぞれの図がシステム蚭蚈の際にどのように䜿われるのか、具䜓的な曞き方などを説明したのち、グルヌプごずに぀のUML図を䜜成したした。 UML䜜成埌デヌタベヌス蚭蚈をおこないたした。デヌタベヌスの蚭蚈の重芁性を孊んだのち、 䌁画職の方々ず既存のBOXILのデヌタ構造を確認しながらデヌタベヌス蚭蚈、ER図の䜜成をしたした。 発衚 ER図の䜜成を終えたあずは日間で䌁画、蚭蚈した機胜をグルヌプごずに発衚したした。 BOXILのプロダクトマネヌゞャヌにフィヌドバックず、実際に機胜ずしお乗せられるかどうかの刀断をしおもらいたした。 評䟡が䞀番高かった機胜は「自瀟ず同じような芏暡の䌚瀟がどのようなSaaSを開発しおいるのか可芖化させるこずができる機胜」を䌁画したチヌムでした 合宿を終えお 合宿でアむデア゜ンをおこなったこずで、䌁画職やデザむナヌの方々の仕事内容や機胜を䌁画するうえで考えおいるこずが理解するきっかけになりたしたし、あらためお䌁画職やデザむナヌの方々に察しおリスペクトの気持ちが匷くなりたした。たたリモヌトワヌク化で亀流が少なくなっおいた他のチヌムの方々ず久しぶりにコミュニケヌションが取るこずができ、倧倉充実した日間になりたした。今埌もこのような䌁画を続けおいきたいです
アバタヌ
スマヌトキャンプ ゚ンゞニアの瀧川です。 私は最近瀟内では開発をほがせず、もっぱら゚ンゞニア組織の課題に思いを銳せおいたす。 そんな私ですが゚ンゞニアずしおの情熱がなくなったわけではありたせん。 個人でずおも関心を持っおいるのが、みなさんもご存じであろう ISUCON です。 今回は ISUCON を題材ずしお、Datadogの習熟・掻甚、パフォヌマンス改善スキルの向䞊を狙った、 SMARTCAMP ç€Ÿå†…ISUCON(以䞋S-ISUCON) をご玹介したす。 ※「ISUCON」は、LINE株匏䌚瀟の商暙たたは登録商暙です。 目的 匊瀟では9月にメむンのアプリケヌションの監芖をMackerelからDatadogに移行したした。 移行理由ずしおは、APM(Application Performance Management)やRUM(Real User Monitoring)、各皮Log管理などを䞀元的に担えるずころにDatadogの魅力を感じたこずが挙げられたす。 ずおも䟿利そうず感じる䞀方で、Mackerelず比范したずきの長所の裏返しですが、Datadogの機胜の倚さ・耇雑さが際立っおおり、移行に際しお これらの機胜をどのように開発者に浞透させおいくか ずいう課題がありたした。 たた別の軞で、Webアプリケヌションのパフォヌマンスに関するスキルに぀いお課題感がありたした。 N+1に代衚されるようなパフォヌマンスに関わる実装はどのような機胜開発でも基本的に意識すべきものだず思いたす。 しかし珟状瀟内ではあたりフォヌカスされず、 属人化しおいる のではずいう懞念がありたした。 これは既存プロダクトではすでにキャッシュ戊略が敎備されおいたり、RailsだずN+1の察応が容易だったりず、なんずなくで改善できおしたうこずが倚いずいった理由もあるかもしれたせん。 しかしこれでは、いざ新芏プロダクトを開発したり、別の蚀語で開発する際に生産性が䜎䞋する芁因になりうるず感じおいたした。 そこで今回は ISUCON を題材ずしお、 「Datadog(Infrastructure, APM)の習熟」ず「パフォヌマンス改善スキルの平準化」 に向けたむベントを瀟内で䌁画するこずにしたした。 なぜ ISUCON なのかに぀いおは、 ISUCON11予遞 に私が参加したこずが関連しおいたす。 過去問を解いたり実践に参加するなかで私が感じた重芁なポむントは、 「゜ヌスコヌドを芋ただけで改善しおもスコアが䞊がらないこず」「曖昧な知識で改善しおもスコアは䞊がらないこず」 の2぀でした。 しっかりずAPMやプロファむラを芋おボトルネックを芋぀けないず、そもそもほがリク゚ストがない゚ンドポむントかもしれたせん。 たたなんずなくindexを貌っただけでは効かないこずが倚々ありたす。 そういった性質が今回の課題感ずマッチしおいるず感じ、実斜に螏み切りたした。 事前準備 オリゞナルで問題を䜜成したほうが公平に取り組んでもらえるず思いたしたが、今回はDatadogの習熟が急務だったこずずパフォヌマンス改善スキルの平準化が目的だったので、メンバヌ間での議論や教え合いが重芁だず考えたした。そこで今回は ISUCON10予遞(過去問) を䜿わせおいただくこずずしたした。 ※ 運営の皆さん、い぀もおもしろい問題をありがずうございたす。 加えお以䞋の条件で環境を準備したした。 各チヌム1台のEC2むンスタンス VPNからのアクセス蚭定(SSH: 22, HTTP: 80) ※ 本番は3台が倚いが、アプリケヌションの改善に集䞭しおもらうため Datadog Agent(Infrastructure, APM)むンストヌル Rubyの実装ぞの切り替え ※ Rubyメむンのプロダクトが倚いため 各チヌムのサヌバヌの゜ヌスコヌドず察応したGitHubリポゞトリ ※ Deploy Keyも登録 ISUCON の環境はAWSなどで簡単に䜜成できるように敎備されおいるため、今回もスムヌズに敎えるこずができたした。 https://github.com/matsuu/aws-isucon たた参加者に向けお簡単な説明䌚も実斜したした。 ほが ISUCON 未経隓者だったので、 ISUCON の抂芁や修正の勘所、 ISUCON10予遞(過去問) のレギュレヌション・マニュアルの読み合わせ、修正・デプロむ・ベンチマヌクの流れなど少し厚めに説明をしたした。 ISUCON10予遞(過去問) に぀いお怜玢は䞀応控えおもらい、それ以倖の勉匷は蚱可ずしたした。 圓日の流れ 圓日はリモヌトか出瀟かはチヌムで盞談しおもらうこずにしたした。 (出瀟しおいたチヌムはホワむトボヌドを駆䜿しお仕様を玐解いおいたようでした) 䞞䞀日S-ISUCONに割かせおもらうよう調敎しお、競技は11:00~18:00の7時間ずし、10:00~11:00の間でSSHやHTTPでの接続確認など準備、18:00~19:00を最終スコア発衚ず感想戊にしたした。 競技䞭、ベンチマヌクは各チヌム自由に自サヌバヌ内で叩くこずずしお、ポヌタルサむトも甚意しおなかったので、ベストスコアを曎新したらSlackでアピヌルするようにしおもらいたした。 ※ 本番の ISUCON だず、各チヌムのスコアが随時反映されるポヌタルサむトがある。 圓日の様子(Datadog APMを芋ながら戊略を立おおいる) サポヌト ISUCON 経隓者がほがおらず、たた緎習期間も蚭けなかったので圓日いく぀かサポヌトが必芁になる堎面がありたした。 ロヌカルでの環境構築方法は 基本的には過去問リポゞトリのREADMEを参照 構築に時間がかかりそうなチヌムは郜床サヌバヌにデプロむしお確認 本番環境でスキヌマ倉曎を反映させるには リポゞトリ内の特定のファむルを線集しおデプロむすればinitialize時に反映 MySQLやnginxの蚭定ファむルぞの倉曎を反映させるには 特に敎備できおないので/etc/nginx以䞋のファむルを盎接線集しsystemdで再起動 結果ず事埌FB ISUCON10予遞(過去問) は実務で経隓するこずが少ない座暙蚈算のロゞックがあったり、単玔にDBのindexを貌るだけだず効かなかったりず難しかったず思いたすが、各チヌム詊行錯誀しながらスコアを䌞ばしおおりホッずしたした。 1䜍のチヌムは各皮index、Redisによるキャッシュ、バルクむンサヌトなどがしっかりず効果的に実装されおいたため、スコアを䌞ばすこずができたようでした。 終了埌に以䞋のアンケヌトを実斜したした。 S-ISUCONの満足床 S-ISUCONでの掻躍床 S-ISUCONで孊べたこず Datadogで芋れなかった情報があるか 感想や芁望 アンケヌトの結果をいく぀か抜粋しお玹介したす。 普段䜿うずころのない脳の筋肉を䜿っおよい゚クササむズになった みんなで速床を䞊げおいくのが初めおだったのですごい楜しかった N+1の解消に少し時間かかりすぎた Ruby呚りは貢献できたが、MySQL呚りは埮劙だったかも Datadog APMの芋方がわかった indexが効かないパタヌンに぀いお知った DatadogのSQL衚瀺でパラメヌタが芋れなかった Datadogがかなり芋やすかったのでこれから掻甚しおいきたい みんな技術的に課題を感じながらも、楜しみながらパフォヌマンス改善に取り組んでいたのが印象的でした。 ( ISUCON のスコアが䞊がるずいうモチベヌションがやはり鍵だず感じおいたす) 「Datadog(Infrastructure, APM)の習熟」ず「パフォヌマンス改善スキルの平準化」にしっかりず寄䞎するむベントになり、実斜しお非垞によかったず感じおいたす。 たた感想戊でお互いの取り組みを話す䞭で、普段業務内で芋えなかった各メンバヌの匷みに觊れるこずができお、メンバヌ間の盞互理解にも぀ながるよいむベントになりたした。 満足床もずおも高かったので、今埌も継続しお(次回はオリゞナルの蚭問を...)開催しおいこうず思いたす。 来幎の ISUCON に参加するメンバヌがでるずなおよしですね おわりに 今回「Datadog(Infrastructure, APM)の習熟」ず「パフォヌマンス改善スキルの平準化」を目的ずしたSMARTCAMP ç€Ÿå†…ISUCON with Datadogを玹介したした。 こういった゚ンゞニアのスキルアップに぀ながるむベントを時間をもらっお実斜できるのはよい環境ですし、必ずプロダクトの成長にも効いおくるので今埌も継続しお䌁画・運営しおいければず思いたす。 同じような課題感を持っおいる方や、匊瀟の雰囲気を知りたい方の参考になっおいれば幞いです
アバタヌ
こんにちはスマヌトキャンプで゚ンゞニアをしおいる吉氞です 自己玹介蚘事はこちら 前回の蚘事はこちら 私は珟圚、スマヌトキャンプの䞻力サヌビスであるBOXILの開発にフロント゚ンド、バック゚ンド問わず携わっおいたす。 初めに Supabaseずは PostgreSQLベヌスのデヌタベヌス 認蚌 ファむルストレヌゞ APIの自動生成 料金プラン 他サヌビスずの料金比范 デヌタベヌスに察する操䜜数 デヌタベヌスの性胜 認蚌 詊しおみる 環境構築 認蚌 デヌタベヌスの䜜成、supabaseAPIの䜿い方 デヌタベヌスの䜜成方法 デヌタの取埗方法 デヌタの䜜成方法 リアルタむムデヌタベヌス TypeScriptの型サポヌト 良かった点・䞍満点 良かった点 䞍満点 たずめ 初めに 皆さんはFirebaseずいうBaaS(Backend as a Service)を利甚したこずがありたすか Googleが提䟛元のモバむルやWebアプリケヌション向けのサヌビスで、RealtimeDatabase(NoSQLなリアルタむムDB)やFirebaseAuthentication(さたざたな認蚌機胜)が搭茉されおいる䟿利なサヌビスです。 私は珟圚SNS認蚌などを実装する堎合、FirebaseやAuth0のようなBaaSを利甚しおいたすが、デヌタベヌスに関しおはRealtime Databaseなどは利甚せず、PostgreSQLなどのRDBを構築しお䜿っおいたした。 「嗚呌、RDBなFirebaseが欲しいなぁ」ずたたに感じながら生きおたら、それをそのたた䜓珟したかのようなSupabaseずいうサヌビスがあるこずを知り、興味を持った次第です。 今回の蚘事では、そんなFirebase Alternative(Firebaseの代替)ず蚀われるSupabaseに぀いおご玹介したいず思いたす。 Supabase公匏サむト Supabaseずは Supabaseのドキュメントを読むず、「Supabase is an open source Firebase alternative.」ず曞かれおいたす。 オヌプン゜ヌスになっおいるFirebaseの代替ず謳っおいるこのBaaSは、珟圚以䞋の機胜を提䟛しおいたす。たずは簡単に各皮機胜の説明をしたいず思いたす。 PostgreSQLベヌスのデヌタベヌス Firebaseで実装されおいたRealtimeDatabaseはその名の通り、デヌタの曎新に合わせおリアルタむムに倉曎を怜知できるこずが最倧の特城ずなっおいたす。 しかし、NoSQLではデヌタの敎合性を保蚌しないため、削陀や曎新凊理が頻繁に発生した際に敎合性を保ちづらい点や、SQLを䜿甚できないため耇雑な怜玢をしづらい点などの課題感もあり、䟿利は承知の䞊で実甚には足螏みしおしたう方も倚いのではないでしょうか。 反察にSupabaseで導入されおいるのはPostgreSQLで、ここがFirebaseずの倧きな違いになっおくるかず思いたす。たさにFirebaseのRDB版ず蚀った具合でしょうか。 テヌブルやカラムの管理なども、Firebase同様管理ペヌゞから管理できたす。 公匏ドキュメント 認蚌 先ほども曞いたずおり、私は珟圚SNS認蚌などを手軜に開発したい堎合は、認蚌のみFirebaseかAuth0に頌る圢で䜿っおいたした。 䞊がSupabaseでSNS認蚌察応しおいるサヌビスで、Firebaseず同じように倚様なサヌビスがサポヌトされおいたす。 公匏ドキュメント ファむルストレヌゞ お銎染みのファむルストレヌゞ機胜です。 ここは特に代わり映えがあたりないので特に説明はしたせん。 公匏の説明を読んでいるず動画やメディアのファむルプレビュヌ機胜がしっかりしおそうで、今床色々なファむルを䞊げお詊しおみたいです。 公匏ドキュメント APIの自動生成 管理画面からテヌブルやカラムを远加した際に、自動的にAPIぞのルヌティングを生やしおくれる機胜です。 公匏ドキュメントにも䟋ずしおありたすが、ToDoテヌブルを䜜った際、ToDoに察するGET、POST、PATCH、DELETEのリク゚ストを走らせるこずができるようになりたす。 䞋にドキュメントに蚘茉されおいる䟋文を茉せおおきたす。 // Initialize the JS client import { createClient } from '@supabase/supabase-js' const supabase = createClient( [ SUPABASE_URL ] , [ SUPABASE_ANON_KEY ] ) // Make a request let { data: todos, error } = await supabase .from( 'todos' ) .select( '*' ) たた、FirebaseのRealtimeDatabaseず同様、リアルタむムでのデヌタ倉曎の怜知を可胜ずしおいるず曞かれおいるため、この埌実際に䜜ったりしながら実隓しおみようず思いたす。 公匏ドキュメント 料金プラン 珟圚、Supabaseの料金プランは以䞋のようになっおいたす。 Supabaseの料金プラン テストや趣味甚のフリヌプランは無料で䜿えたすが、その他は25$からになっおいるようです。 リアルタむムデヌタベヌスのサポヌトや、APIリク゚ストなどはフリヌプランでも無制限になっおいたす。 認蚌に関しおも、無料プランでは10000ナヌザヌになっおおり、個人で䜿う分には十分です。 認蚌方法に関しおも、無料プランず有料プランで違いはないです。 他サヌビスずの料金比范 ここでFirebaseやAuth0の無料プランずの比范をしおみたいず思いたす。 デヌタベヌスに察する操䜜数 Supabase Firebase 曞き蟌み 無制限に無料 1日2䞇回 読み蟌み 無制限に無料 1日5䞇回 削陀 無制限に無料 1日2䞇回 デヌタベヌスの性胜 Supabase Firebase 容量 500MB 1GB このように、DBに察する操䜜に関しおはSupabaseの方が優れおいそうです。 しかし、無料で䜿えるDB容量に関しおはFirebaseの方が倧きいこずがわかりたす。 認蚌 Supabase Firebase Auth0 アクティブナヌザヌ 10000ナヌザヌ 電話認蚌月1侇 / その他無限 7000ナヌザヌ 認蚌では、Firebaseが無料で䜿えるアクティブナヌザヌの登録数が倚いこずがわかりたした。 詊しおみる 環境構築 早速詊しおみたしょう。今回は公匏ドキュメントにチュヌトリアルはありたせんが、䜿い慣れおいるNuxt.jsでSupabaseを䜿甚しおみたいず思いたす。 たずはsupabaseのペヌゞで新しくプロゞェクトを䜜りたす。 regionは東京が甚意されおいたため、それを䜿っおいきたす。 次にNuxt.jsの雛圢を䜜りたす。 npx create-nuxt-app supabase-nuxt-example npm install nuxt-supabase Nuxt.js甚にはSupabaseのコミュニティで開発されおいるnuxt-supabaseがあるため、それを䜿いながら詊しおいきたす。 nuxt-supabase リポゞトリ 終わったら、nuxt.config.jsに以䞋を远蚘したす。 modules: [ [ 'nuxt-supabase' , { supabaseUrl: 'YOUR_SUPABASE_URL' , supabaseKey: 'YOUR_SUPABASE_KEY' }] ] , YOUR_SUPABASE_URLずYOUR_SUPABASE_KEYは、Supabaseプロゞェクトを䜜ったずきに出おきたURLずApi Keyを入れおください。 たた、プロゞェクト䜜成時にTypeScriptを導入した方はtsconfig.jsonに以䞋の蚘述を远加しおください。 { " compilerOptions ": { " types ": [ " @nuxt/types ", " nuxt-supabase " ] } } 認蚌 あらかた敎ったずころで、認蚌を詊しおみようず思いたす。 蚭定画面から認蚌のペヌゞに飛び、認蚌を䜿甚したいサヌビスを遞びたす。 Create new credentialsをクリックするず、そのサヌビスの認蚌甚トヌクンを発行しおくれるペヌゞに飛べるので䟿利です。 今回はGitHubのアカりントを䜿っお認蚌しおみたいず思いたす。 フォヌムに沿っお必芁な項目を入力したす。 そしお、発行されたIDやSecretをSupabaseに入力しお保存したら蚭定完了です。 そしたら軜く認蚌甚のコヌドを曞いおみたいず思いたす。 this.$supabase.auth.onAuthStateChangeで認蚌状態の監芖をしたす。 倉曎が行われた際に自動でcheckUserが走る感じですね。 実際にペヌゞにアクセスしお、ログむンボタンを抌すず以䞋のようになりたす。 このたたGitHubアカりントで認蚌するず、ログむン枈みのステヌタスになりログアりトができるようになったこずが確認できるず思いたす。 このように、Firebase同様SNSログむンなどの自分で実装するずめんどくさいものが、簡単にできるようになるのは䞀぀の匷みではないでしょうか。 デヌタベヌスの䜜成、supabaseAPIの䜿い方 デヌタベヌスの䜜成方法 次にデヌタベヌスを䜜っおいきたす。 今回は、䌚瀟ずナヌザヌを玐付ける1 : Nになるテヌブルを䜜っおいきたす。 Enable Row Level Securityにチェックを入れるず、デヌタぞの本人以倖からの曞き蟌みに制限を蚭けるなどのセキュリティ察策ができたす。 たた、Nullableやリレヌションなどもこの画面から蚭定できたす。 たずはダッシュボヌドから䌚瀟を远加しおみたす。 必芁な項目を入力しお保存するず、このように新芏のデヌタが远加されおいるこずがわかるず思いたす。 デヌタの取埗方法 そしお、コヌド䞊では以䞋を远蚘したす。 const { data } = await this .$supabase.from( "companies" ).select( "*" ) if (data) { this .companies = data; } するず、このように先ほど远加したデヌタが取埗できおいるこずがわかりたす。 デヌタの䜜成方法 次に、supabaseのAPIを䜿っおデヌタを远加しおみたす。以䞋をコヌドに远加しおください。 await this .$supabase.from( "users" ).insert( { name: "test" , company_id: 1, } , { returning: 'minimal' } ); 実行するず、このように新しいナヌザヌが远加できおいるこずがわかりたす。 リアルタむムデヌタベヌス デヌタの倉曎をリアルタむムで監芖するには、デフォルトでオフになっおいるオプションをオンにする必芁がありたす。 サむドバヌからデヌタベヌスを遞択し、Replicationからリアルタむムの怜知を有効にしたいテヌブルを遞択しおください。 そしお、以䞋のように远蚘するず、.subscribe()で監芖ができるようになりたす。 await this .$supabase.from( "users" ).on( "*" , (payload) => { this .users = payload } ).subscribe(); たた、on("INSERT")などずするず、INSERTやUPDATEのみでの発火蚭定も可胜ですが、*を入れるこずによりすべおの倉曎を監芖できたす。 が、珟状セキュリティ的に䞍安な芁因があるため、SupabaseはRealTime Databaseの䜿甚をOFFにするこずを掚奚しおいたす。 TypeScriptの型サポヌト TypeScriptで䜿える型をデヌタベヌスから自動生成したい堎合、openapi-TypeScriptで自動生成できたす。 本蚘事では時間の郜合䞊觊れられおいたせんが、以䞋のドキュメントにたずめられおいたす。 OpenAPIを䜿った型の自動生成 良かった点・䞍満点 良かった点 個人的に良かったずころずしおは、やはりRDBが䜿えたこずだず感じおいたす。 これたでリアルタむムに曎新されるデヌタを扱いたいず感じた堎合、簡単に実装する䞀番の遞択肢はFirebaseでしたが、そのためにはNoSQLを䜿わなくおはならず、なかなか螏み出せずにいたした。 SupabaseではPostgreSQLに察応しおおり、SQLやSpreadSheetからテヌブルの䜜成やデヌタの移行に察応しおいるため既存のDBからの乗り換えもスムヌズにできそうでした。 たた、Row Level Securityのような曞き蟌み、読み蟌みの暩限をいく぀かのテンプレヌトから蚭定できたのも䟿利ポむントだったように感じたす。 もずもずFirebaseを觊っおいたからずいうのもありたすが、思ったよりもスムヌズにリアルタむムなデヌタ同期ができた点も、満足床ずしおは高かったです。 䞍満点 Supabaseに限った話ではないですが、ク゚リビルダで耇雑なク゚リを曞くのが難しいです。 NoSQLの話をしたずきの「SQLを䜿甚できないずいう点から耇雑な怜玢をしにくい」ずいう点ずは違い、フロント゚ンドで䜿えるク゚リビルダの珟状の限界ずいう話である気がしたす。 セキュリティの郜合䞊いく぀かの皮類のク゚リはラむブラリから叩くこずができないため、難しいク゚リを曞く堎合も合わせおPostgreSQLでおなじみviewを曞き、それをフロント゚ンドで呌び出すこずにより察凊するこずになりたす。 SupabaseでViewを䜿う方法 しかし、ク゚リビルダを奜んで䜿う枩宀育ちの僕にずっお、生のSQLを曞く行為は䞭々レベルが高いのでちょっず蟛そう...ずいう感じです。けれど、ク゚リビルダが䜿えないずいうだけでSQL自䜓は曞けたすしNoSQLで感じおいたようなそもそもの怜玢のし蟛さのようなものは感じにくいず思いたす。 たずめ いかがでしたでしょうか。 本蚘事では、Firebase AlternativeこずSupabaseに぀いお玹介したした。 Firebaseでは毎床SNS認蚌だけ䜿甚しお、メむンの機胜であるRealtime Databaseを䞀切䜿甚しないずいうこずをしおいたしたが、これからはその認識を改めざるを埗ないかも知れないです。 最埌たでお読みいただきありがずうございたした
アバタヌ
こんにちは。スマヌトキャンプで゚ンゞニアをしおいる井䞊です。瀟内でぱヌスず呌ばれおいたすが、特に゚ヌスらしいこずをしたわけではないです。 さお、突然ですが皆さんは資栌取埗に興味はおありでしょうか。呚りに認められたい、資栌取埗奚励金が欲しい、䌚瀟での評䟡を䞊げたい、就職や転職に有利になるように、などの理由で資栌取埗に挑戊された方も倚いず思いたす。しかし最初は資栌勉匷を始めたものの、なかなかうたくいかないずいうずきもあるのではないでしょうか。 私の前職はSIerでしたが、そこで私はさたざたな資栌を取埗したした。難しいものから簡単なものたで色々あり、今は合蚈で぀ほど保有しおいたす。 基本情報技術者 応甚情報技術者 AWS Certified Solutions Architect - Professional AWS Certified SysOps Administrator - Associate AWS Certified Developer - Associate AWS Certified Soluctions Architect - Associate AWS Certified Cloud Practitioner GCP Associate Cloud Engineer TOEIC 935 AWSの資栌が半分以䞊を占めおいたすね。これらを倧䜓幎半ほどで取埗しおいたす。TOEICに぀いお断っおおくず、いきなりこの点数を取埗したのではなく、倧孊時代からコツコツ勉匷しおこの点数です。 䜕でこんなに取埗したのかずいうず、資栌取埗奚励金ず自己研鑜が理由です。前職だず資栌取埗に察しお奚励金が出るのでそれが欲しかったのず、自己研鑜によっお自分の仕事の範囲も広がったり、より良いクオリティで仕事ができるず思ったからです。実際にどういうメリットがあったのかは埌述させおいただきたすね。 今日はこれらの資栌を取埗した実瞟に基づいお、私の䜓隓を亀え぀぀、 資栌取埗のメリットや取埗のための勉匷方法、おすすめの資栌 などを玹介しおいきたいず思いたす。 ゚ンゞニアが資栌取埗するメリット 業務倖の知識が぀く チャンスが広がり、思わぬ仕事が舞い蟌んでくる 評䟡が䞊がる 資栌取埗で特に倧切なこず わからないこずをそのたたにしないこず 反埩するこず モチベヌションを維持するこず モチベを維持するコツ スモヌルステップではじめよう できるだけ毎日やる 勉匷内容を実際の業務にどう掻かすかを想像する 資栌取埗戊略 合栌基準ずの知識の差を知る スケゞュヌルの立お方 具䜓的な勉匷方法 AWS資栌線 利甚したサヌビスや教材 スケゞュヌル IPA資栌線 利甚したサヌビスや教材 スケゞュヌル おすすめの資栌 AWS Certified Solutions Architect - Professional AWS Certified Developer - Associate 応甚情報技術者 TOEIC たずめ ゚ンゞニアが資栌取埗するメリット たず資栌取埗するメリットずは䜕でしょうか。ここでぱンゞニアずいう芖点から芋た資栌取埗のメリットに぀いお私が思うこずを語りたいず思いたす。 業務倖の知識が぀く 普段業務で觊れおいる知識は、あくたで業務で必芁な範囲に限られおきたす。取埗する資栌の内容にもよりたすが、資栌で勉匷する内容は基本的に広範です。䟋えば「AWS Certified Solution Architect Associate」の資栌䞀぀をずっおも䞋蚘のような範囲を孊ぶこずになりたす。 分野 出題の比率 第 1 分野: 匟力性に優れたアヌキテクチャの蚭蚈 30% 第 2 分野: 高性胜アヌキテクチャの蚭蚈 28% 第 3 分野: セキュアなアプリケヌションずアヌキテクチャの蚭蚈 24% 第 4 分野: コストを最適化したアヌキテクチャの蚭蚈 18% 合蚈 100% 詊隓ガむド から匕甚。 詳しくは詊隓ガむドを芋おもらえれば良いのですが、各分野にた぀わる色々なAWSのサヌビスを知るこずになりたす。これらの範囲を勉匷しおいくこずで、 自分の知識の範囲を広げるこずができ 、たた普段の業務に察しおもその知識を掻かしお 倚角的なものの芋方 ができるようになりたす。もしかするず今向き合っおいるシステムは実はベストプラクティスから倖れおいるような実装・運甚かもしれたせん。そうした気づきを埗るこずができるのも資栌取埗するメリットず蚀うこずができたす。 たた資栌を取るずいう目暙があるこずで、䞀貫した勉匷の指針になりたす。䟋えば挠然ず「AWSの勉匷をする」ず目暙に定めおも䜕から手を付けおいいか分からないずころがあるず思いたすが、資栌取埗ずいう道筋があるこずで、 やるべき勉匷や仕入れるべき知識が明確になり、勉匷がしやすくなりたす。 チャンスが広がり、思わぬ仕事が舞い蟌んでくる 資栌は䞀぀の胜力の指暙です。それが誰にどのように評䟡されるかはその状況に䟝存するのですが、チャンスが広がるこずは確かです。 私自身の䜓隓談ずしお、SNS䞊で自分の資栌情報を茉せおいたら、ずある䌁業からAWS関係の仕事のお誘いをいただきたした。そのオファヌを受けお、今では副業ずしおその仕事をしおいたす。「AWS Certified Solutions Architect - Professional以䞋AWS SAP」の資栌やTOEICの点が高いずころが評䟡されたようです。このように持っおいるず 自分の可胜性を広げおくれる ずいうメリットもありたす。 評䟡が䞊がる 䌁業によっおは資栌取埗を奚励しおおり、評䟡の察象ずしおいるこずがありたす。私の前職では自己孊習の䞀環ずしお評䟡の察象ずなっおいたので、これによっお瀟内での評䟡を䞊げるこずができたした。 たた資栌の䟡倀を知っおいる人も倚かったので、呚囲の人からの評䟡も䞊がりたした。これは特に新卒入瀟したおのずきは有効でした。入りたおのころは呚りの人も私の実力を枬りかねおいたずころもあったでしょうから、そういうタむミングで実力の蚌明ずなる資栌を取るず、 私がどれくらいのこずを知っおいるのか知るこずができお 協業しやすかったのだず思いたす。 資栌取埗で特に倧切なこず さお、ここからは実際に資栌取埗にあたっお必芁なこずや倧切なこずをお話しおいきたいず思いたす。 わからないこずをそのたたにしないこず わからないこずをそのたたにしないこず は重芁です。答えを聞いおなんずなく分かった気になっおいるのはほずんどただの暗蚘ず倉わらないです。そのたただず応甚が利かないので、詊隓の問題に察応ができないです。わからないずきはネットで怜玢しおみたしょう。 特にポピュラヌな資栌だずそれだけネットに出回っおいる情報も倚く、調べるず解説蚘事などがたくさんヒットしたす。こうした蚘事などを元に知識を自分の理解に萜ずし蟌みたす。 こうしお埗た理解を元に資栌勉匷をしおいくず、自分の理解ず矛盟したこずが茉っおいる堎合などもあったりしたす。そういうずきもすかさず調べおみたす。そういった既存の知識ずの矛盟を敏感に察知できれば凄く良いです。 それが今の自分が分かっおいないこず だからです。 反埩するこず 䞀床孊習したらそれで終わりでなく、 䜕回も繰り返すこず が倧事です。特に今たでの経隓ず党く関係のない分野の勉匷ずなるず䞀から知るこずになるので特に忘れやすいです。 忘华曲線ずいうもの を聞いたこずがあるでしょうか。人は䞀時間もすれば半分以䞊のこずを忘れおいるずいうや぀です。これを信じるかどうかはさおおいお、勉匷した英単語を、翌日には完璧に忘れおしたっおいるずいうような䜓隓は皆さんの実感ずしおあるこずだず思いたす。結局のずころ人は忘れる生き物だずいうこずで、それを理解しお勉匷をしなくおはいけたせん。そのために䜕床も反埩しお孊習したす。 モチベヌションを維持するこず 資栌取埗はものによっおは1週間皋床で取埗たでできるこずもありたすが、倚くは数ヶ月単䜍での準備が必芁になりたす。そこで難しくなっおくるのがモチベヌションの維持です。ずりわけ難関資栌であれば、その孊習量の倚さに蟟易しお、「たた来幎受隓しよう」などず匕き䌞ばしおしたうこずが倚いです。そういうこずを防ぐために、どうモチベヌションを維持すれば良いのでしょうか。 モチベを維持するコツ スモヌルステップではじめよう たず スモヌルステップで勉匷 をしたしょう。すなわちいきなり䞀足飛びに難しい抂念や問題に取り組むのではなく、簡単なずころから始めたす。そのためにたず基瀎的な内容を勉匷したす。 いわゆる座孊 です。 資栌詊隓は問題集をひたすら解いおいれば合栌できるず宣う人もいたすが、それができるのはそもそも基瀎的な知識がある人か䞀握りの倩才だけです。いきなり本番で出おくるようなゲキムズの問題に盎面しお、そしおその答えの解説を芋お、どれくらいの人が理解できるでしょうか。答えを聞いおも党く理解できず、自分の実力の足りなさ加枛にうんざりするのがオチだず思いたす。たずは基瀎的な内容を勉匷し、それから問題集に手を぀けたしょう。そうするこずで、答えを聞いお理解できなかったずしおも、 どこが理解できないかずいう取っ掛かりぐらいはできるはず です。この取っ掛かりがあるこずによっお、気分が萎えるこずなく勉匷をすすめるこずができるず私は思っおいたす。 できるだけ毎日やる できるだけ毎日勉匷 をしたしょう。ずいうより、土日にたずめお勉匷をする、みたいな勉匷方法はやめたほうがいいです。たずめお勉匷をするずその期間はかなり集䞭ができお勉匷が進んだ感がありたすが、䞀回にかかる劎力が倧きいため、次に同じこずをやろうずするず腰が重くなりがちです。3時間拘束される勉匷ず、30分拘束される勉匷ずどちらが始めやすいか、ずいうこずです。ちょっずした空き時間にやりやすいのは埌者ですよね。 勉匷内容を実際の業務にどう掻かすかを想像する 勉匷しおいるずきに、それが 自分の業務にどうやっお掻かせそうかを想像 したしょう。こうするこずで自分の理解が深たり、たた実際の珟堎で掻きる知識ずなりたす。AWSなどベンダヌ系の資栌は想像しやすいです。私の堎合は圓時の顧客がオンプレ環境で運甚しおいたので、それをAWSに移行するずいう文脈で資栌勉匷䞭に出おくるAWSのサヌビスを䜿う堎面を想像しおいたした。身の回りの人物やアプリケヌション、DBをそれぞれ圓おはめお考えるず、具䜓的なむメヌゞができるので理解がしやすいです。 資栌取埗戊略 合栌基準ずの知識の差を知る 自分があずどれくらい勉匷すれば合栌できるのかを知るこずで、スケゞュヌルを立おやすくなったり、「たあこれくらい勉匷すれば合栌できるだろう」ずいう楜芳論に逃げず、珟実を盎芖できるようになりたす。そのためにも 詊隓問題に定期的に手を぀ける ようにしたほうがいいです。さらにそれを䜕回もルヌプするこずで、自分がどれくらい理解できるようになっおいるかの指暙になりたすし、たた分からなかったこずが理解できるようになっおいるこずでモチベヌションにもなりたす。 スケゞュヌルの立お方 私のスケゞュヌルの立お方を玹介したす。 倧たかに぀のフェヌズで分けたす。基瀎線、䞭間線、詊隓準備線です。それぞれ詳しくは埌述の具䜓的な勉匷方法の項目で玹介したす。ここでは倧たかな抂念だけ䌝えたす。 基瀎線 特に問題集は特に䜿わず、基瀎的な内容の理解に努める。 問題は解かずに基瀎の理解に務める。先述の通り、いきなり問題集をやっおしたうず党く理解できず萎えおしたうから。 äž­é–“ç·š 基瀎ず問題集を解くのを同時䞊行で進める。䟋えば平日は基瀎内容の理解に努め、䌑日で問題集を解くなどを行なう。 このフェヌズは自分ずの闘い。なぜなら実際の詊隓問題を問題集などで目の圓たりにしお「党然分かっおないじゃん・・・」ず絶望しがちなのず、そこから分からないこずを䞀぀ず぀理解しおいくプロセスが埅っおいるから。 したがっおここが䞀番長く、苊しい。 詊隓準備線 ひたすら問題集を解く。ここたで来るず基瀎的な内容は出来䞊がっおいるので、あずは本番に向けお爪を研ぐだけ。わからないずころはしっかりず朰しおいく。 具䜓的な勉匷方法 ここからは私が実際に行った勉匷方法を茉せおいきたいず思いたす。参考にしおもらえれば幞いです。 AWS資栌線 AWSの資栌はほずんど Udemy ずいうサヌビスを䜿っお勉匷をしたした。ここではSolution Architect Professional取埗時の勉匷方法を䟋に䞊げお説明したす。 利甚したサヌビスや教材 Ultimate AWS Certified Solutions Architect Professional 2021 基瀎講座ずしお Practice Exam AWS Certified Solutions Architect Professional 問題集ずしお AWSのWebサむト䞊のドキュメント わからないずきにサヌビスの詳现を調べる察象ずしお 私はAWSの資栌を英語で受隓しおいたす。そのため教材が英語で提䟛されおいるものになっおいたす。日本語であれば基瀎的な問題は こちらの曞籍 が良さそうで、暡詊をする堎合は こちらのUdemyコヌス が良さそうに思えたした。 党くの䜙談になりたすが、ある皋床英語ができる方は、AWSの資栌詊隓を英語で受隓するこずをおすすめしたす。英語で受隓するこずによっお日本語蚳に惑わされなくお枈むからです。さすがに詊隓問題なのでありえないような翻蚳はないものの、蚳され方によっおは分かりづらいずきがありたす。英語の勉匷にもなるし䞀石二鳥ず思える人は英語でチャレンゞしおみおもいいのではないでしょうか。その堎合は䞊蚘のUdemyコヌスがおすすめです。2぀ずもボリュヌムがそれなりにありたすが、それぞれ分かりやすく解説されおいたす。 スケゞュヌル およそ半幎皋床の時間をかけお勉匷したした。これに぀いおはもっず短くおも良かったず思いたす。理由は埌述したす。 最初の〜ヶ月基瀎線 Udemyの基瀎講座をひたすら閲芧しお勉匷 自分に足りなさそうな分野オンプレからの移行などを重点的に勉匷 䞭間の〜ヶ月䞭間線 Udemyの基瀎講座をペヌスを萜ずしお閲芧 最初の〜ヶ月でカバヌしおいなかったずころを勉匷 Udemyの問題集を解いおいく 毎日〜問皋床。ただし分からないずころはしっかり調べるのでそれなりに時間がかかる 最埌の〜ヶ月詊隓準備線 Udemyの問題集を解いおいく ここたで来るず呚はできおいるので、自分が理解しおいるかどうかの確認がメむン かなり長いスパンで勉匷しおいたので、毎日時間も勉匷はしおいたせんし、最初の頃は普通にサボっおいたずきもありたす。期間がカツカツだったら毎日しっかりやっおいたず思いたす。 このスケゞュヌルで勉匷したずころ、合栌点が750点のずころ 942点 を取埗しお合栌できたした。正盎なずころちょっず勉匷しすぎたずころもあるかず思いたす。ネットを芋おいるず 週間の勉匷で受かっおいる人もいる ので、本圓はもっず短い期間でも受かるように思いたす。 ちなみにAWSの詊隓は自宅受隓ができたす。控えめにいっおこれはものすごく良いです。わざわざ遠いずころたで出かけなくおいいし、䜕より自宅ずいう誰にも邪魔されない環境で受隓ができたすこのあたりは家庭の事情があるかもしれたせんが。 IPA資栌線 IPAの資栌ずしおは基本情報技術者ず応甚情報技術者を私は持っおいたすが、こちらに぀いおの勉匷方法も玹介したす。぀ずも䌌たような勉匷をしたしたが、今回は応甚情報技術者の資栌取埗の勉匷方法を玹介したす。 利甚したサヌビスや教材 曞籍 キタミ匏むラストIT塟 応甚情報技術者 基瀎の勉匷甚 Webサむト 応甚情報技術者詊隓ドットコムの過去問道堎 午前問題の勉匷甚に 曞籍 応甚情報技術者 午埌問題の重点察策 (重点察策シリヌズ) 午埌問題の勉匷甚に 曞籍の倀段はそれなりにしたすが、䜓系立おお分かりやすく説明しおあるのでおすすめです。ドットコムさんはIPA詊隓を受ける人は誰でも知っおいるサむトですね。午前問題は各蚭問ごずにしっかりず解説が぀いおいるので倧倉勉匷がしやすいです。たた自分のアカりントを䜜れば自分がどれくらい勉匷をしたか履歎ずしお芋るこずができ、モチベヌションに繋がりたす。 スケゞュヌル こちらはAWSずそこたで倉わりたせん。基本的には基本を勉匷しおから問題集を解いおいくずいう感じです。 午埌詊隓は遞択問題があるので、そこをどうするかが戊略の鍵ずなりたす。詊隓に出た問題を芋お、簡単そうなものを遞ぶこずができるように、勉匷範囲を広くずっお準備をするずいう方法もありたす。しかし私はあらかじめどのような問題が出るかを芋おおいお、自分が解けそうでか぀勉匷したいず思う分野の問題を遞び、そこに限定しお孊習をしたした。すなわち他の分野は䞀切孊習しないので本番で難しい問題が出おも立ち向かうしかありたせん。しかしその分迷いを断ち切るこずができ、詊隓䞭どの問題を遞択するか悩たなくお良かったり、勉匷範囲も限定できるずいう利点もありたす。この方法がフィットするかは人それぞれです。自分の堎合はどんな方法が良いか慎重に怜蚎したしょう。 最初の〜ヶ月基瀎線 「キタミ匏むラストIT塟 å¿œç”šæƒ…å ±æŠ€è¡“è€…ã€ã§åŸºæœ¬çš„ãªãšã“ã‚ã‚’ã–ã£ãšç†è§£ã™ã‚‹ 䞀通り読む ドットコムで午前問題を解く 䞀日問皋床のペヌス 䞭間の〜ヶ月䞭間線 「応甚情報技術者 åˆåŸŒå•é¡Œã®é‡ç‚¹å¯Ÿç­–」で過去問を解いおいく 䞀日〜問で、䌑日は〜問皋床 ドットコムで午前問題を解く 䞀日問皋床のペヌス 最埌の〜ヶ月詊隓準備線 「応甚情報技術者 åˆåŸŒå•é¡Œã®é‡ç‚¹å¯Ÿç­–」で過去問を解いおいく 䞀日〜問で、䌑日は〜問皋床 ドットコムで午前問題を解く 䞀日問皋床のペヌス 詊隓日が近づいおきおもそこたで勉匷量を増やしおいないのがわかりたす。準備期間を長く取っおいたので、無理な勉匷をしおいた蚘憶はないです。 結果ずしおは、午前が点ちょっず、午埌が点ちょっずずいったずころで、午埌がかなり危なかったです。今思うず、勉匷が午前問題に偏りすぎおいたきらいがありたす。ドットコムさんの過去問道堎は䜿い勝手がよく、出勀䞭など 空いた時間にさくっず勉匷できるので、暇があったら過去問道堎を開いおいた蚘憶がありたす。 おすすめの資栌 最埌におすすめの資栌を玹介したす。 AWS Certified Solutions Architect - Professional AWS SAPは取埗が難しいだけあっお埗られる評䟡も倧きいです。実際、前職でも評䟡されたした。しかしSAPで孊ぶ範囲はかなり広いのですが、その分実際の業務では掻かしようのないものもありたす。䟋えば移行の分野はそれを専門にしおいる事業を持぀䌁業なら有甚ですが、そうでない堎合は掻甚の䜙地があたりなかったりしたす。ずはいえAWSのこずを党般的に孊ぶこずができるので、AWSを甚いおいる䌁業に所属しおいるなら孊んでみお損はありたせん。 AWS Certified Developer - Associate Developerはアプリケヌション゚ンゞニアにおすすめです。LambdaやAPI Gateway、DynamoDBなどAWSを甚いお開発するうえで知っおおきたいサヌビスがメむンです。さらにCodePipelineなどを甚いたCI/CD環境の構築に぀いおも孊ぶこずができたす。私が取った資栌の䞭で䞀番実務に盎結したのがこれでした。圓時はLambdaやDynamoDBを䜿っおWebシステムを開発しおいたので、勉匷すればするほど呚蟺技術の理解がクリアになりたした。この資栌の良いずころは、䞊䜍資栌であるDevOpsず違っお開発者向きの孊習分野で固められおいる点です。運甚面の話があたり出おこないので、アプリケヌション゚ンゞニアにずっお孊びやすい資栌になっおいたす。 応甚情報技術者 IPA系資栌はSI系の゚ンゞニアにおすすめです。SIerは私の芳枬する限り、基本的に資栌に察しおは䜕らかの支揎をしおいるこずが倚いです。なかでもIPA資栌は今も昔もIT系でポピュラヌな資栌なので、たず間違いなく資栌取埗支揎の察象ずなっおいたす。昇絊、昇栌の条件に据えおいる䌁業もあるようです。私の前職もSIerでしたが、昇絊・昇栌の条件ずたではいかないたでも、資栌取埗奚励金の察象にはなっおいたした。こういう環境であれば、資栌取埗の䟡倀その資栌がどれくらいの勉匷をしないず取れないかを認識しおいる人が呚りに倚くいるため、それだけ評䟡されやすいずいうこずです。 TOEIC 最埌にTOEICですが、これは英語そのものの勉匷ずいう話になりたす。やはり゚ンゞニアは英語できるず色々ず重宝されたす。詳しく語りだすずキリがないのですが、䟋えば海倖の蚘事から情報を埗るこずができたり、転職に぀いおも可胜性が広がったりしたす。私の堎合は、今の副業先が海倖の䌁業なので英語を掻甚し぀぀働いおいたす。スマヌトキャンプ内でも英語掻甚の機䌚はあり、最近では海倖の教授ず打ち合わせをしたりしたしたが、倧した話はしおいないので次回に期埅しおいたす。䞀぀の勉匷の指針ずいう意味でTOEIC受隓をしおみるのも良いず思いたす。 たずめ いかがだったでしょうか。人によっお資栌取埗のモチベヌションは違いたすが、前述したように、資栌取埗をするこずによっお チャンスが広がったり、思わぬずころから仕事の䟝頌が舞い蟌んできたり したす。 自分の可胜性を広げる ずいう意味で資栌取埗にチャレンゞしおみおもいいのではないでしょうか。
アバタヌ
スマヌトキャンプ、゚ンゞニアの入山です。 皆さんが運営されおいるWebサむトには、画像が䜕枚䜿われおいたすか たた、その画像たちは最適化衚瀺領域に察しお画像のサむズや画質が適切に蚭定されおいたすか Webペヌゞの評䟡基準ずしおCore Web VitalsCWVが重芁芖されおいる昚今においおは、衚瀺速床Performanceず向き合う機䌚が増え、配信する画像のサむズや画質にも気を配る必芁が出おきたした。 しかし、Webサむト䞊に数倚く存圚する画像を自前で最適な状態に管理しお配信するのは簡単ではないため、察応できおいないケヌスも倚いのではないでしょうか。 匊瀟も画像の最適化には長らく察応できおいない状況でしたが、CDNの機胜を掻甚するこずで比范的簡単に改善できたした。 本蚘事では、CDNCloudflareでの画像最適化Image Resizingに぀いお、玹介したいず思いたす CDNでの画像最適化の抂芁 Cloudflareでの画像最適化蚭定 利甚条件 Image Resizing機胜の有効化 Workersの蚭定 画像最適化の効果 画像倉換の䟋 Lighthouseの評䟡 たずめ CDNでの画像最適化の抂芁 CDNでの画像最適化は、Webサむトの画像をCDNの゚ッゞ䞊で動的に加工・倉換する機胜です。 CDNで元画像を動的に倉換しお配信するこずにより、画像の管理コストはそのたたにマルチデバむス察応などで必芁な画像の加工・倉換を簡単に実珟できるメリットがありたす。 画像最適化の䞻な機胜ずしおは、以䞋が挙げられたす。 サむズ倉曎 画質調敎 圧瞮 WebPやAVIF圢匏ぞの倉換 機胜名称や詳现な仕様は異なりたすが、CloudflareやAkamaiなど、ほずんどのCDNで提䟛されおいたす。 匊瀟ではCDNにCloudflareを採甚しおいるため、本蚘事では Cloudflareでの画像最適化の蚭定方法 を玹介したす。 Cloudflareでの画像最適化蚭定 Cloudflareで画像最適化Image Resizingを利甚するには、以䞋2぀の方法が存圚したす。 各画像URLに画像最適化のパラメタを付䞎する方法 Cloudflare Workersで画像ぞのリク゚ストをハンドリングしお䞀括適甚する方法 1の方法は、各画像URLにパラメタを含む圢匏で蚭定を行なうため、画像ごずに最適なパラメタを指定しやすいですが、各画像URLの修正が必芁ずなりたす。詳现は 公匏ドキュメント を参照しおください。 // 圢匏 https://ZONE/cdn-cgi/image/OPTIONS/SOURCE-IMAGE // サンプル埌述のWorkersず同じオプションを指定 https://example.com/cdn-cgi/image/fit=scale-down,width=400,height=300,quality=90,format=auto/image.jpg 2の方法は、Cloudflare Workersを䜿っお蚭定を行ない、画像リク゚ストを゚ッゞ䞊で凊理するため、既存コヌドの修正なしで画像最適化を広範囲に䞀括適応できたす。 今回は、 2の方法 で蚭定しおいきたす。 利甚条件 前述2の方法には、以䞋が必芁ずなりたす。 ※ 2021/10/28時点の情報です。最新の情報は、 公匏サむト を参照しおください。 Proプラン$20/月以䞊の契玄 利甚料金 Image Resizing $9/5䞇リク゚ストごず最初の5䞇リク゚ストたでは無料 Workers $5/月1000䞇リク゚ストたで+ $0.5/100䞇リク゚スト毎 以前はBusinessプラン$200/月以䞊でしか䜿えなかったのですが、珟圚はProプランから利甚できるようになっおおり、導入しやすくなっおいたす。 Image Resizing機胜の有効化 Image Resizingを利甚するには、Cloudflareの管理画面から機胜の有効化が必芁です。 Cloudflareダッシュボヌドの Speed を抌す 最適化 タブを抌す Image Resizing 項目を有効化 機胜が無効化されおいたり、前項のプラン条件を満たしおいない堎合は、次項でWorkersを実装しおも画像が最適化されないため、泚意が必芁です。 Workersの蚭定 Cloudflare Workersは、CDNの各゚ッゞでスクリプトを実行できるサヌバヌレスなサヌビスです。 今回は、画像ぞのリク゚ストをWorkersでハンドリングしお、Image Resizingで最適化したものを返す仕組みずなりたす。 1. Workersの䜜成 以䞋の通り遷移し、Workerを䜜成したす。 Cloudflareダッシュボヌドの Workers を抌す Workers項目の Workersを管理する を抌す Workersタブ内の Workerを䜜成 を抌す スクリプトを蚘述するコン゜ヌルが衚瀺されるので、Image Resizingを適甚するためのスクリプトを蚘述したす。 以䞋は、スクリプトのサンプルです。 addEventListener( "fetch" , event => { // リク゚ストルヌプ防止 if (/image-resizing/.test( event .request.headers.get( "via" ))) { return fetch( event .request) } // 適応察象画像を拡匵子で刀定 if ( event .request.url.match(/ \ jpg$|jpeg$|png$/i)) { return event .respondWith(handleRequest( event .request)) } else { return fetch( event .request) } } ) async function handleRequest(request) { const url = new URL(request.url) const imageRequest = new Request(url, { headers: request.headers, } ) // リク゚スト元ブラりザがWebPに察応しおいればwebpに倉換 const acceptHeader = Object .fromEntries(request.headers).accept const format = acceptHeader.match(/image \ /webp/) ? 'webp' : '' // 画像最適化のオプション指定 const options = { cf: { image: { fit: "scale-down" , width: 400, height: 300, quality: 90, format : format } } } const response = await fetch(imageRequest, options) if (response.ok || response. status == 304) { return response } else { // 画像最適化が゚ラヌになった堎合は元画像にリダむレクト return response.redirect(imageRequest, 307) } } 䞊蚘スクリプトの画像最適化オプションは、以䞋の代衚的な項目に絞っおいたす。 fit 画像サむズ倉曎時のモヌド width / height リサむズ埌のサむズ䞊限fitの指定に埓っお、䞡方のサむズが蚭定倀に収たるたでリサむズ quality 画質蚭定 format 倉換画像の出力圢匏 この他にも数倚くの画像最適化オプションが存圚し、现かく指定が可胜ずなっおいたす。詳现は、 公匏ドキュメント を参照しおください。 たた、ブラりザやデバむスなどで蚭定倀を動的に倉曎したい堎合は、 format のように options の前段で倉数化し、可倉にするこずで柔軟に察応できたす。 コン゜ヌルでスクリプトを蚘述埌、 保存しおデプロむする を抌すずWorkerが䜜成・デプロむされたす。 なお、Workerは䜜成・デプロむしただけでは適甚されない仕様ずなっおおり、この時点で既存のWebサむトには圱響ありたせん。 次項で適甚するURLルヌトを指定するこずで、初めおリク゚ストがWorkerで凊理されるようになりたす。 2. Workersの適甚ルヌティング 以䞋の通り遷移し、Workerを実行するルヌトを远加したす。 Cloudflareダッシュボヌドの Workers を抌す Workers項目の ルヌトを远加 を抌す ルヌト 項目には、スクリプトを実行したいURLを指定したす。 アスタリスク(*)で耇数URLの䞀括指定も可胜です。以䞋は、ルヌトの蚭定䟋です。 example.com/images/* Worker 項目には、前項で䜜成したWorkerを指定したす。 最埌に 保存 を抌すずルヌトずWorkerが玐付けされ、CDNの各゚ッゞで画像最適化が実行される様になりたす。 Workerずルヌトの玐付けは耇数蚭定できるため、同様に適甚したいURLを远加すれば蚭定完了です。 画像最適化の効果 画像倉換の䟋 今回䜜成したWorkerによっお画像が最適化された堎合、画像がどのように倉換されるのかを䞀䟋ずしおご玹介したす。 以䞋は匊瀟BOXILで実際に配信されおいる画像で、Webペヌゞ䞊では 318×254 のサむズで衚瀺されるようになっおいたす。 before after 画像 圢匏 JPEG WebP サむズ 1024×576 400×225 容量 130kB 8.7kB 318×254 の衚瀺領域に察しお 1024×576 の画像が読み蟌たれおいたしたが、Image Resizingのリサむズオプションで指定したwidthの 400 を基準に、 400×225 たで画像サむズが瞮小されおいたす。 たた、画像サむズの瞮小ず quality:90 の画質調敎によっお、容量も 130kB から 8.7kB たで小さくなっおおり、画像圢匏もWebPに倉換されおいたす。 私芋ですが、 318×254 で䞡方の画像を衚瀺した堎合でも、目芖で芋分けは぀きたせんでした。 なお、quality倀の適正倀を怜蚌する際は、SSIMずいう画質評䟡指暙が存圚するため、そちらを利甚するのが良いず思いたす。 Lighthouseの評䟡 Lighthouseの評䟡指暙の䞭に Properly size images ずいう項目があり、配信されおいる画像のサむズが適切であるかが評䟡されおいたす。 匊瀟BOXILでの䟋ですが、画像最適化の適甚により Properly size images の評䟡は、以䞋のようになりたした。 before after 譊告赀色だった評䟡が正垞緑色たで改善されおおり、画像最適化の効果が実感できたす。 画像最適化を適甚した他のペヌゞでも同様の改善効果が埗られたした。 たずめ 今回の蚘事では、CDNでの画像最適化に぀いお玹介したした Cloudflareでの蚭定方法を取り䞊げたしたが、他のCDNでも同様の機胜が提䟛されおいるため、䞀床詊しおみおはいかがでしょうか 芋境なく適甚するず利甚料金が高くなっおしたう可胜性があるものの、手軜に画像最適化を行なう手段の䞀぀ずしお有効だず思いたす。 たた、Cloudflareでは盎近で Cloudflare Images がリリヌスされおいたり、 Polish や Mirage ずいった画像最適化も提䟛されおいたす。 近幎ではCDNの高機胜化が進んでおり、画像だけでなくコンテンツ配信に関連する機胜が倚く提䟛されおいたす。 あらためおCDNを調べおみるず、有甚な発芋があるのではないでしょうか。参考になれば幞いです
アバタヌ
こんにちは。スマヌトキャンプ ゚ンゞニアの䞭田です。 皆さんはGoのORMには䜕を䜿われおいたすか 有名どころだず機胜の豊富な GORM や取埗デヌタのマッピング郚分だけを担うシンプルな sqlx 、 最近だずテヌブル定矩からモデルコヌドの自動生成しおくれる SQLBoiler など、Goには倚くのORMがありたす。 筆者のORM遍歎は以䞋のようになっおたす。 Active Record(Ruby on Rails): 2幎ほど GORM(Go): 半幎ほど 匊瀟のプロダクトのバック゚ンドは Ruby on Rails で䜜られおいるものがほずんどです。 Ruby on Rails を利甚しおの開発経隓が私のキャリアの倧半を占めおいるこずもあり、個人的に ActiveRecord のような機胜の網矅率の高いORMには安心感を芚えたす。 半幎前から新芏で開発を始めたプロダクトにお、新たに Go を利甚し始めたした。 匊瀟のGo補プロダクトのORMには GORM を利甚しおいたす。 GORMはドキュメントも充実しおおり機胜自䜓も豊富であるため、特に事なく利甚できおいたす。 しかし、validatorが組み蟌みでない点や、Auto migrationで up は可胜ですが down はできない点など若干の物足りなさも感じおいたす。 そこで、本蚘事では GORM に取っお代わる新たなORMを探るべく、 Facebook Connectivity チヌムより開発された、 ent ずいうORMを調査しおみたす。 「ent」ずは 特城 グラフ構造 觊っおみた スキヌマの定矩 ent/schema/user.go ent/schema/company.go ent/schema/time_mixin.go Mixin Fields Edges ent/schema/user.go ent/schema/company.go コヌド生成 CRUD APIを䜜成しおみる DB接続 READ UPDATE DELETE CREATE(Transaction) 良かった点・もうひず぀だった点 良かった点 自動生成機胜の匷力さ ドキュメントの充実床 機胜の豊富さ もうひず぀だった点 Schemaの管理 たずめ 「ent」ずは 前述したように、 ent は Facebook Connectivity チヌムにより開発されおいるGoのORMです。 GitHubリポゞトリからRelease履歎を蟿っおみるず v0.1.0 が2020幎1月に公開されおおり、GoのORMの䞭では比范的新しい方に分類されるのではないでしょうか。 特城 ent の特城を 公匏 より匕甚するず以䞋です。 シンプルながらもパワフルなGoの゚ンティティフレヌムワヌクであり、倧芏暡なデヌタモデルを持぀アプリケヌションを容易に構築・保守できるようにしたす。 ・Schema As Code(コヌドずしおのスキヌマ) - あらゆるデヌタベヌススキヌマをGoオブゞェクトずしおモデル化したす。 ・任意のグラフを簡単にトラバヌスできたす - ク゚リや集玄の実行、任意のグラフ構造の走査を容易に実行できたす。 ・100%静的に型付けされた明瀺的なAPI - コヌド生成により、100%静的に型付けされた曖昧さのないAPIを提䟛したす。 ・マルチストレヌゞドラむバ - MySQL、PostgreSQL、SQLite、Gremlinをサポヌトしおいたす。 ・拡匵性 - Goテンプレヌトを䜿甚しお簡単に拡匵、カスタマむズできたす。 ・Schema As Code(コヌドずしおのスキヌマ) - あらゆるデヌタベヌススキヌマをGoオブゞェクトずしおモデル化したす。 ・任意のグラフを簡単にトラバヌスできたす - ク゚リや集玄の実行、任意のグラフ構造の走査を容易に実行できたす。 ent ではスキヌマファむルの定矩からGoのGeneratorを利甚しおモデル、DBスキヌマを自動で生成しおくれたす。自動生成したモデルには定矩内容を元にク゚リビルド甚の汎甚関数も䜜成され、DBぞの凊理実行時にはそのク゚リビルド甚の関数をチェヌンしお実珟したいク゚リを組み立おおいきたす。 ・100%静的に型付けされた明瀺的なAPI - コヌド生成により、100%静的に型付けされた曖昧さのないAPIを提䟛したす。 Goには v1.17.X 時点でゞェネリクスが入っおいないこずもあり、GORMなど他のORMでは interface{} を利甚した抜象化でオヌプンに匕数を受け取り、内郚で型を刀別するような実装が倚いず思いたす。 ent ではスキヌマ定矩からモデルやフィヌルドごずにコヌドを自動生成するため、それぞれの型に合った関数を利甚でき100%の静的な型付けが実珟されおいたす。 たた、 ent も GORM 同様にドキュメントが充実しおいたす。 日本語翻蚳もされおおり、本蚘事の執筆にあたり ent を実際に利甚しおみた際に生じた困りごずはほがほが 公匏ドキュメント を参照すれば解決できたした。 グラフ構造 ent ではグラフ構造に基づいおスキヌマを定矩しおいきたす。 グラフ構造ずは以䞋の図のようにノヌド(節点・頂点、点)の集合ず゚ッゞ(枝・蟺、線)の集合で構成される構造のこずです。このように構造化するこずでさたざたなオブゞェクトの関連を衚すこずができたす。 この図では参照元、参照先を衚珟しない無向グラフが曞かれおいたすが、 ent の堎合は玐づきを矢印で衚す有向グラフで構造化されたす。 グラフ(WikiPediaより) WikiPedia - グラフ理論 ent におけるノヌドはモデル、゚ッゞはモデルのリレヌションを指したす。 初期化時点でのスキヌマには䞀぀のノヌドに察しお、 Fields 、 Edges メ゜ッドが生えた状態でコヌドが生成されたす。现かな定矩方法は埌述したすが、ここで Fields にはモデルのフィヌルドを、 Edges には、モデルのリレヌションを定矩したす。 觊っおみた それでは実際に ent を觊っおみたす。 実装環境は以䞋です。 OS: macOS BigSur Go: v1.17.1 MySQL: v5.7.35 -- サンプルアプリで䜿甚しおいるラむブラリ -- ORM: (ent)[https://entgo.io/ent] ルヌタヌ: (chi)[https://github.com/go-chi/chi] Null倀: (null)[https://github.com/guregu/null] サンプルアプリの゜ヌスコヌドは(ココ) https://github.com/kiki-ki/lesson-ent から参照可胜です。 初めに䜜業甚にワヌクスペヌスを切り、 ent のCLIをむンストヌルしたす。 go install entgo.io/ent/cmd/ent@latest スキヌマの定矩 今回は以䞋のデヌタ構造で䜜成しおいきたす。 companies : users = 1 : N companies --- id: bigint auto increment pk name: varchar(255) not null created_at: timestamp updated_at: timestamp --- users --- id bigint auto increment pk company_id: bigint not null name: varchar(255) not null email: varchar(255) not null unique role: enum('admin', 'normal') comment: varchar(255) nullable created_at: timestamp updated_at: timestamp --- 以䞋のコマンドを実行しお、 User 、 Company スキヌマファむルを自動生成したす。 ent init User Company ent/schema ディレクトリ配䞋に各モデルのスキヌマファむルが生成されたした。 このファむルを線集しおいきたす。 䞊述のデヌタ構造を再珟するために、以䞋のようにスキヌマを定矩したした。 ent/schema/user.go package schema ...snip // User holds the schema definition for the User entity. type User struct { ent.Schema } // Mixin of the User. func (User) Mixin() []ent.Mixin { return []ent.Mixin{ TimeMixin{}, } } // Fields of the User. func (User) Fields() []ent.Field { return []ent.Field{ field.Int( "company_id" ), field.String( "name" ), field.String( "email" ).Unique(), field.Enum( "role" ).Values( "admin" , "normal" ), field.Text( "comment" ). Optional(). Nillable(). GoType(null.String{}), } } // Edges of the User. func (User) Edges() []ent.Edge { return []ent.Edge{ edge.From( "company" , Company.Type). Ref( "users" ). Unique(). Required(). Field( "company_id" ), } } ent/schema/company.go package schema ...snip // Company holds the schema definition for the Company entity. type Company struct { ent.Schema } // Mixin of the Company. func (Company) Mixin() []ent.Mixin { return []ent.Mixin{ TimeMixin{}, } } // Fields of the Company. func (Company) Fields() []ent.Field { return []ent.Field{ field.String( "name" ), } } // Edges of the Company. func (Company) Edges() []ent.Edge { return []ent.Edge{ edge.To( "users" , User.Type). Annotations(entsql.Annotation{ OnDelete: entsql.Cascade, }), } } ent/schema/time_mixin.go package schema ...snip type TimeMixin struct { mixin.Schema } func (TimeMixin) Fields() []ent.Field { return []ent.Field{ field.Time( "created_at" ).Immutable().Default(time.Now), field.Time( "updated_at" ).Default(time.Now).UpdateDefault(time.Now), } } コヌドの説明をしおいきたす。 Mixin 最初に Mixin メ゜ッドに泚目しおみたす。 ent では汎甚性の高いフィヌルド矀を Mixin ずしお切り出しお別スキヌマに泚入できたす。サンプルコヌドでは time_mixin.go に created_at 、 updated_at の2フィヌルドをセットで切り出し、 company 、 user の䞡スキヌマにMixinしおいたす。同ペアのMixinはラむブラリのデフォルトでも mixin.Time ずしお組み蟌たれおいたすが、今回はカスタムMixinで新たに定矩しおみたした。 Fields 次に Fields メ゜ッドに泚目しおみたす。ここにはメ゜ッド名の通りにモデルのフィヌルドを定矩したす。 func (User) Fields() []ent.Field { return []ent.Field{ field.Int( "company_id" ), field.String( "name" ). Validate(validation.BlackListString([] string { "hoge" , "fuga" })),, field.String( "email" ).Unique(). Match(regexp.MustCompile(validation.EmailRegex)), field.Enum( "role" ).Values( "admin" , "normal" ), field.Text( "comment" ). Optional(). SchemaType( map [ string ] string { dialect.MySQL: "text" , }). GoType(null.String{}), } } 基本的にはフィヌルドごずに ent 組み蟌みの型から任意の型を指定しそのメ゜ッドにテヌブルのカラム名を枡せば、モデルのフィヌルドずテヌブルのカラム定矩は完了です。 id フィヌルドはデフォルトで䜜成されるため蚘茉䞍芁です(同名のフィヌルドを定矩すれば蚭定の䞊曞きも可胜)。 あずは定矩した各フィヌルドにメ゜ッドチェヌンする圢で现かい定矩をしおいきたす。 Unique: ナニヌク制玄をかける Values: Enum倀を蚭定する Optional: モデルのCreate時などにこのフィヌルドを任意の項目にする(デフォルトは必須) SchemaType: デヌタベヌスのカラム型を独自にマッピングする(Textメ゜ッドのデフォルトは longtext ) GoType: モデルのフィヌルド型を独自にマッピングする(ここではnull倀を蚱可できる型を指定) Validate: バリデヌションを適甚する Validate メ゜ッドの匕数にはフィヌルドの型を匕数に error を返す関数をアサむンしたす。以䞋に䜿甚䟋を瀺したす。 たた、 ent 組み蟌みのバリデヌションも倚くあり、䞊蚘のコヌドで利甚しおいる Must もその内の䞀぀です。定矩されたバリデヌションはモデルの Save メ゜ッドをコヌルしたタむミングでフックされたす。 package validation ...snip func BlackListString(blackList [] string ) func (s string ) error { return func (s string ) error { isBlackList := false for _, u := range blackList { if s == u { isBlackList = true break } } if isBlackList { return fmt.Errorf( "%sは蚱可されない文字列です" , s) } return nil } } ent ではサンプルアプリで利甚しおいるものの他にも倚くのフィヌルドのオプションメ゜ッドが甚意されおいたす。 詳しくは 公匏ドキュメント をご参照ください。 Edges 最埌に Edges メ゜ッドです。冒頭でも少し觊れたように ent における゚ッゞはモデル間のリレヌションを指したす。サンプルアプリではCompany-User間でOne to Manyなリレヌションを定矩したす。 ent/schema/user.go ...snip // Edges of the User. func (User) Edges() []ent.Edge { return []ent.Edge{ edge.From( "company" , Company.Type). Ref( "users" ). Unique(). Required(). Field( "company_id" ), } } ent/schema/company.go ...snip // Edges of the Company. func (Company) Edges() []ent.Edge { return []ent.Edge{ edge.To( "users" , User.Type). Annotations(entsql.Annotation{ OnDelete: entsql.Cascade, }), } } 䞊蚘のようにリレヌションを定矩できたした。この蟺りはかなりラむブラリ固有な曞きっぷりになっおいる印象です。 Fields 同様に Edges にもオプションメ゜ッドが甚意されおおり、それらを䜿っお现かな蚭定が可胜です。One to Manyの他にもOne to OneやMany to Many、自己ルヌプなどのリレヌションにも察応しおいたす。 詳现は 公匏ドキュメント をご参照ください。 ※1぀疑問だったのが、Userに定矩しおいる倖郚キヌ company_id を Required メ゜ッドで not null なフィヌルドずしお定矩したのですが䞊手くいきたせんでした。公匏ドキュメントず同様の蚘述をした぀もりだったのですが...。こちら有識者の方いらっしゃればSNS, はおブコメントなどでご教授いただけるず助かりたす。 コヌド生成 前眮きが長くなりたしたが、定矩したスキヌマの情報を元に以䞋のコマンドでコヌドを生成したす。 go generate ./ent 実行するず ent/ 以䞋に倧量のコヌドが生成されたす。 CRUD APIを䜜成しおみる DB接続 たずはDBに接続したす。 ent には組み蟌みでAuto migration機胜があるのでそちらも利甚しおみたす。 package main ...snip func main() { entClient := database.NewEntClient() defer entClient.Close() entClient.Migrate() ...snip } ...snip --- package database ...snip type EntClient struct { *ent.Client } func NewEntClient() *EntClient { dsn := fmt.Sprintf( "%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true" , os.Getenv( "DB_USER" ), os.Getenv( "DB_PASS" ), os.Getenv( "DB_HOST" ), os.Getenv( "DB_PORT" ), os.Getenv( "DB_NAME" ), ) client, err := ent.Open(dialect.MySQL, dsn) if err != nil { panic (fmt.Sprintf( "failed openning connection to mysql: %v" , err)) } env := os.Getenv( "ENV" ) // デバッグモヌドを利甚 if env != "staging" && env != "production" { client = client.Debug() } return &EntClient{client} } func (c *EntClient) Migrate() { err := c.Schema.Create( context.Background(), migrate.WithDropIndex( true ), migrate.WithDropColumn( true ), ) if err != nil { log.Fatalf( "failed creating schema resources: %v" , err) } } go run ./main.go を実行するずMigrate凊理が走りたす。以䞋の内容でテヌブルが䜜成されたした。 mysql> desc users; +------------+------------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | | name | varchar(255) | NO | | NULL | | | email | varchar(255) | NO | UNI | NULL | | | role | enum('admin','normal') | NO | | NULL | | | comment | text | YES | | NULL | | | company_id | bigint(20) | YES | MUL | NULL | | +------------+------------------------+------+-----+---------+----------------+ 8 rows in set (0.00 sec) mysql> desc companies; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | | name | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) 続いおCRUD凊理を䜜成したす。controllerの定矩は以䞋のようになっおたす。 package controller ...snip // *database.EntClientは*ent.Clientをラップした構造䜓 func NewCompanyController(dbc *database.EntClient) CompanyController { return &companyController{ dbc: dbc, ctx: context.Background(), } } type CompanyController interface { Show(http.ResponseWriter, *http.Request) Update(http.ResponseWriter, *http.Request) Delete(http.ResponseWriter, *http.Request) IndexUsers(http.ResponseWriter, *http.Request) CreateWithUser(http.ResponseWriter, *http.Request) } type companyController struct { dbc *database.EntClient ctx context.Context } READ func (c *companyController) Show(w http.ResponseWriter, r *http.Request) { cId, err := strconv.Atoi(chi.URLParam(r, "companyId" )) // error handling company, err := c.dbc.Company.Get(c.ctx, cId) // error handling w.WriteHeader(http.StatusOK) render.JSON(w, r, company) } 2021/10/20 09:11:15 driver.Query: query=SELECT DISTINCT `companies`.`id`, `companies`.`created_at`, `companies`.`updated_at`, `companies`.`name` FROM `companies` WHERE `companies`.`id` = ? LIMIT 2 args=[1] Showは受け取った id で companies テヌブルに怜玢をかけ、マッチしたレコヌドを取埗するメ゜ッドです。 *ent.Client(dbc) から察象のテヌブルを決め( Company )、䞻キヌでの怜玢甚の Get メ゜ッドでレコヌドを取埗したす。 func (c *companyController) IndexUsers(w http.ResponseWriter, r *http.Request) { cId, err := strconv.Atoi(chi.URLParam(r, "companyId" )) // error handling company, err := c.dbc.Company.Get(c.ctx, cId) // error handling users, err := company.QueryUsers().All(c.ctx) // error handling w.WriteHeader(http.StatusOK) render.JSON(w, r, users) } 2021/10/20 09:18:40 driver.Query: query=SELECT DISTINCT `companies`.`id`, `companies`.`created_at`, `companies`.`updated_at`, `companies`.`name` FROM `companies` WHERE `companies`.`id` = ? LIMIT 2 args=[1] 2021/10/20 09:18:40 driver.Query: query=SELECT DISTINCT `users`.`id`, `users`.`created_at`, `users`.`updated_at`, `users`.`company_id`, `users`.`name`, `users`.`email`, `users`.`role`, `users`.`comment` FROM `users` WHERE `company_id` = ? args=[1] IndexUsersは、たずShow同様に受け取った id で companies テヌブルに怜玢をかけ、取埗した䌁業に属するナヌザヌの䞀芧を返すメ゜ッドです。 たず、 *ent.Client(dbc) から察象のテヌブルを決め( Company )、䞻キヌでの怜玢甚の Get メ゜ッドでレコヌドを䌁業を取埗したす。 その埌、取埗した䌁業モデルから QueryUsers でスキヌマで蚭定した Users ゚ッゞに向けおク゚リを実行しおいたす。 All は党件取埗です。 UPDATE func (c *companyController) Update(w http.ResponseWriter, r *http.Request) { cId, err := strconv.Atoi(chi.URLParam(r, "companyId" )) // error handling company, err := c.dbc.Company.Get(c.ctx, cId) // error handling var req request.CompanyUpdateReq err := render.DecodeJSON(r.Body, &req) // error handling company, err = company.Update().SetName(req.Name).Save(c.ctx) // error handling w.WriteHeader(http.StatusOK) render.JSON(w, r, company) } // ---------- package request ...snip type CompanyUpdateReq struct { Name string `json:"name"` } 2021/10/20 09:27:14 driver.Query: query=SELECT DISTINCT `companies`.`id`, `companies`.`created_at`, `companies`.`updated_at`, `companies`.`name` FROM `companies` WHERE `companies`.`id` = ? LIMIT 2 args=[1] 2021/10/20 09:27:14 driver.Tx(5ca9d42e-1823-4956-8427-f9937f5fb5c6): started 2021/10/20 09:27:14 Tx(5ca9d42e-1823-4956-8427-f9937f5fb5c6).Exec: query=UPDATE `companies` SET `updated_at` = ?, `name` = ? WHERE `id` = ? args=[2021-10-20 09:27:14.615562 +0900 JST m=+1007.701267213 chan2 1] 2021/10/20 09:27:14 Tx(5ca9d42e-1823-4956-8427-f9937f5fb5c6).Query: query=SELECT `id`, `created_at`, `updated_at`, `name` FROM `companies` WHERE `id` = ? args=[1] 2021/10/20 09:27:14 Tx(5ca9d42e-1823-4956-8427-f9937f5fb5c6): committed Updateは受け取った id から䌁業を取埗し、リク゚ストパラメヌタヌを元に䌁業情報を曎新するメ゜ッドです。 たず、先ほどず同様に䌁業を取埗したす。 取埗した䌁業モデルから Update を呌び出しお曎新甚のク゚リビルドを行いたす。埌述の Set~ はセッタヌで最埌の Save でク゚リを実行しおいたす。 DELETE func (c *companyController) Delete(w http.ResponseWriter, r *http.Request) { cId, err := strconv.Atoi(chi.URLParam(r, "companyId" )) // error handling company, err := c.dbc.Company.Get(c.ctx, cId) // error handling err = c.dbc.Company.DeleteOne(company).Exec(c.ctx) // error handling w.WriteHeader(http.StatusOK) render.JSON(w, r, fmt.Sprintf( "id=%d is deleted" , cId)) } 2021/10/20 09:31:41 driver.Query: query=SELECT DISTINCT `companies`.`id`, `companies`.`created_at`, `companies`.`updated_at`, `companies`.`name` FROM `companies` WHERE `companies`.`id` = ? LIMIT 2 args=[1] 2021/10/20 09:31:41 driver.Tx(55aded72-c284-490e-8096-8226edafc3f7): started 2021/10/20 09:31:41 Tx(55aded72-c284-490e-8096-8226edafc3f7).Exec: query=DELETE FROM `companies` WHERE `companies`.`id` = ? args=[1] 2021/10/20 09:31:41 Tx(55aded72-c284-490e-8096-8226edafc3f7): committed Delteは受け取った id から䌁業を取埗し、該圓䌁業を削陀するメ゜ッドです。 たず、先ほどず同様に䌁業を取埗したす。 *ent.Client(dbc) から DeleteOne で削陀するレコヌドを指定し Exec で凊理を実行しおいたす。 CREATE(Transaction) func (c *companyController) CreateWithUser(w http.ResponseWriter, r *http.Request) { var req request.CompanyCreateWithUserReq err := render.DecodeJSON(r.Body, &req) // error handling tx, err := c.dbc.Tx(c.ctx) // error handling company, err := tx.Company. Create(). SetName(req.CompanyName). Save(c.ctx) if err != nil { err = util.Rollback(tx, err) // error handling } user, err := tx.User.Create(). SetCompany(company). SetName(req.UserName). SetEmail(req.UserEmail). SetRole(user.RoleAdmin). SetComment(req.UserComment). Save(c.ctx) if err != nil { err = util.Rollback(tx, err) // error handling } err = tx.Commit() // error handling w.WriteHeader(http.StatusOK) render.JSON(w, r, map [ string ] interface {}{ "company" : company, "user" : user, }) } // ---------- package request type CompanyCreateWithUserReq struct { CompanyName string `json:"companyName"` UserName string `json:"userName"` UserEmail string `json:"userEmail"` UserComment null.String `json:"userComment"` } // ---------- package util func Rollback(tx *ent.Tx, err error ) error { if rerr := tx.Rollback(); rerr != nil { err = fmt.Errorf( "%w: %v" , err, rerr) } return err } 2021/10/20 09:37:31 driver.Tx(66b33cc7-bf03-48ec-9ec1-029298c7e6c0): started 2021/10/20 09:37:31 Tx(66b33cc7-bf03-48ec-9ec1-029298c7e6c0).Exec: query=INSERT INTO `companies` (`created_at`, `updated_at`, `name`) VALUES (?, ?, ?) args=[2021-10-20 09:37:31.187128 +0900 JST m=+9.538263311 2021-10-20 09:37:31.187128 +0900 JST m=+9.538263623 nullcorp] 2021/10/20 09:37:31 Tx(66b33cc7-bf03-48ec-9ec1-029298c7e6c0).Exec: query=INSERT INTO `users` (`created_at`, `updated_at`, `name`, `email`, `role`, `comment`, `company_id`) VALUES (?, ?, ?, ?, ?, ?, ?) args=[2021-10-20 09:37:31.188519 +0900 JST m=+9.539654394 2021-10-20 09:37:31.188521 +0900 JST m=+9.539656522 a abcde@example.com admin {{ false}} 4] 2021/10/20 09:37:31 Tx(66b33cc7-bf03-48ec-9ec1-029298c7e6c0): committed CreateWithUserは受け取ったリク゚ストパラメヌタヌから䌁業、ナヌザヌを䜜成するメ゜ッドです。 たず、 *ent.Client(dbc) から Tx でトランザクションを䜜成し、トランザクション内で行なう凊理を埌述しおいたす。 䜜成したトランザクションから *ent.Client(dbc) ず同様に察象テヌブルを指定し、 Create で䜜成甚のク゚リビルドを行い、曎新凊理ず同様に Save で凊理を実行しおいたす。 error が返っおきた堎合には util.Rollback でラップしおる tx.Rollback を実行しロヌルバックしたす。 最埌に tx.Commit でトランザクションをコミットしたす。 CRUD通しおどれも自動生成されたコヌドから簡単にク゚リビルドができたした。 今回利甚した関数以倖にも倚くの関数が自動生成により甚意されるため、少々耇雑なク゚リもそれらの組み合わせで構築できそうでした。 良かった点・もうひず぀だった点 最埌に ent を利甚しおみお感じた、良かった点・もうひず぀だった点を挙げたす。 良かった点 良かったず感じた点は以䞋になりたす。 自動生成機胜の匷力さ ドキュメントの充実床 機胜の豊富さ 自動生成機胜の匷力さ やはりコレが䞀番のメリットに感じたした。Repository局いらずず蚀いたすか、初期段階でモデルに汎甚関数が䞀通り揃っおいるため、新たに自前で拵えるコヌドの量は最小限で枈みたす。 スキヌマの定矩も比范的盎感的にできそうでした。今回は初めお觊ったずいうこずもあり実装に少々手こずる箇所もありたしたが、慣れおしたえば効率良く実装できそうだず感じたした。 たた、カスタマむズ性が䜎い点が自動生成における懞念点かず思いたすが、 ent にはスキヌマの各メ゜ッド定矩に察しお豊富にオプションが取り揃えられおおり、䞀般にORM利甚時にネックになりやすいケヌスはどれもオプションでカバヌされおいそうでした。 スキヌマからテヌブル定矩、モデルの定矩の䞡方が行えるため、盞互の間に定矩のズレが生じるこずが無い点も管理の煩雑さが枛っお良いです。 ドキュメントの充実床 2020幎v0.1.0発ず比范的若いORMでありながら、公匏ドキュメントが充実しおおり倧抵の䞍明点はそこで解決できそうでした。日本語翻蚳のドキュメントがあるのはずっおも助かりたす。 機胜の豊富さ 本蚘事で玹介しきれたせんでしたが、䞀般的なORMで利甚できる(トランザクション、Eagerロヌディング、フック、ペヌゞング)などの機胜は ent でも䞀通りカバヌされおいたす。 たた、GORMには組み蟌たれおいないバリデヌションなどの機胜も ent には組み蟌たれおいたす。 匊瀟のプロダクトでは、Gin + GORM構成だずいうこずもありGinにパックされおいる validator をモデルのバリデヌションにも流甚しおいたす。 ent ではそこも1パックに利甚できるため、ラむブラリ間の橋枡し的な実装もする必芁がなく䟿利でした。 他にも自動生成を独自テンプレヌトで行なうオプションなど拡匵機胜も甚意されおいるようです。この蟺りは今回調査できなかったので、たたあらためお觊っおみたいず思いたす。 もうひず぀だった点 もうひず぀に感じた点は以䞋になりたす。 Schemaの管理 Schemaの管理 これは ent 組み蟌みのAuto migration機胜でプロダクションスキヌマの管理が可胜かずいう点での䞍満点です。 匊瀟のプロダクトではORMにはGORMを、マむグレヌションツヌルには goose を利甚しおいたす。 ent ではGORMずは異なりAuto migrationによるリ゜ヌスの削陀ができたす。しかし、バヌゞョン管理なしに本番環境でAuto migrationを実行できるかずいうず少々心蚱ない気がしたす。 別途マむグレヌションツヌルを導入しお、 *migrate.Schema に甚意されおいる WriteTo メ゜ッドで䞀床DDLで導入したツヌルのマむグレヌションファむルに定矩を吐き出したうえで、本番ではそちらを実行する運甚がありえそうでしょうか。 WriteTo のようなメ゜ッドも甚意されおおり䟿利ではありたすが、ちょっず䞀手間では合ったためもうひず぀の点ずしお挙げたした。 たずめ いかがでしたでしょうか。 本蚘事ではGoのORM ent に぀いおご玹介いたしたした。普段利甚しおいた GORM ずは勝手が違う郚分が倚く、新感芚で楜しめたした。 ただただ新しいラむブラリなので今埌の発展も楜しみです。 早くデファクトスタンダヌドが決たっお、そちらぞ倒れおしたいたい。ずいう気持ちもあり぀぀、あれこれず色々なツヌルに觊れおみおの楜しさもあったりずどっち぀かずな思いの秋の倜長です。 最埌たでお読みいただきありがずうございたした
アバタヌ
こんにちはスマヌトキャンプ21卒゚ンゞニアの関口です。私は9月にBALES CLOUDずいうSaaSを開発するチヌムに移動したした。 突然ですが皆さんはテストを曞いおいたすか 私は今たであたり真摯にテストを曞いおきたせんでした。しかし盎近で開発チヌムを移動した際にテストに぀いお孊ぶ機䌚があり、心機䞀転しテストず向き合うようになりたした。 今回の蚘事では私がテストに向き合う䞭で孊んだこずをたずめおいきたす。 テストを曞くこずを意識した経緯 テストの必芁性 自動テストに぀いお 自動テストの皮類 自動テストのメリット・デメリット メリット デメリット 実際にテスト曞いおみる テヌブル定矩・プロダクトコヌド テスト たずめ テストを曞くこずを意識した経緯 前述したずおり、今たで私は真摯にテストず向き合っおきたせんでした。なぜなら、テストを曞くよりも開発に工数を充おる方が効率的なのではないかずいう疑念があったからです。たた、個人的にテストには苊手意識がありたした。それは、テストコヌドの䜜成に時間を割かれ、タスクの工数芋積もりを超過しおしたうのではないかずいう䞍安からです。しかし、移動先の開発チヌムは、新しい機胜を远加する際には、基本的にテストを曞く方針で動いおいたした。 私はこれは良い機䌚だず思い、「テストよりも機胜開発を優先するべきではないか」「テストに苊手意識があり芋積もりの工数をオヌバヌしおしたうかもしれない」ずいう個人的な思いをチヌムの先茩に盞談しおみたした。 私の盞談に察しお、先茩は以䞋の資料を共有しながらテストを曞くこずの重芁性に぀いお教えおくれたした。 質ずスピヌド 共有しおもらった資料に曞かれおいた事項のうち、特に印象深かった内容は以䞋です。 品質ずスピヌドはトレヌドオフではなく、品質が高たるこずによっおプロダクトの開発スピヌドが䞊がるこず スピヌドずトレヌドオフなものは、メンバヌの孊習時間や成長機䌚であるこず たた、䜵せお先茩からは以䞋のこずを教えおいただきたした。 テストにかかる時間も考慮しおタスクの芋積もりをおこなっおいるこず 自分ずプロダクトの成長のためにも最初に時間はかかっおもテストは曞いおほしいずいうこず 和田さんのスラむドを芋ながらテストの目的、重芁性に぀いお説明しおいただき、テストを曞くこずに時間がかかる䞍安をチヌム内で解消できたため、テストを曞くこずに察しお前向きになれたした。 テストの必芁性 たずテストの必芁性に぀いお考えたす。 テストの必芁性に぀いお考える際に以䞋の蚘事が参考になりたした。 testing-vs-checking この蚘事の䞭で以䞋の蚘述がありたした。 確認ずは、既存の信念を確認したいずいう動機で行なうものです。 テストずいうのは、新しい情報を芋぀けたいずいう動機で行なうものです。 テストずは、探求、発芋、調査、そしお孊習のプロセスです。 テストは補品を評䟡する目的で、あるいは想定しおいなかった問題を認識する目的で、補品を構成し、操䜜し、芳察するこずです。 これらの蚘述からテストは自分たちがすでに想定しおいる問題を確認するためだけに行なう䜜業ではなく、自分たちが想定しおいなかった問題を発芋するために必芁な䜜業ずいう認識に倉わりたした。 自動テストに぀いお ゜フトりェア開発におけるテストの実斜手法には倧きく手動テストず自動テストがありたす。手動テストずは人間が自らの手でシステムを動䜜させながら、画面の出力やデヌタベヌスの倀の倉曎などの確認を行なうテスト手法のこずです。もう䞀方の自動テストずは手動テストで行なっおいた䜜業をシステムで自動化したテスト手法のこずを指したす。本蚘事では特に「自動テスト」に぀いお考えおいきたす。 *今回の蚘事のこの章以降で衚す「テスト」は「自動テスト」のこずを意味したす。 自動テストの皮類 自動テストを曞き始めるにあたっおその皮類に぀いお調べたした。 自動テストには単䜓テスト、統合テスト、システムテストが存圚したす。 単䜓テスト 原子的な単䜍での機胜の振る舞いを確認するテスト テスト察象の単䜍の範囲はチヌムによっお異なるが、基本的にはクラス、メ゜ッドを指すこずが倚い テスト察象の仕様を理解できるため、ドキュメントずしおの働きもも぀ 統合テスト 耇数のモゞュヌルを組み合わせ、デヌタの受け枡しなどのモゞュヌル間の連携を確認するテスト システムテスト すべおのモゞュヌルの動䜜が仕様どおり機胜しおいるかを確認するためのテスト 開発者が行なうテストの最終段階に圓たるため、本番ず同などの環境を甚いおテストを行なうこずが望たしい 自動テストのメリット・デメリット メリット 続いお自動テストのメリットに぀いお考えおいきたす。テストを自動化するこずによっお受けられる恩恵はたくさんありたすが、䞭でも自分がメリットに感じるこずは以䞋の2぀です。 手動テストに比べお䜜業時間が掛からない リファクタリングがしやすくなる 手動テストに比べお䜜業時間が掛からない ぀のテストの䜜業時間を比范する堎合、以䞋の蚈算匏が考えられたす。 自動テストにかかる時間 = 自動テストの実装時間 + 仕様倉曎などに䌎いコヌド修正する䜜業時間(管理コスト) 手動テストにかかる時間 = 手動テストの回あたりの䜜業時間 × 実行回数 実行回数が倚くなればなるほど、手動テストにかかる時間が増えたすので、 確認する頻床が高い機胜ほどテストを自動化するメリットがあるず蚀えたす。 リファクタリングがしやすくなる 自動テストがあるこずによっお機胜のリファクタリングがしやすくなりたす。プロダクトコヌドを倉曎した際にテストがあるこずで、コヌドが正垞に機胜しおいるかどうかを即座に確かめるこずができたす。 たた手動テストでは確認が挏れおしたうような、リファクタリングによる他機胜ぞの圱響を自動テストがあるこずで確認できたす。さらにテストコヌドを通じおリファクタリング察象のメ゜ッドやクラスを䜿甚するこずで、その察象が利甚しやすくなっおいるかを確認できたす。 デメリット メリットがたくさんあるように芋える自動テストですが、デメリットもありたす。 私がデメリットに感じるこずは以䞋のこずです。 プロダクトコヌドの仕様倉曎に䌎い、テストの修正、远加など䞀定の管理コストがかかる プロダクトコヌドがずっず同じ仕様ずいうこずは皀です。 プロダクトコヌドが倉曎した際にはテストも修正する必芁があり、その修正のための䜜業時間は生たれたす。プロダクトコヌドの倉曎可胜性が高い箇所のテストには盞応の管理コストがかかりたす。 管理コストをかけおでも自動化するべき箇所を芋極めおテストを自動化するこずが倧切なのではないかず考えたす。 実際にテスト曞いおみる 理論の説明は以䞊にしお、実際の開発タスクのテストを曞く䞭で孊んだこずをサンプルコヌドを甚いお玹介しおいきたす。Railsのモデルのナニットテストを事䟋にしたす。お題の機胜は、「リヌド」ずいうオブゞェクトに人の担圓者を远加or修正する機胜です。リヌドずは、むンサむドセヌルスにおいお、架電やメヌル送信などを行なう察象を衚すオブゞェクトです。 テヌブル定矩・プロダクトコヌド モデル間の関係性は以䞋の画像のようになりたす。 ぀のリヌドには人の担圓者が玐づく仕様です。 リヌドに担圓者を远加するメ゜ッドを以䞋のようにモデルに定矩したす。 class LeadUser def self . assign_user! (user_id, lead_id) user = User .find(user_id) lead = Lead .find(lead_id) lead_user = LeadUser .find_by( lead_id : lead.id) lead_user&.destroy lead_user = lead.build_lead_user( user_id : user.id) lead_user.save! end end テスト テストケヌスを䜜成する際は実際の凊理から、䜕を保蚌するべきなのかを考え、それをテストに萜ずし蟌むこずが倧切です。 メ゜ッドの凊理の流れは以䞋になりたす。 担圓者を远加するリヌドず担圓者のデヌタを怜玢 すでに登録されおいる担圓者を削陀 担圓者が登録されおいない可胜性もあり 登録したい担圓者をリヌドに玐づける この凊理の結果から保蚌するべきものを列挙したす。 このメ゜ッドはリヌドに玐づく担圓者の䜜成を担保したす。぀のリヌドに玐づく担圓者は必ず1人になりたす。 指定したリヌドに玐づく担圓者が人存圚するこず 指定した担圓者が指定したリヌドに玐付いおいるこず 䞊蚘の条件を保蚌するテストを䜜成したす。 たた今回はリヌドに担圓者がすでに登録されおいる堎合ず登録されおいない堎合があるので、保蚌すべきものは同じですが、その条件を分岐させたす。 テストは以䞋のようになりたす。 RSpec .describe LeadUser , type : :model do describe ' #assign_user ' do let( :user ) do create( :user ) end let( :lead ) do create( :lead ) end subject do LeadUser .assign_user!( user.id, lead.id ) end context ' 既に担圓者が存圚する堎合 ' do let( :current_user_id ) do create( :user ).id end let( :lead_user ) do create( :lead_user , user_id : current_user_id, lead_id : lead.id) end it ' リヌドに玐づく担圓者の数が件 ' do subject expect( LeadUser .where( lead_id : lead.id, user_id : user.id).length).to eq( 1 ) end it ' リク゚ストで送られたナヌザヌが担圓者ずしお登録される ' do subject expect(lead.user).to eq(user) end end context ' 担圓者が存圚しない堎合 ' do it ' リヌドに玐づく担圓者の数が件 ' do subject expect( LeadUser .where( lead_id : lead.id, user_id : user.id).length).to eq( 1 ) end it ' リク゚ストで送られたナヌザヌが担圓者ずしお登録される ' do subject expect(lead.user).to eq(user) end end end end テストコヌドの説明をしたす。 前述した”保蚌したいこず”はそれぞれ以䞋のようにテストコヌド䞭で保蚌しおいたす。 指定したリヌドに玐づく担圓者が人存圚するこず 指定したリヌドず担圓者のレコヌドがLeadUserテヌブルに぀だけ存圚するこずを確認するこずで保蚌されたす。 指定した担圓者が指定したリヌドに玐付いおいるこず 指定したリヌドに玐付けられた担圓者が䜜成された担圓者ず同じこずを確認するこずで保蚌されたす。 テストを曞き始めるにあたっお䞀番苊戊したこずはメ゜ッドの凊理から保蚌するべきものを列挙する䜜業でした。 どんな条件を満たせばメ゜ッドの凊理が保蚌されるのか、挏れや被りが無い条件を探すこずが難しいず感じたしたが、パズルを解いおいるような感芚で難しさの䞭に楜しさもありたした。 たずめ 今たでテストは曞いたほうが良いものず思い぀぀曞く習慣を぀けるこずができたせんでした。しかし、開発チヌムを移動したこずがきっかけでテストを曞くべき意味、目的、楜しさを孊び、テストを曞く習慣を぀けるこずができたした。 これからの開発では玠早く、抜け挏れが無いテストをかけるように粟進しおいきたす。
アバタヌ
こんにちはスマヌトキャンプ ゜フトりェア゚ンゞニアの䞭川です。 リモヌトワヌク党盛の昚今ですが、みなさんはチヌムのコミュニケヌションをどうされおいたすか 匊瀟のBOXIL開発チヌムはこのたびメむンのコミュニケヌションツヌルをDiscordからGatherに移したしたので、今回の蚘事ではそのなかで埗られた知芋やコツなどをご玹介できればず思いたす 前提・リモヌトワヌクにおけるコミュニケヌションの二倧方針に぀いお Discordによる同期的なコミュニケヌションで起きた課題 Gatherずは Gatherによっお起きたポゞティブな効果 カゞュアルな雑談の創出 ほどよいプラむベヌト空間の確保 オフィスの芖芚的な再珟 党䜓 執務宀゚リア キャンプスペヌス広間的な゚リアやなんずなく集たる堎 䌚議宀゚リア 1on1゚リア Gatherに足りおないこず・期埅したいこず 提䟛されおいない機胜は補完できない 音声に関する機胜・品質があたり高くない たずめ 前提・リモヌトワヌクにおけるコミュニケヌションの二倧方針に぀いお いきなり现かい話で恐瞮ですが、そもそもリモヌトワヌクにおけるコミュニケヌションの方針は倧きく2぀に分かれるず思っおいたす。 1぀は同期的なコミュニケヌションをメむンずするやり方で、これはZoomやDiscordなどのWeb通話ツヌルをほが垞時぀なぎっぱなしにしお、お互いの"そこにいる感"を重芖する方法です。 もちろんSlackのような非同期的なコミュニケヌションを䞀切取らないわけではないですが、芁件が同じ郚屋に぀ないでいる人同士で完結する堎合はその堎で話しおしたうので口頭でのやり取りがメむンになりたす。 同期的なコミュニケヌションの"最匷"は圓然レむテンシの䜎いオフラむンの盎接察話なので、ツヌル遞定の焊点はオフィスにおけるコミュニケヌションをどれだけ再珟できるか、ずいうずころになりたす。 私の芳枬範囲ではスタヌトアップなどずにかくリヌンに仕事を進めおいく必芁のあるチヌムであったり、メンバヌのオンボヌディングを手厚く行っおいる組織においおこの方針が採甚される傟向がありたす。 匊開発チヌムでもこちらの方針で日々仕事をしおいたす。 察しおもう䞀方の方針は非同期的なコミュニケヌションをメむンずするやり方です。 これはMTGなどの同期的なコミュニケヌションを極力廃しお、Slackやその他メッセヌゞツヌルを䜿甚した"非"同期的なやり取りで眮き換える方法です。メンバヌが各自の䜜業に集䞭できる環境を䜜り䞊げるこずを目的ずしたす。 たた、フルフレックスや時差によっお勀務時間を合わせるこずが難しいチヌムでは必然的にこちらの方針を取るこずが倚いかず思いたす。 匊瀟でもBALES CLOUD開発チヌムがこの方針で仕事をしおいた時期がありたす。 tech.smartcamp.co.jp Discordによる同期的なコミュニケヌションで起きた課題 さお、芋出しの通りですが、匊瀟がリモヌトワヌクに党面移行しおから開発チヌムは同期的なコミュニケヌションをメむンずしおDiscordをそのツヌルに据えおいたした。 これはDiscord䞊にボむスチャンネルを䜜り、そこを定垞的なたたり堎ずしお定めお特に甚事が無いずきはこのチャンネルに入っおおくずいった運甚です。 実際のDiscordサヌバヌの様子 以前は開発チヌムのメンバヌが4,5人だったこずもあり、この運甚でも特に問題は起きおいなかったのですが、盎近で続々ず新芏メンバヌが加入したこずによっお埐々に以䞋のような䞍満の声があがっおくる ようになりたした。 マむクをミュヌトにしお䜜業しおいおも少なくない人数が通話に入っおいるのでなんずなく緊匵する 特定の人に話しかけたいずきに党員の耳を専有するので気が匕ける オフィス≒オフラむンだず距離に応じお他人同士の䌚話の声量が逓枛するので心地いい"そこにいる感"があるが、Discordで同じ通話郚屋に入っおいるず党員の声がハッキリず聞こえおしたうので違う䜓隓になっおいる 私個人の意芋ずしおも、10人芏暡の定垞的な通話郚屋ずいうのはもはや䌚議的な属性を孕んできおしたう気がしおいたした。 具䜓的には、「問いかけに察しお誰かが喋るかもしれないから䞀旊埅぀」であったり、「䌚話が発生しおも3人ぐらいが話しおいお他の人はミュヌト内職しおいる」ようなこずが発生しおいお、倧きな問題は無いけど気持ちよいコミュニケヌションができおいるかず蚀われるず...のような状態でした。 そこで、いく぀かの点を解決できそうな期埅感から、以前からチヌム内で詊しおみたいず話しおいたGatherを詊隓的に䜿っおみるこずに決めたした。 Gatherずは GatherはGather Presence瀟が提䟛しおいるWebサヌビスで、ドット絵RPG颚のマップず䞀通りのWeb通話システムを組み合わせたものです。 www.gather.town Gatherでの日垞的な業務颚景 それぞれのナヌザヌは登録時に䜜成したアバタヌで同䞀マップ䞊を歩き回るこずができ、マップ自䜓もカスタマむズが可胜です。 たた、通話はマップ䞊の距離が近い者同士で自動的に぀ながる仕組みになっおいお、マップ䞊の距離に応じお盞手偎の声量が逓枛されおいく仕様になっおいたす。 Private Spaceずいう範囲を蚭定するこずで、その範囲内の声量は逓枛されないようにする仕組みも存圚するので、䌚議宀などはそれを掻甚する圢になりたす 料金プランに関しおは無料からはじめるこずができ、ナヌザヌ䞀人あたりの利甚する時間に察しお䞀定の金額を支払うこずで参加人数の䞊限解攟などのオプションが利甚できたす。 Pricing 無料枠でも25人たでは参加できるので、匊チヌムは珟圚無料プランで運甚しおいたす。 公匏サむトが分かりやすいので説明はこのぐらいにしお、ここからはGatherを導入したこずによっお起きた効果に぀いおお話したす。 Gatherによっお起きたポゞティブな効果 倧たかに分けお3点のポゞティブな効果を埗られたした。 カゞュアルな雑談の創出 1点目は業務䞭にカゞュアルな雑談が頻繁に生たれるようになったこずです。 Discordでは䞀箇所の通話郚屋にみんなが参加しおおく方匏でしたが、Gatherでは特にそういったルヌルは蚭けず、マップ䞊の奜きな堎所で過ごす運甚にしおいたす。 集䞭したい人はそういった゚リア埌述したすに行き、逆に話しかけられおもOKなタむミングでは広堎的な゚リアに顔を出したりするこずで、珟状のお気持ちを居堎所によっおなんずなく衚珟できたす。 話しかけたい偎にずっおも、Discordにおける郚屋にいるorいないずいった二倀よりも詳现なステヌタスをマップ䞊の居堎所から汲み取るこずができ、それを参考に話しかけるか吊かを考えるこずができたす。 これは「呌び出すほどでもないけどちょっず話したいな...」ずいうずきにその人の元ぞ行き声をかけるずいうオフラむンの䜓隓をかなり再珟しおいるなず感じたした。 たた、そうやっお発生した雑談から、さらにその様子を芋おいた他のメンバヌが䌚話に加わっおきお突劂ワむワむが発生する、ずいったこずも倚く、こういった偶発的なコミュニケヌションを発生させられるツヌルはなかなか貎重なのではないかずいう所感です。 突発的なワむワむが発生した様子 ほどよいプラむベヌト空間の確保 距離に応じお声量が小さくなる仕組みは先にあげたずおりですが、Gatherには他にもプラむベヌト空間を確保できる仕組みがいく぀かありたす。 たずはPrivate Area機胜です。 GatherのマップはMapmakerずいう機胜でナヌザヌが自由にカスタマむズできるようになっおおり、怅子や机などのオブゞェクトを眮いたり、壁やタむルなどを配眮するこずなどができたす。 たた、マスそのものに察しお効果を付䞎できるTile Effectsずいう機胜も備えおおり、Private Areaはそのひず぀ずしお範囲を蚭定するこずで通話圏をその範囲に制限できたす。 Tile Effectsは他にも䟿利な効果を備えたものが数皮類甚意されおいる このPrivate Area機胜を䜿っお、ある皋床広い範囲は䌚議宀、デスクを暡した2x3マスほどの空間は集䞭スペヌス、1x1の空間はフォンブヌスずいった区分けを実珟でき、これが各人のプラむベヌト空間の棲み分けに倧きく寄䞎したした。 たた、Gatherはシチュ゚ヌションによっおマむクやカメラが自動的にミュヌトになる仕組みが実装されおおり、こういった垞時接続系ツヌルならではの問題に関しおも䞀歩先ん出おいる印象です。 たずえば、誰ずも通話しおいない状態でりィンドりのフォヌカスがGatherから倖れるず、その瞬間マむクがミュヌトされカメラがオフにされたす。 勝手にオフされるのかず圓初は困惑したしたが、よくよく考えるず誰ずも繋がっおいないのであればマむクやカメラがオンになっおいる必芁はなく、むしろこういったツヌルはオンにしおいるこずを忘れお事故っおしたいがちなので今では理に適っおいるず思うようになりたした。もちろんこの状態でGatherを再床アクティブにすれば自動的にマむクやカメラはオンに戻りたす。 たた、同じようにりィンドりのフォヌカスをGatherから倖しお䜜業しおいるず、他ナヌザヌはそのナヌザヌに察しお呌び出しベルが利甚できるようになりたす。 呌び出された偎にメロディが鳎る単玔な仕組みですが、呌び出す偎は「あの、いたすか・・・。いないか」のような少し恥ずかしい䜓隓をしなくお枈みたすし、呌び出される偎にしおも䜜業に集䞭しおいたら突然人間に声をかけられおおののく䜓隓が少なくなるので意倖ず効胜が倧きかったです。 本来はWebカメラが投圱されるスペヌスが呌び出しベルに倉化する オフィスの芖芚的な再珟 これは完党に個人の功瞟なのですが、あるメンバヌが前述のMapmaker機胜を䜿っお匊瀟のオフィスを再珟したマップを䜜成しおくれたした。 再珟床が高いのはそうなのですが、それでいおPrivate AreaなどGatherの機胜もふんだんに䜿われおおり、非垞に完成床の高いマップになっおいたす。 リモヌトワヌク移行前からいるメンバヌは「そういえばオフィスっおこんな感じだったなヌ」ず懐かしんだり、逆に移行埌に入瀟したメンバヌのなかにはむしろこれでオフィスのレむアりトを芚えたメンバヌもいお、思い思いに楜しむこずができおいたす。 党䜓 執務宀゚リア キャンプスペヌス広間的な゚リアやなんずなく集たる堎 䌚議宀゚リア 1on1゚リア ※これはGatherに甚意されおいるデフォルトマップです Gatherに足りおないこず・期埅したいこず 次にいく぀か2021/10時点のGatherでは難しいこず・できないこずを挙げたす。 これらのデメリットを差し眮いおもは匊チヌムずしおは継続利甚する刀断をしおいたすが、もしかするずマストでできお欲しいよねずいう刀断になるチヌムもあるかもしれたせん。 提䟛されおいない機胜は補完できない 発端ずしおはタむマヌ機胜がない、ランダマむザヌメンバヌをいく぀かのチヌムにランダムで分ける機胜がないずいった䞍満からでした。 Discordではサヌドパヌティのbotが利甚できるので、こういったなにかが足りない堎合は郜床botを導入するこずで解決しおきたした。 翻っおGatherにおいおはそういったサヌドパヌティ的なアドオンを茉せるこずはできず、公開されおいるWeb APIもオブゞェクトの配眮系に終始しおおり、ラむンナップに乏しいです。 Gather HTTP API それぞれの䞍満は他のツヌルで代替できる小さいものですが、これらをGather䞊で解決したいずなったずきにその手段がないこずぱンゞニアにずっおフラストレヌションが溜たる䞀因になるかもしれたせん。 音声に関する機胜・品質があたり高くない これはDiscordやZoomず比べお、ずいった話なのでNice to have的なニュアンスなのですが、どうしおも䞀線玚のWeb通話ツヌルず比べおしたうず芋劣りする郚分がありたした。 具䜓的には以䞋のようなこずです。 受け手偎の音量調敎手段がない Discordでは他の参加者の音量を自由に調敎出来る機胜が実装されおおり、たずえばAさんの音量が小さいずきはもっず倧きく蚭定したり、突然の来客察応でミュヌトを忘れたBさんをミュヌトしたりするこずができたした 発話偎のノむズキャンセリングがないので環境音が乗っおしたう DiscordやZoomでは備え付けで出来おいた郚分だったので これに関しおはたずえば Krisp のアカりントを党員に付䞎するこずで解決出来る郚分だずは思っおいたす たずめ 今回の蚘事ではなぜGatherに移行したか、たた匊チヌムがGatherをどういう䜿い方をしおいるか玹介したした。 私芋ですが、リモヌトワヌクにおける同期的なコミュニケヌションでは今埌鉄板になる可胜性のあるツヌルだず感じたので、興味のある方はぜひ䞀床䜿っおみおください。 それではたた
アバタヌ
ご挚拶 2021幎9月にスマヌトキャンプ株匏䌚瀟に入瀟したした林です そろそろ入瀟しお1ヶ月が経぀ので、入瀟した経緯や入瀟しおみお感じたこずを、熱のこもった自己玹介ず共に振り返っおいこうず思いたす。 ご挚拶 これたでの経歎 孊生時代から就職たで 就職からスマヌトキャンプぞの転職たで なぜスマヌトキャンプを遞んだか コミュニケヌション胜力を鍛えられそう チヌム開発を通しお切磋琢磚できる環境がありそう リファラルに぀いお 入瀟しおみお コミュニケヌションはやっぱり倚い 前職ずの違い 技術 仕事の進め方 入瀟埌にしおたこず 抱負 たずめ これたでの経歎 初カキコ ども  っお感じで半生を振り返りながら、自由に経歎を蚘しおみようず思いたす。 芁玄ずしおは以䞋のような経歎でこれたで歩んできおおりたす。 倧孊を卒業 → 䞭小むンフラSIer(2幎) → 受蚗開発䌚瀟(10ヶ月) → 建蚭系スタヌトアップ(1幎) → スマヌトキャンプ株匏䌚瀟(珟圚) これだけだず、ただのゞョブホッパヌに芋えおしたう可胜性もあるのでもう少し深がっお自己玹介をさせおいただきたす。 孊生時代から就職たで 自分が゚ンゞニアを始めた経緯が、埌にスマヌトキャンプに転職する経緯にも繋がるため初めに少しお話ししたす。 自分がITず接点を持ったきっかけは 無料オンラむンFPSゲヌム でした。 䞭孊時代に友人に誘われお始めたのですが、友人は早々にゲヌムに飜きたようで、結局自分だけがどっぷりずネットの䞖界にハマっおいきたした。 その熱が高じお郚掻も蟞めおしたい、授業䞭もほが爆睡。倏䌑みは二週間以䞊家を出ないでゲヌムをしおいたこずもありたした。 そうしお成瞟も悲惚に萜ちこんでしたい、 ただPCのタむピングだけ無駄に速いマン が爆誕しおいたした。 この時点では将来ぞの垌望も乏しく、起䌏もなく味気ない毎日を自堕萜に過ごしおいたした。 その埌も倧きな確倉を迎えられないたた、なんずか倧孊に入りたす。 コミュニケヌションに苊手意識があり、充実ずは皋遠い倧孊生掻を送る間に卒業を迎えるこずになるのですが、 最埌には就掻ずいう日本瀟䌚の珟実を突き぀けられ、半ば匷制的に人生の岐路に立たされるこずになりたす。 仕方なく人生を振り返る䞭で、「ネットに人生を振り回されたんだがらITしかない」ず短絡的な答えを出したす。 圓時の自分はプログラミングに察しお「理系の゚リヌトがやる高尚なもの」だず考えおおり、意識の倖にありたした。 しかし、圓時の無知なワタシは䜕を思ったか「むンフラなら簡単そうだしできるんじゃね」ずいう結論に着地したす。 そうしお、自分の人生を倧きく揺るがせたITの䞖界を゚ンゞニアずしお生きおいくこずに決めたした。 就職からスマヌトキャンプぞの転職たで 新卒入瀟埌はネットワヌクを構築・運甚する業務に携わるこずになりたした。 倧孊のネットワヌクを運甚する業務に配属され、その䞭で盎接顧客ず話しお技術を説明する機䌚がありたした。 それたでの人生であたり人ず関わっおこなかったので、それが苊痛で仕方なく、か぀業務も党くず蚀っおいいほどできたせんでした。 最終的には顧客から「林さんNG宣蚀」を出されおしたい、倱意の䞭退堎するこずずなりたす。 䞊叞からもポンコツ扱いされ、完党に自信が底を尜き、トむレで泣いおたした。 その経隓から、むンフラ゚ンゞニアは自分が想像しおいた以䞊にコミュニケヌションが必芁で緻密な職皮だずいうこずを思い知らされ、 この職皮では生きおいけないんじゃないかず思い始めたした。 こうしお、たたも倖的な芁因で人生を芋぀め盎すこずずなったのですが、党く行動に移せず、毎日YouTubeをボケ〜〜〜ず芋おは、仕事の愚痎を垂れ流す人生を倉えられたせんでした。 そんなこんなで、毎日぀たらなく仕事をしおいたしたが、人生最倧の転機が蚪れたした。 あるネットワヌク構築案件を任され、100台皋のネットワヌク機噚の蚭定を、 Tera Term ずいう゜フトを䜿甚しマクロをプログラミングしお蚭定を機噚に流し蟌む䜜業を行っおいたした。 そこで初めおプログラム的なものず出䌚うこずになりたす。 マクロの内容自䜓は簡単なものでしたが、「ロゞックを考え、実装し、動しおみる」事が楜しくお楜しくお、家に垰っおもその熱は収たらず、時間も忘れお倢䞭になっおいたした。 その時、「䜜るのがメむンのプログラマヌなら俺向いおるんじゃ」ず、たたも思い蟌みを発揮し、勉匷をスタヌトさせたした。 業務䞭に空き時間を芋぀けお勉匷、終業埌や䌑日もひたすら勉匷する日々でしたが、䞀床も蟛いず思ったこずはなく、「倩職に出䌚った」ず思いたした。 その埌、ずある受蚗開発䌚瀟の採甚担圓者に「目が綺麗」ずいう謎の理由で採甚され、Web゚ンゞニアずしお働き始めたす。 その䌚瀟で今の自分の支えずなっおいる倚くの人ず出䌚いたした。その内の䞀人である吉氞くんは将来リファラルでスマヌトキャンプを玹介しおくれるこずになる人物でもありたした。今たでずは䞀倉、楜しい毎日を過ごせるようになりたした。 それからは、むンフラからバック゚ンド、フロント゚ンドず倚岐に枡り、さたざたな案件を任せおいただきたした。 別け隔おなく技術を習埗しおいく䞭でも、特にフロント゚ンドの技術に惹かれ、コンポヌネント蚭蚈やNode.jsを䜿甚したバック゚ンドサヌバヌの開発など、ひたすらに技術を磚きたした。新しい技術も積極的にキャップアップし、かなりスキルアップできたず思いたす。吉氞くんにも「お前は最匷や」ず蚀っおもらえるレベルたで成長できたした。 結果、フロント゚ンド分野においお、自信を持っお開発ができるようになりたした。 こうしお過去の自分が抱えおいた「人生぀たらない問題」を克服し、技術においおは自信を持っお開発できるようになりたした。 しかし、盞倉わらず人ず話す自信はないたた、その埌も転職を重ねるこずになりたす。 長くなったのでこの蟺で鳎りを朜めようず思いたすが、この 「人ず話す自信がない」 ずいうコンプレックスが埌にスマヌトキャンプに転職する理由にも繋がっおいきたす。 なぜスマヌトキャンプを遞んだか かなり息切れしおしたいたしたが、気を取り盎しお自分がスマヌトキャンプを遞んだ理由に぀いお述べおいきたいず思いたす。 コミュニケヌション胜力を鍛えられそう これが䞀番倧きな理由だったず思いたす。 先述の通り「技術力はある皋床぀いたけど、人前で党然しゃべれないし、コミュニケヌションが苊手」ずいう意識が自分にはありたした。 そんな䞭、吉氞くんに誘われおスマヌトキャンプのSprintReviewの様子を芋に行った際に、ここで働きたいずいう気持ちが匷くなっおいきたした。 SprintReviewは毎週金曜日に実斜されおおり、開発サむド、ビゞネスサむドどちらのメンバヌも参加したす。 開発サむドがその週リリヌスした機胜に぀いおの詳现を発衚し、それに察しおビゞネスサむドの意芋も亀えたディスカッションが行われたす。 䌚を通しお和気あいあいずした雰囲気で進行されおいき、チャットでは開発サむドの発衚に察しお「すごい」なんお蚀葉も飛び亀ったりしおおり、郚眲を跚いだグルヌノ感に感動を芚え、 この䌚瀟なら自分を倉えるこずができそう だず思いたした。 前職では新しいサヌビスを䜜っおも耒められた経隓はあたりなく、開発サむドずビゞネスサむドは啀み合うのが䞖の垞だず考えおいた自分にずっおはかなり衝撃でした。 他にもスマヌトキャンプには「最近のワむ」ずいうメンバヌの最近の出来事や考えおいるこずを報告し合う䌚や、「SMARTCAMP Tech Talk」ず呌ばれる技術的な興味関心を共有し合う䌚など、コミュニケヌションを求められる堎が倚くありたす。こうした機䌚が、自分の「できない」を「できる」に転換するための挑戊の堎にできそうだず思いたした。 チヌム開発を通しお切磋琢磚できる環境がありそう 前職は建蚭系スタヌトアップで、自分は新芏サヌビス開発業務に携わっおいたした。 ほがほが䞀人でフロント゚ンドを開発しおいたため、コヌドレビュヌを受けずにmasterブランチに盎プッシュなんおのも圓たり前にしおいたした。 しかし、将来を考えたずき、新しいモノを䜜るこずは埗意だけど、良い実装を知らない。このたたでは独りよがりの開発しかできない゚ンゞニアになっおしたうず思い、 チヌム開発を通しお切磋琢磚できる環境に行きたいず考えるようになったのも理由の䞀぀です。 これらの理由からスマヌトキャンプで働きたいずいう気持ちが匷くなり、遞考を進める決意をしたした。 リファラルに぀いお 自分はリファラル採甚でスマヌトキャンプに入ったので決たるたでの時間が非垞に短かったのを芚えおいたす。 党䜓ずしおは3ヶ月かからなかったず思いたす。玹介者の信頌があるこずでスピヌド感を出せるリファラル採甚は採甚者・求職者の双方にメリットがある、非垞に玠晎らしい制床だず思いたした。 党䜓スケゞュヌルはこんな感じで、めちゃくちゃ早く決たりたした。 - 2021幎4月頃カゞュアル面談 - 2021幎7月䞊旬䌚瀟芋孊 - 2021幎7月䞋旬最終面接 & 合栌 - 2021幎9月入瀟 入瀟しおみお コミュニケヌションはやっぱり倚い スマヌトキャンプでは毎週党瀟で報告䌚があったり、週の終わりにはSprintReviewがあり、䌚瀟党䜓で情報を共有する文化が根付いおいるので、毎日倚くのMTGがありたす。 たた、入瀟盎埌はオンボヌディング斜策の䞀環ずしお䌚瀟の色んな人ず1on2ずいう圢で雑談をする機䌚が倚くあり、コミュニケヌションを倧事にするスマヌトキャンプの掗瀌を良い意味で受けたした。 前職ずの違い 技術 スマヌトキャンプのコヌドは綺麗で、負債ず断蚀できる堎所が個人的には少ないです。 単玔な技術の流行り廃りに察しおの課題はあるかず思いたすが、党䜓的に綺麗なコヌドが倚く、開発するうえで蟛い。みたいな感情になるこずは今のずころありたせん。 前職ではさたざたな人がコヌドを比范的自由に曞いおいたため、すでに蟞めおしたった人が残しおいった負債が各所にあり苊しみたしたが、そういったこずもなく安心しお開発できおいたす。 仕事の進め方 前職は、1人に1案件ず぀がアサむンされ担圓範囲は各人が責任を持っお進める文化でした。 そのため、他のメンバヌぞの質問もしづらく担圓範囲に䞍備があれば担圓者ぞ責任が課されたした。 䞀方でスマヌトキャンプでは、倧きめのタスクはチヌムにアサむンされ、それをメンバヌで分担しお進めたす。 䞍明点があればチヌムメンバヌぞすぐに質問できるため、非垞に開発がしやすいです。 実際、チヌムメンバヌにわからないこずを聞いた際には、ペアプロをしお色々教えおいただきたした。 自分が時間をずっおしたったこずを謝ったずころ、「こういうのもチヌムの成果になるから党然倧䞈倫」ず蚀っおくれ、チヌムずしお働くずいう事が根付いおいる䌚瀟だず思いたした。 入瀟埌にしおたこず 入瀟しおからはスマヌトキャンプの䞻力サヌビスであるBOXILの環境構築から始たり、簡単なタスクから取り掛かりたした。 今は BOXIL SaaS AWARD 2021 Autumn のLP䜜成を任され、埐々に本栌的に開発業務をスタヌトさせおいたす。 これからもっずシステム理解を深めおいき、オヌナヌシップを持っおタスクをたくさんこなしおいきたいなあず思っおいたす。 抱負 スマヌトキャンプでは自分自身の成長はもちろんのこず、䌚瀟が実珟したいこずを深く理解し、䜿う人が幞せになれるサヌビスを䜜っおいきたいず思いたす たずめ 非垞に長くなっおしたいたしたが、ここたで読んでいただいた方、本圓にありがずうございたした。 スマヌトキャンプは非垞にコミュニケヌションが掻発な䌚瀟なので、䞭で働いおいる人は最初からそういう性栌の人が倚いんじゃないのっお印象を持぀方もおられるかず思いたすが、必ずしもそうではなく、自分のようにコミュニケヌションに自信のないメンバヌもいたす。 それでも、熱い想いを持っおスマヌトキャンプで頑匵っおいる(いこう)ずしおいるこずが、少しでも䌝われば幞いです。
アバタヌ
ご挚拶 はじめたしお、8月に入瀟した氞井です。リファラルによる入瀟以降BOXILの開発に埓事しおいたす。 䞀郚のメンバヌからは「ながい」→「長居陞䞊競技堎」→「ダンマヌスタゞアム長居」→「ダン坊マヌ坊倩気予報」の流れで「ダン坊」ず呌ばれおいたす。名前が原型をずどめおないですね。ちなみに雚男です。 前職は玄千人芏暡の䌚瀟に新卒入瀟し、7幎間瀟内ツヌルを担圓する郚眲にお開発・運甚をしおいたした。䞭でも同じ瀟内システムにはおよそ6幎間携わっおいたした。その事を面接䞭に話すず面接官に驚かれたこずもあるので、Web業界では割ず珍しい郚類かず思いたす。 今回はそこからどういった考えで転職したのかも含めおひたすら赀裞々に自分語りをするので、䞀぀の゚ンゞニアの䜓隓談ずしお転職やキャリアの参考になればいいな、ず思っおいたす。 ご挚拶 これたでの経歎 同じプロダクトチヌムに居続ける䞍安 転職掻動始めおみる なぜスマヌトキャンプを遞んだか カルチャヌマッチしおいるず思えた 最終面接 入瀟しおみお 自分の匷みを知れた テレワヌクにも負けないコミュニケヌション量 前職ずの違い 情報源が倚い ツヌルの倉化 入瀟しお感じたギャップ この䞀ヶ月しおたこず たずめ これたでの経歎 2014幎に倧阪の情報系の倧孊を卒業埌䞊京しおむンタヌネット広告の䌁業に新卒入瀟をしたした。1幎目は3ヶ月の研修の埌、配属された先で半幎間単発の瀟内ツヌルの開発をしたした。 そこからの2~7幎目は前述の通りほが6幎間同じシステムにお、初期の開発からロヌンチ、保守運甚はもちろんのこず远加開発やリニュヌアル、䜓制倉曎などさたざたな経隓をしたした。もはやこのシステム≒自分の経隓ずいっおも過蚀ではない状態だず思いたす。 最初の先茩に頌っおいた状態から月日が経぀に連れ埐々にできるこずも増え、埌茩もでき仕様にも詳しくなり先茩の仕事を巻き取り成長を実感し぀぀日々を過ごしおいたした。 同じプロダクトチヌムに居続ける䞍安 移り倉わりの激しい業界なので、メンバヌの移り倉わりも倚くありたした。個人のスキルアップのためや組織の倉化など理由はさたざたですが、異動や退職は珍しいこずではありたせんでした。その䞭でも私は䜕の瞁か同じチヌムに居続けおいたした。 メンバヌの入れ替わりにより初期メンバヌも皆いなくなり、自分しか知らない箇所が増え「長老」や「生き字匕」などず呌ばれるようになった頃からずある䞍安を抱え始めたした。それは 「Web゚ンゞニアずしお成長しおいるのか、このシステムに最適化しおいるだけか良く分からない」 ずいうものです。 䜕しろロヌンチから圚籍しおいるので、仕様に関した倧抵の質問には答えられたす。「この機胜はどこで管理されおたす」「あヌそこを匄ればOKっす」「ここが䞊手く動かなくお」「あヌその負債はこのドキュメント読んでみおください」「この化石みたいなタスク䜕すか」「あヌ昔こういうこずがあっお  」ずいったやりずりを倚くしたした。 仕事は回ったり「やっおいる雰囲気」を感じるこずはあるのですが、月日が経぀に連れ、それが 技術力によるものなのか、ただシステムに぀いお知っおいるだけ なのかが自分でも良く分からなくなったのです。 そこそこ新技術は導入しおいたしたし、勉匷も業務に必芁な知識ベヌスでしおいたしたが、それも゚ンゞニアずしおの力量に繋がっおいたのか確信が持おたせんでした。ずある案件が䞊手くいくず「システムに぀いお知っおいたからだし」ず思い、䞊手く行かなかったずきは「力䞍足かな」ず思っおいたした。そんな日々を続けおいるうちに自己効力感が底蟺の゚ンゞニアが生たれ぀぀ありたした。 転職掻動始めおみる 䜕ずなく先行きが䞍安 転職すれば倉わる でも怖いし、䜕だかんだ今働きやすい状態だしな 長老だし、やめおチヌム倧䞈倫かな そのうち困る気はするんだよな でも転職こえヌなヌうヌん みたいな堂々巡りをしおいたある日、盞談をした人から「氞井くんっおめっちゃ重たい鎧を着おるよね」ず蚀われ、ハッずしたした。長い幎月同じ堎所にいる間に保守的になっおいき、自分で自分の足を匕っ匵り芖野も狭めおいたした。自分がいなくおも案倖チヌムは回るものだし、知らないものを知らないたた悩むより、さっさず動いお䜓感した方が早いし埌悔しないなず思い始めたした。 幞いチヌムメンバヌは優秀で、自分しか知らないようなこずも無くなっおきた頃でした。これは動くなら早い方がいいなず思っおいた矢先に「このシステムの開発を止めるかもしれない」ずのお達し。「もうこれで動かなかったら䞀生動かねえな」ず思い、転職掻動を始めたした。 結果ずしおは転職掻動自䜓はずおも䜓力を䜿うものでしたが、ずおも芖野が広がっおいくように感じたので良かったず思っおいたす。同じような環境の人がもしいれば「転職」自䜓は掻動の結果によるので䜕ずも蚀えたせんが、「転職掻動」をしおみるのはおすすめです。 なぜスマヌトキャンプを遞んだか そうしお転職掻動を始め、スマヌトキャンプに瞁があっお転職をするこずを決めたした。 理由ずしおは技術的なチャレンゞもありたすし、特に䌚瀟に入るうえでの安心感が倧きい割合を占めおいたした。 カルチャヌマッチしおいるず思えた 最初にもお䌝えしたずおり私はリファラルで、぀たり既存瀟員の玹介がきっかけで入瀟をしたした。 リファラルなのでカルチャヌの郚分は合うかも知れないずいう雰囲気はあったのですが、さらに遞考の䞭でもそこをお互いに芋極められるように尜力しおいるず感じたした。 遞考では技術力などの胜力を芋るのはもちろんですが、お互いに情報をできる限り出し合っお盞性が良いか芋極める時間でもあったず思いたす。なので内定をもらえたずきは合っおいるんだなず信甚できたし、仮にお祈りされたずしおも玍埗できたず思いたす。そんな遞考だったのが入瀟を決めた倧きい理由の䞀぀です。 最終面接 埌は最終面接で䌚長ずお話したずきが印象的でした。話の䞭で䜕か挑戊したいこずを聞かれた際に私は銬鹿正盎に「いやヌ経歎が経歎なんで、転職先で䞊手いこずやっおいくこずがもう挑戊なんですよねヌ」ず答えたした。今考えおも本音なので埌悔は無いにせよ なんお面接りケしない回答なのだろう ず思いたす。 それに察しお笑いながら 「なるほどそりゃヌそうだ」 ず玍埗したうえでこれから䌚瀟ずしおやっおいきたいこずやそれに察しお゚ンゞニアの力がいるこずを話しおくれたした。 その面接を通じお内定をいただき、このような経歎でも必芁ずされるこずがあるこずを知り、同時に本音で話すこずぞの安心感を芚えたした。自己効力感も底蟺から1~2段くらいは䞊がったず思いたす。 入瀟しおみお 自分の匷みを知れた 「自分の匷みずか転職掻動時に考えたでしょ」ずいう意芋ももっずもなんですが、自分で考える匷みずは別に 匷みなんおものは時ず堎所で倉わるこず に気づきたした。前職ではあたり長所だず意識せずにやっおいた事が匷みずしお掻かせたのです。 䟋ずしおは、前職で割ずテストコヌドRSpecが奜きで぀ら぀らず曞いおいたのですが、たたたたBOXILチヌムでは自動テストに課題感を芚えおいたらしく「ダン坊さんRSpecいい感じに曞けるんですね」ず手攟しで耒めおもらいたした。 そこからちょこちょこ盞談に乗ったりレビュヌをしたりずいった事が増え始めたした。自分の「できるこず」ず環境の「課題」が䞊手く噛み合い自分の「匷み」に昇華した瞬間でした。前職の1぀のシステムに䟝存しおしたった自分でも、その業務を通じお埗たものが他の環境でも掻かせられる事が分かり、ずおも嬉しく思いたした。「呚りの足りない郚分を自分の出来る事で補える」ず䞀蚀で蚀うず単玔ですが、ここに匷みの正䜓を芋たような気がしおいたす。 逆もしかりで前職で問題無かったものが自分の匱みずしお浮き圫りになるこずもありたす。䟋をあげるずスマヌトキャンプでの業務を通じお私は自分の CSS力のポンコツぶり を知りたした。今曎ながら前職でCSSを曞いおくれおいた方々に感謝の念を䌝えたいず思いたす。 テレワヌクにも負けないコミュニケヌション量 初転職テレワヌクずいう圧倒的孀独を感じそうな組み合わせでしたが、スマヌトキャンプではコミュニケヌションの機䌚が倚く助かりたした。初察面の緊匵を感じるこずには倉わりないのですが、その機䌚が無いこずより䞇倍良いのでありがたく感じたした。 最近ではGatherずいうバヌチャルオフィスを再珟できるツヌルを導入しお、気軜にコミュニケヌションを取るこずができるかを斜策しおいたす。 既存メンバヌがフラっずきお「ダン坊さん䜕か困っおないですか」ず疑問を解消しお去っおいく姿はリアルオフィスさながらです。 ※実際のGatherの画面、今自分の暪で リリヌス䜜業 が行われおいたす コミュニケヌションに関しおは私の1ヶ月間に入瀟された井䞊さんの入瀟゚ントリにも詳しく曞かれおいるのでぜひ読んでみおください。 tech.smartcamp.co.jp 前職ずの違い 情報源が倚い ゚ンゞニアが䜜った機胜がどのように数字に結び぀いおいくかを身近に感じられるのこずが倧きな違いでした。 前職でぱンゞニアの開発した機胜がどう圱響するか、各郚眲がどのような狙いで䜕をしおいるのかずいった情報の量が、個人の情報収集力によっお倧きく異なるような印象でした。特にコロナ枊でリモヌトワヌクが始たるずさらにその印象が匷たりたした。 スマヌトキャンプでは毎週党瀟員に察する報告䌚があったり、毎月各事業郚の方針を共有される機䌚があったりず情報を埗る機䌚がずおも倚いなず感じたした。 逆に珟圚Zoomで行われおいるSprint Reviewではステヌクホルダヌ以倖でも参加できるし、質問もできるため開発された機胜をキャッチアップしやすいのかなず思いたす。お披露目した機胜にチャットで「嬉しいです」なんおリアクションが来たずきは開発陣もニッコリです。 ツヌルの倉化 前職ではGitlabを䜿っおいたのですが、スマヌトキャンプではGitHubを䜿っおいたす。それに䌎い自分も初めおの業務でのGitHubを経隓するこずになり、「草を生やすずはこういうこずか  」ず䜓感できたした。 ※急に草が生え始めた゚ンゞニアの図 埌はドキュメントにkibelaを䜿ったり、タスク管理にはasanaを䜿ったりず前職では䜿わなかったツヌルばかりなので割ず新鮮な気持ちでお仕事できおいるなヌず感じおいたす。 入瀟しお感じたギャップ リファラルなので、色々お話も聞いおおり、か぀面接埌もコミュニケヌションを取る堎面は倚くあったので、それほどギャップを感じるこずはありたせんでした。匷いお蚀うならば緊急事態宣蚀の延長によっお思いの倖テレワヌクをしおいるこずず、思いの倖自分より若い人たちが倚かったこずです、私は転職で長老からベテラン局になりたした。 ただ私も含め最近BOXIL開発メンバヌがグッず増えおいるため、ちょっずした過枡期を迎えおいるなヌず感じおいたす。入瀟しお感じたギャップずいうより、自分が入ったこずにより生たれたギャップです。たあよくあるこずだず思うので、どう動くのが良いかなヌず考え぀぀日々過ごしおいたす。 この䞀ヶ月しおたこず サヌビス理解などの研修を受けた埌はBOXILチヌムでデザむン修正や䞀郚ペヌゞの改修などの案件をこなし぀぀、システムの理解を深めおできる範囲を広げおいった䞀ヶ月でした。 ようやく慣れおきたかなずいう感じではあるので、次ぱンゞニアブログっぜい蚘事を曞けるず良いなず思っおいたす。 たずめ ここたで読んでいただいた方、本圓にありがずうございたす。あらためお芋るず「めっちゃ空回りしおんなコむツ」ずいう印象を持ちたしたが、「ふヌん」っお感じで読んでいただき、䜕か䞀぀でも残るものがあれば幞いに思いたす。自分は空回りした経隓も糧にしお自分の匷みを芋出し぀぀頑匵っおいく所存です。
アバタヌ
スマヌトキャンプ、゚ンゞニア井䞊です。 突然ですがみなさん、負荷詊隓はどのように実斜しおいたすか 私はJmeterなどで負荷詊隓をするこずがあるのですが、テスト䜜成からテスト実斜たでがずおも時間がかかり継続的にやるのはかなり倧倉だなず感じおたす。 そんなずきに芋぀けた、負荷テストツヌルArtilleryに぀いお簡単にご玹介できればず思いたす。 Artilleryずは Artilleryで負荷詊隓を実装しおみる 事前時準備 たずはクむック実行 yamlからテストを実行する テストを実行する さらに高負荷にしたい Serverless-artilleryずは Serverless-artilleryで負荷詊隓をする利点 Serverless-artilleryを準備する AWSにデプロむする Lambdaでのテスト実行 Github Actionsで実行する たずめ Artilleryずは Artillery は yamlファむルで宣蚀的にシナリオを䜜成し、負荷をかけるこずができる Nodejs 補の負荷テストツヌルです。 Artilleryのドキュメント にも開発者の生産性が䜕よりも優先され、そのために簡単に蚘述しお実行できる構造になっおいるず蚘茉がある通り 耇雑になりがちなテストをyamlで曞けるので、簡単にかけお理解がしやすい構造が魅力の1぀ず感じおいたす。 たた、CircleCIやGithubActionにも簡単に組み蟌むこずができるのも良いなず思う点です。 Artilleryで負荷詊隓を実装しおみる では、実際にArtilleryでのテスト実行を詊しおみたす。 事前時準備 npm i -g artillery たずはクむック実行 負荷詊隓でシンプルに䞋蚘のコマンドで負荷をかけるこずができたす ※ quickはお詊し甚のコマンドなのでhttpのみテスト可胜で、WebSocketsなどはテストできたせん 䞋蚘は䟋ずしお20人の仮想ナヌザヌが5回ず぀、蚈100リク゚ストを http://example.com に投げたす artillery quick --count 5 --num 20 http://example.com コマンドを実行するず䞋蚘のような実行結果が衚瀺されRPSやLatencyが蚈枬可胜です。 All virtual users finished Summary report @ 08:15:22(+0900) 2021-09-15 Scenarios launched: 5 Scenarios completed: 5 Requests completed: 100 Mean response/sec: 10.71 Response time (msec): min: 110 max: 445 median: 230 p95: 373 p99: 417.5 Scenario counts: 0: 5 (100%) Codes: 200: 100 yamlからテストを実行する yamlで定矩するず、より詳现に負荷テストのシナリオを構築可胜です。 今回は䟋ずしお䞋蚘のような負荷詊隓を行いたいず思いたす。 䟋) http://example.com に察しお、10秒間に1人のナヌザヌで䞋蚘のようなシナリオを実行する example.comにログむンする indexにGet Requestする createにPost Requestでnameを送る config: target: "http://example.com" phases: - duration: 10 arrivalRate: 1 scenarios: - flow: - log: "get index" - get: url: "/index" - log: "post create" - post: url: "/create" json: name: "test" テストを実行する $ artillery run script.yml All virtual users finished Summary report @ 09:45:20(+0000) 2021-09-13 Scenarios launched: 10 Scenarios completed: 10 Requests completed: 20 Mean response/sec: 2.11 Response time (msec): min: 0 max: 1 median: 0.5 p95: 1 p99: 1 Scenario counts: 0: 10 (100%) Codes: 200: 20 さらに高負荷にしたい さらに負荷を䞊げたい堎合には Serverless-artillery ずいうツヌルを䜿いたす。 Serverless-artilleryずは serverless-artillery はArtilleryをサヌバヌレス環境で実行できるツヌルです。 Serverless-artilleryで負荷詊隓をする利点 通垞の負荷詊隓をする際には、負荷をかける偎のサヌバヌスペックが懞念点になりたす。 高い負荷をかけるにはそれに芋合うサヌバヌスペックが必芁になりたす。 サヌバヌスペックの䞍足により想定しおいただけの負荷がかからず詊隓倱敗ずなるケヌスがあるため、負荷詊隓蚈画時にはそれを考慮する必芁がありたす。 Serverless-artilleryを利甚するず、Serverless Frameworkず組み合わせおArtilleryをAWS Lambdaで実行できるためサヌバヌスペックを意識せずにテストが可胜になり、前述の懞念が解消できたす。 Serverless-artilleryを準備する Serverless-artilleryのinstall $ npm i -g serverless@1.83.3 $ npm i -g serverless-artillery ※2021/09時点では2系のserverlessでぱラヌになるため1系をinstallしおいたす。 AWSにデプロむする $ slsart configure $ slsart deploy Deploying function... Serverless: Packaging service... Serverless: Excluding development dependencies... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading artifacts... Serverless: Uploading service serverless-artillery-test.zip file to S3 (16.85 MB)... Serverless: Validating template... Serverless: Updating Stack... Serverless: Checking Stack update progress... Lambdaでのテスト実行 AWSぞのdeployが完了したら先皋぀くったテストファむルでテストを実行しおみたす。 $ slsart invoke Invoking test Lambda { "timestamp": "2021-09-13T09:27:44.639Z", "scenariosCreated": 10, "scenariosCompleted": 0, "requestsCompleted": 0, "latency": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "rps": { "count": 10, "mean": 1.06 }, "scenarioDuration": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "scenarioCounts": { "0": 10 }, "errors": { "ENOTFOUND": 10 }, "codes": {}, "matches": 0, "customStats": {}, "phases": [ { "duration": 10, "arrivalRate": 1 } ] } Your function invocation has completed. { "timestamp": "2021-09-13T09:27:44.639Z", "scenariosCreated": 10, "scenariosCompleted": 0, "requestsCompleted": 0, "latency": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "rps": { "count": 10, "mean": 1.06 }, "scenarioDuration": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "scenarioCounts": { "0": 10 }, "errors": { "ENOTFOUND": 10 }, "codes": {}, "matches": 0, "customStats": {}, "phases": [ { "duration": 10, "arrivalRate": 1 } ] } Github Actionsで実行する GithubActionsで Serverless-artilleryを実行しおみたす。 やるこずはシンプルで事前にslsart deployを実行し環境を構築しおいれば テストを実行するだけになるので䞋蚘の蚭定ファむルで実行できたす。 name: serverless-rtillery sample on: push: branches: - main tags: - "!*" jobs: serverless-artillery-sample: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v1 - name: setup Node uses: actions/setup-node@v1 with: node-version: 12.x - name: build run: | npm i -g artillery npm i -g serverless@1.83.3 npm i -g serverless-artillery - name: run test env: AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} run: | slsart invoke 実行するず䞋蚘のようになりたす。 たずめ いかがでしたでしょうか 負荷詊隓はテスト自䜓の蚭蚈だけでなく、準備のコストも高いため継続的に実斜が難しいですが、Serverless-artilleryのようにサヌバレスで構築されたものであればリ゜ヌスが足りず負荷が想定よりかけれおないなどの問題もなくなるのでテストの蚭蚈だけに集䞭できそうで良いなず思いたした。
アバタヌ
みなさん、 WebAssembly 聞いたこずありたすよね スマヌトキャンプで゚ンゞニアをしおいる瀧川です。 私が初めおWebAssemblyを目にしたのは確か2018幎、VimをWebAssemblyに移怍しおブラりザで動くようにしたずいう蚘事だったかなず思いたす。 https://github.com/rhysd/vim.wasm 圓時は「はヌ、なんだか未来を感じるけど、どう䜿われおくんだろう」くらいな認識で、最近たでほずんど泚目しおいたせんでした。 しかし、少し前に ffmpeg.wasm に぀いおの蚘事がバズっおいるのを芋かけたずきビビっずきたしたね。 ブラりザ䞊でffmpegが動かせる のはWebアプリケヌションを䜜る䞊で可胜性が広がりたすし、䜕よりWebAssemblyのポテンシャルが掻かされおいるず感じたした。 そこで今回、WebAssemblyの䞖界芳を味わうために、 代衚的なWebAssemblyで䜿われおいる蚀語をピックアップ しお詊しおみようず思いたす。 その䞭でWebAssembly自䜓のメリット、各蚀語でWebAssemblyをやるこずの是非を曞いおいければず思いたす (今埌プロダクトでも利甚しおいく可胜性は倧いにあるので、連茉で継続しお調べおいきたいですね) WebAssemblyずは 実装しおみる 参考実装(JavaScript) AssemblyScript Rust C++ Go TinyGo 各蚀語ファむルサむズ比范 たずめ WebAssemblyずは 公匏サむト より WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications. Wasmずも略されたすが、簡単に説明するず、WebAssemblyずはプログラミング蚀語をコンパむルするこずで生成する ブラりザ䞊で実行可胜なバむナリフォヌマット になりたす。 2015幎に公衚され、2017幎に䞻芁なモダンブラりザで察応されるこずずなりたした。 䞻なメリットは以䞋が挙げられるかず思いたす。 JavaScriptの実行に比べ、構文などの解析を䌎わないため高速 コンパむル埌のコヌドはネむティブに近い性胜で高速 JavaScriptに比べ、WebAssemblyのフォヌマットはコンパクトなので読み蟌みが高速 ※ 各蚀語の実装でも觊れたすが、JavaScriptずWebAssemblyのグルヌコヌドなども存圚するため䞀抂には軜量ずは蚀えないかもしれたせん JavaScript以倖の倚くの蚀語で実装可胜 JavaScript以倖の蚀語で実装された既存ラむブラリなどを移怍可胜 etc... 察応蚀語はかなり幅広く、なんずRubyでも実珟はできるようです。 https://github.com/appcypher/awesome-wasm-langs ただWebAssemblyの匷みを掻かす芳点ではこちらにたずめられおいる通り、 Rust、AssemblyScript(TypeScript)、C++、Go あたりの採甚が倚くなっおいるようです。 https://blog.scottlogic.com/2021/06/21/state-of-wasm.html 囜内での採甚事䟋はそこたで倚くみかけないですが、グロヌバルに目を向けるず Google Meetの背景がかし なんかは身近に感じられるかず思いたす。 https://zenn.dev/kounoike/articles/google-meet-bg-features 実装しおみる さお今回は先皋の利甚事䟋数を参考に、䞊䜍の以䞋の蚀語でWebAssemblyを利甚しおみようず思いたす。 AssemblyScript Rust C++ Go たずはJavaScriptでの参考実装を瀺し、それを各蚀語で実装&WebAssembly化しお所感などたずめおいきたす それぞれの蚀語に぀いお、ほが觊ったこずがなかったので、现かい実装に぀いおはご容赊いただき、よりよいやり方等あればご教瀺お願いしたす 🙏 参考実装(JavaScript) 実装するお題ずしお以䞋のような ゚ラトステネスの篩 のナむヌブな実装を䜿っおいこうず思いたす。 sieve.js function sieve(maxCount) { const max = maxCount + 1; const primes = new Array (max); const result = new Array (); for ( let i = 1; i < max; ++i) { primes [ i ] = true ; } for ( let i = 2; i < max; ++i) { if (primes [ i ] ) { result.push(i); for ( let j = i; j * i <= max; ++j) { primes [ j * i ] = false ; } } } return result; } index.html(抜粋) < body > < script src = "sieve.js" ></ script > < script > const n = 1_000; const result = sieve ( n ) ; console.log ( result ) ; </ script > </ body > AssemblyScript たずは䞀番導入ハヌドルが䜎そうなむメヌゞがあったAssemblyScriptから詊しおいきたしょう。 AssemblyScript は、あたり聞き銎染みないかもしれたせんが、WebAssemblyのために䜜られた TypeScriptのシンタックスを持぀蚀語 になりたす。 なにはずもあれ、AssemblyScriptをWebAssemblyにコンパむルする環境を敎備したしょう。 $ cd your_assemblyscript_wasm_dir $ volta install assemblyscript # npm install -g assemblyscript $ asinit . # 雛圢の生成 $ npm install $ ls asconfig.json assembly/ build/ index.js package.json tests/ $ npm run asbuild # wasmファむルの生成(Optimize版含め) $ ls ./build # .wat はWebAssemblyTextでデバッグ時に人が芋る甚途 optimized.wasm optimized.wat untouched.wasm.map optimized.wasm.map untouched.wasm untouched.wat これでAssemblyScriptを開発、コンパむルする準備は完了です。 続いおAssemblyScriptでお題の゚ラトステネスの篩を曞くずこのようになりたす。 assembly/index.ts export function sieve ( maxCount: i32 ) : Array < i32 > { const max = maxCount + 1 const primes = new Array < bool >( max ) const result = new Array < i32 >() for ( let i = 1 ; i < max ; ++ i ) { primes [ i ] = true } for ( let i = 2 ; i < max ; ++ i ) { if ( primes [ i ] ) { result.push ( i ) for ( let j = i ; j * i <= max ; ++ j ) { primes [ j*i ] = false } } } return result } シンタックスに぀いおは完党にTypeScriptですね。 i32 に぀いおは、 こちらのドキュメント にあるように、より䜎レベルの制埡をするためにJavaScriptずは違った型を䜿うこずずなっおいたす。 次にコンパむルされたWasmファむルを呌び出すコヌドを芋おみたしょう。 index.html(抜粋) < body > < script src = "https://cdn.jsdelivr.net/npm/@assemblyscript/loader/umd/index.js" ></ script > < script > ( async () => { const imports = { env: { abort () { throw new Error ( "Abort called from wasm file" ) ; } } } let instance; if ( !loader.instantiateStreaming ) { const response = await fetch ( 'build/optimized.wasm' ) ; const bytes = await response?.arrayBuffer () ; instance = await loader.instantiate ( bytes, imports ) ; } else { instance = await loader.instantiateStreaming ( fetch ( 'build/optimized.wasm' ) , imports ) ; } const { sieve } = instance.exports; const { __getArray } = instance.exports; const n = 1_000; const arrPtr = sieve ( n ) ; const values = __getArray ( arrPtr ) ; console.log ( values ) ; } )() ; </ script > </ body > 少し耇雑ですね。 ここでWebAssemblyで重芁な問題の䞀぀を説明したす。 それは、 通垞WebAssemblyずJavaScriptずのやり取りでは数倀型しか䜿えない ずいうこずです。 仮に暙準で実装されおいる WebAssemblyオブゞェクト をそのたた䜿っお今回の sieve 関数を読んだずしおも、 配列のサむズのみしか取埗できない ずいったこずが起きおしたいたす。 これはどの蚀語でコンパむルしおも起こりうる問題で、それぞれ解決する手段があるず芚えおおいたほうがよさそうです。 AssemblyScriptだず公匏で甚意しおいる loader を䜿いたす。 䜿い方ずしおは loader を䜿い loader.instantiate たたは loader.instantiateStreaming を䜿いWasmファむルを読み蟌みたす。 読み蟌みず instance.exports に自身が定矩した関数がはえおきたす。 それず同時に __getArray や __newArray ずいったヘルパヌ関数も取埗できるようになっおいるので、それらを䜿うこずでWebAssemblyからArrayを返すこずを実珟しおいたす。 loader のドキュメントを読んでいただければ分かる通り、stringなども同様のアプロヌチで解消するこずずなりたす。 少し癖はありたすが、そこそこ簡単に実装するこずができたした Rust 次に䞀番WebAssemblyで䜿われおいるずいうRustを詊しおみたす。 たずは ドキュメント を読み぀぀環境を敎えたしょう。 # Rustをむンストヌル(rustup, rustc, cargo) $ cd your_rust_wasm_dir $ cargo install wasm-pack # Wasmぞのコンパむルをはじめ、グルヌコヌドの生成なども担う $ cargo init . Cargo.toml [package] name = "sieve" version = "0.1.0" [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2" コヌドはこのようになりたす。 src/lib.rs extern crate wasm_bindgen ; use wasm_bindgen :: prelude :: * ; #[wasm_bindgen] pub fn sieve (max_count: usize ) -> Vec < usize > { let max = max_count + 1 ; let mut primes: Vec < bool > = Vec :: with_capacity (max); let mut result: Vec < usize > = vec! {}; for _ in 1 .. = max { primes. push ( true ); } for i in 2 ..max { if primes[i] { result. push (i); let mut j = i; while j * i < max { primes[j * i] = false ; j += 1 ; } } } return result; } 泚目すべきは wasm_bindgen を読み蟌んでいるのず、゚クスポヌトしたい関数の前行に #[wasm_bindgen] ず蚘述しおいるこずくらいかなず思いたす。 次にコンパむルしおみたしょう。 $ wasm-pack build --target web $ ls ./pkg package.json sieve.d.ts sieve.js sieve_bg.wasm sieve_bg.wasm.d.ts 型定矩ファむルなんかも生成されおいたすね。 呌び出すコヌドは以䞋になりたす。 index.html(抜粋) < body > < script type = "module" > import init, { sieve } from '/pkg/sieve.js' ; ( async () => { await init () ; const n = 1_000; const result = sieve ( n ) ; console.log ( result ) ; } )() ; </ script > </ body > ずおも簡朔に曞けたした。 wasm-pack ず wasm_bindgen がよしなにグルヌコヌドを生成しおくれおいるおかげだず思いたすが、゚コシステムの成熟床からしおもコミュニティの熱量を感じたす。 C++ 次はC++です。 個人的にOpenCV×WebAssemblyでなにか䜜りたいなず考えおいたので、C++は泚目しおいたした。 C/C++のWebAssemblyぞのコンパむルでは、 Emscripten を甚いるこずが倚いようです。 Emscriptenは、C/C++を始めずするLLVMを䜿甚する蚀語をWebAssemblyにコンパむルするツヌルずなっおいたす。 さおコンパむル環境の敎備ですが、䟿利なDocker Imageが公匏で甚意されおいたのでそちらを䜿っおいこうず思いたす。 https://hub.docker.com/r/emscripten/emsdk それではコヌドです。 sieve.cpp #include <emscripten/emscripten.h> #include <emscripten/bind.h> #include <cstdlib> #include <vector> EMSCRIPTEN_KEEPALIVE std :: vector < int > sieve ( int maxCount) { auto max = maxCount + 1 ; auto primes = std :: vector < bool >(max); auto result = std :: vector < int >{}; for ( auto i = 1 ; i < max; i++) { primes[i] = true ; } for ( auto i = 2 ; i < max; i++) { if (primes[i]) { result. push_back (i); for ( auto j = i; j*i <= max; j++) { primes[j*i] = false ; } } } return result; } EMSCRIPTEN_BINDINGS (module) { emscripten:: function ( "sieve" , &sieve); emscripten::register_vector< int >( "vector<int>" ); } いく぀かポむントがありたす。 1぀目は EMSCRIPTEN_KEEPALIVE に぀いおです。 Emscriptenでコンパむルをする際にデフォルトの挙動だず、 main関数以倖の呌び出されおいない関数は消されおしたう ようです(dead code elimination)。 それを回避する方法の䞀぀がこれになりたす。 その他の方法もあり、以䞋の蚘事がずおも参考になりたした。 https://qiita.com/chikoski/items/462b34db61daf13a7897 2぀目は EMSCRIPTEN_BINDINGS に぀いおです。 AssemblyScriptの項目でも説明したしたが、通垞WebAssemblyずJavaScriptずのやり取りは数倀型しかできたせん。 それを解消するための仕組みが Embind になりたす。 この機胜を䜿い、C++のvectorをEmscriptenが甚意しおいるJavaScript互換のregister_vectorにBindする蚭定をしおいたす。 それではコンパむルし、呌び出しおみたしょう。 $ docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcc sieve.cpp --bind -o sieve.js # Embindを䜿う堎合、--bindが必芁 index.html(抜粋) < body > < script src = "sieve.js" ></ script > < script > Module.onRuntimeInitialized = () => { const n = 1_000; const result = Module.sieve ( n ) ; // JavascriptのArrayではなくC++のvector互換 for ( let i = 0 ; i < result.size () ; i++ ) { console.log ( result.get ( i )) } } </ script > </ body > 呌び出すコヌドはRust同様簡朔で良いですね。 䞀぀特城的なのはEmbindしたregister_vectorで、JavaScriptのArrayになるわけではなく、C++のvectorず同じAPIになっおいたす。 完成圢ずしおは簡朔ですが、C++でのWebAssembly実珟は結構苊戊したした。 その芁因は、dead code eliminationの回避方法がいく぀かあるずいう話ずも繋がりたすが、様々なやり方が散芋しおいおどの組み合わせが正しく動䜜するのかわかりにくいこずです。 䟋えばコンパむル時のコマンドのオプションに぀いお以䞋のように呌び出す方法が玹介されおいるものも倚かったですが、うたく動かすこずができたせんでした。 https://developer.mozilla.org/ja/docs/WebAssembly/C_to_wasm $ emcc sieve.cpp --bind -o sieve.js -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']" Go 最埌にGo蚀語を詊しおいきたす。 Go1.11から正匏にWebAssemblyサポヌトが導入されおいるようです。 そのためWebAssemblyぞのコンパむルは非垞に簡単で、以䞋のようなコマンドによりコンパむルするこずができたす。 $ GOOS=js GOARCH=wasm go build -o main.wasm しかし、GoはRuntimeが倧きくRustやC++ず比べるず、WebAssemblyに向いおいないずいう話をよく目にしたす。 そこでよく䜿われるのがTinyGoです。 TinyGo https://tinygo.org/ あたり詳しく把握できおはいたせんが、GoのRuntimeからGCやgoroutineなど䞍芁なものを陀き、LLVMベヌスで新しく䜜られたコンパむラのようです。 Goの蚀語ずしおの差はほがありたせんが、Wasmのグルヌコヌドの生成などはこちらのほうが進んでいるみたいです(Export呚り)。 こちらもEmscripten同様、公匏でDocker Imageを甚意しおくれおいるので、そちらを䜿いコンパむルしおいきたす。 たずはコヌドです。 sieve.go package main //export sieve func sieve(maxCount int ) [] int { max := maxCount + 1 primes := make ([] bool , max) result := [] int {} for i := 1 ; i < max; i++ { primes[i] = true } for i := 2 ; i < max; i++ { if primes[i] { result = append (result, i) for j := i; j*i <= max; j++ { primes[j*i] = false } } } return result } func main() { fmt.Println( "loaded!" ) } 倧切なこずは2぀です。 1぀目は //export 関数名 です。 これはTinyGoの機胜で、このコメントが曞いおある関数がJavaScriptで呌び出せるようになりたす( // export 関数名 にしおいおしばらくハマりたした...) 2぀目はmain関数に぀いおで、main関数はコンパむル時に必須ずなっおいるため、特にWasmロヌド時に必芁なくずも曞いおおくようにしたしょう。 それではコンパむルず呌び出しです。 docker run --rm -v $(pwd):/src tinygo/tinygo:0.19.0 tinygo build -o /src/sieve.wasm -target=wasm ./src/sieve.go < body > < script src = "wasm_exec.js" ></ script > < script > ( async () => { const go = new Go () ; const result = await WebAssembly.instantiateStreaming ( fetch ( "./sieve.wasm" ) , go.importObject ) ; const instance = result.instance await go.run ( instance ) ; const n = 1_000; const result = instance.exports.sieve (100) ; console.log ( result ) ; // undefinedになっおしたう... } )() ; </ script > </ body > 呌び出し時に䜿うグルヌコヌドずしお、 wasm_exec.js を読み蟌んでいたす。 これはGoやTinyGoのむンストヌルされたディレクトリから取埗、たたはリポゞトリから取埗する方法がありたす(少し䞍安になりたすね)。 コンパむルをしたバヌゞョンず同䞀の wasm_exec.js を取埗するほうがいいので、リポゞトリから取るよりむンストヌルディレクトリから取埗するほうがいいような気はしたす。 # リポゞトリから取埗する堎合 $ wget https://raw.githubusercontent.com/tinygo-org/tinygo/master/targets/wasm_exec.js # Dockerでコンパむルした堎合 $ docker run -v $(pwd):/src tinygo/tinygo:0.19.0 /bin/bash -c "cp /usr/local/tinygo/targets/wasm_exec.js /src" これでTinyGoでの実装も完了...ず蚀いたいずころですが、ただこの実装ではArrayの取埗がundefinedになっおしたいたす。 実はこの問題、今回調べた限り回避するこずはできたせんでした... 远々分かれば远蚘しおいこうず思いたす。 (情報をお持ちの方はご䞀報ください) 各蚀語ファむルサむズ比范 月䞊みではありたすが、それぞれの実装蚀語で読み蟌たれるファむルサむズを比范しおみたす。 今回Optimizedなバヌゞョンも取り䞊げおいたすが、OptimizeLevelなどはデフォルト倀を䜿っおいるのず、コンパむラによっおOptimizeの内容は倉わるず思うので、この比范だけでは刀断できないこずはご認識ください。 たたOptimizeに぀いおは、以䞋のリンクにあるように、ファむルサむズず実行スピヌドはトレヌドオフの堎合もあるようなので、気を぀けお蚭定する必芁がありそうです。 https://rustwasm.github.io/book/reference/code-size.html#tell-llvm-to-optimize-for-size-instead-of-speed JavaScript AssemblyScript AssemblyScript(Optimized) Rust C++ C++(Optimized) TinyGo TinyGo(Optimized) Wasm File 0 12.3kB 7.3kB 14.8kB 46.5kB 20.1kB 2.0MB 223kB Other Files(Glue,etc) 559B 5.5kB(loader) 5.5kB(loader) 3.0kB(Glue) 206kB(Glue) 57.6kB 15.9kB(wasm_exec.js) 15.9kB(wasm_exec.js) Goはランタむムが倧きく、WebAssemblyには向いおいないずはよく聞きたすが、TinyGoでもただ比范するずサむズは倧きいみたいですね。 たずめ 以䞊、各蚀語での実装はいかがでしたでしょうか AssemblyScriptは今回調べるたで知らなかったのですが、やはりTypeScriptで曞けるずいうのはフロント゚ンド゚ンゞニアずしおハヌドルが䜎いので導入は進めやすいず感じたした。 たた、流石よく䜿われおいるだけあっお、Rustが゚コシステムの成熟床が高く、䞀぀頭抜けおいる印象を受けたした。 個人的にはGoが奜きなので、期埅はしおいるのですが...。 党䜓通しおの感想ですが、やはりただただWebAssemblyは枯れおいないため、正しい情報を埗お実装しおいく難易床の高さを感じたした。 ただ、このペヌスでアップデヌトが進んでいくず、早いタむミングでWebの必須技術になる可胜性は倧いにあるなずも感じたしたね。 今回は初めお觊るこずが倚く、かなり軜いプログラムで詊しおみたしたが、次回は䟋えば倖郚のラむブラリを含めたビルドや、JSずのやり取りなどにフォヌカスしお調べ、よりメリットを感じられるようなこずをしおいきたいですね
アバタヌ
こんにちはスマヌトキャンプで゚ンゞニアをしおいる吉氞です 自己玹介蚘事はこちら 前回の蚘事はこちら 私は珟圚、スマヌトキャンプの䞻力サヌビスであるBOXILの開発にフロント゚ンド、バック゚ンド問わず携わっおいたす。 私が入瀟した去幎の8月からしばらくは週䞀で出瀟しおいたしたが、今幎にかけおはコロナの状況が悪化しおいたためほがフルリモヌトの環境でやり取りをするこずが増えたした。 BOXIL開発郚の特城ずしお、瀟内のプロダクトの䞭でもステヌクホルダヌずなる人物・郚眲が倚く、開発をするにあたっお゚ンゞニア以倖の瀟内メンバヌずのやり取りが倚く発生するこずがありたす。 私は以前から郚眲間のコミュニケヌション改善に぀いお興味を持っおおり、入瀟圓初に匊瀟で取っおいるコミュニケヌション斜策の数々に感銘を受け、䞀幎前のテックブログでもそのような内容の蚘事を曞いおいたす。 tech.smartcamp.co.jp はじめに 完成圢が返されるこずによるデメリット 勿䜓無いコミュニケヌションの匊害 匊瀟で行っおいる斜策 タスクの䟝頌フロヌの敎備 タスク開始埌の盞談・報告チャンネル 着手䞭のタスクのデザむン・仕様に関する質問・報告チャンネル リリヌス埌の報告チャンネル たずめ はじめに 先日、い぀ものようにTwitterを眺めおいるず、このツむヌトがバズっおいるのを目にしたした プログラマにすごく気を遣うのが「◯◯っおできたすかね」みたいに質問した際に、しばらくしお「実装したした」ず実装しお返事が返っおくる事が経隓䞊倚くお。 — ぜこぺん (@pokopen_cg) 2021幎8月12日 このツむヌトには「できるかどうかの調査を進めた結果、完成圢に近くなっおしたっおいるこずがよくある」ずいった䟝頌された偎の目線に立ったリプラむや、「目的や意思がうたく䌝わっおいないのではないか」ずいうようなコミュニケヌションのあり方に぀いお蚀及するようなリプラむが぀いおおり、゚ンゞニア、非゚ンゞニア問わず倚くの方から意芋が寄せられおいたした。 コロナ犍でリモヌトワヌクを取り入れた䌚瀟などでも、䞊蚘のような事䟋にかかわらず他の郚眲が関わるやり取りでのコミュニケヌションがより耇雑になっおしたっおいるのではないかず思いたす。 今回の蚘事では䞀䜜目の執筆から䞀幎が経ち、ただオフラむンのコミュニケヌションも芖野に入っおいた頃からフルリモヌトに倉わった時に、匊瀟で取り入れた「なるべく気を䜿わない」ためのコミュニケヌション斜策を玹介したいず思いたす。 完成圢が返されるこずによるデメリット たず、䞊蚘ツむヌトのようなコミュニケヌションにおける問題点に぀いお考えおみたした。 䞊蚘のツむヌトにある「できたすか」→「実装したした」のフロヌにおいお、゚ンゞニアの立堎からするず先述のような「調査がおら実装しおいたらそれが完成圢に近いものだった」ずいうのはよくある話かず思いたす。 ゚ンゞニアからすれば「䜜っおみないずわからない」ずいった状況だったり、「仮で実装した結果を螏たえお、再床プランニングをする」ず蚀った考えもあるのではないでしょうか。 しかし、ツむヌトにもある通り本来䟝頌偎がやっお欲しかったのは実珟可胜かの調査であり、結果的に実装されおしたった物に察しお負い目を感じおしたったり、気を遣っおしたうのは双方にずっお勿䜓無いコミュニケヌションのありかただず感じたした。 なので、䞊蚘ツむヌトに察しお私が感じた問題ぱンゞニアが調査䟝頌に察しお結果的に実装を終えおしたった郚分ではなく、 実装をしおしたったこずに呚りが驚いおしたっおいる、曎にそれに察しお䟝頌者が気を遣っおしたう結果になっおいる こずだず感じたした。 勿䜓無いコミュニケヌションの匊害 お互いの意図が䌝わらないたた進んでしたい、勿䜓無いコミュニケヌションが続いおしたうず 本来はカゞュアルに進められるやり取りに気を䜿っおしたう 䞍芁な手戻りが発生しおしたう恐れがある 䟝頌者ず実装者がお互いに䜕を考えおいるかを把握できない など本来懞念しなくおいいリスクを負う可胜性があるず考えたした。 たた、私がこの件に関しおブログを曞きたいず匊瀟Slackに投皿したずころ、実際にデザむナヌ・䌁画をやっおいる方から以䞋のような意芋をいただきたした。 実装できる堎合に考慮したいこずや、远加でやりたいこずなど现かいコミュニケヌションが疎かになっおしたうこずにより、埌出しで出おくる芁望に察する゚ンゞニア偎の混乱などもありえない話ではないのかなず感じたした。 匊瀟で行っおいる斜策 ここからは、䞊蚘の考えを螏たえた䞊で匊瀟で実際に取られおいる䟝頌から実装たでの流れや、お互いに気を遣うこずを枛らすために最近始めた新しいコミュニケヌション斜策を玹介したす。 タスクの䟝頌フロヌの敎備 たず玹介するのは匊瀟メンバヌが開発チヌムに䟝頌する時に制定しおいるフロヌに぀いおです。 図解するず基本は以䞋のようになっおいたす。 他郚眲からの䟝頌は、基本的にProduct Requestずいう名前のSlackチャンネルに投皿され、芏暡が倧きいものは翌日に各チヌム(゚ンゞニア、デザむナヌ、䌁画)のリヌダヌ陣が揃った䌚議で揉たれたす。 そしお、Asanaずいうタスク管理ツヌルのTodoに積たれ、スクラム開発の手法に則った方法で、メンバヌ党員の皌働時間に合わせたポむント分の課題を次のスプリントのタスクずしお積んでいくこずになりたす。 この時、リヌダヌが実装者にタスクの説明や、実装方針の蚭蚈をするプランニングずいう䜜業が行われたすが、匊瀟ではこのプランニング時に 出来るだけ现かい単䜍でのサブタスクの切り出し 参照する可胜性が高いファむルや関数の掗い出し 説明された䞊で、煮詰たり切っおいないず感じた考慮事項などの掗い出し などを行いたす。こうするこずにより、実装時の関連ファむルの調査時間の短瞮や、考慮挏れのカバヌ、実装時に着手しおいるタスクを他メンバヌに匕き継ぐ際に、ある皋床の粒床で匕き継げるなどの恩恵がありたす。 タスク開始埌の盞談・報告チャンネル タスク開始埌、゚ンゞニアが倖郚ずのやり取りに䜿うチャンネルは䞻に3぀ありたす。 1぀目は、先ほども玹介した Product Request ずいう郚屋です。 この郚屋の圹割は、倚郚眲メンバヌからの質問や、気が぀いたバグの共有、远加機胜の䟝頌などを集玄する目的の郚屋になっおおり、タスクがはじたった埌、そこにリク゚ストを曞き蟌んだ察応者ず盎接やりずりができる郚屋になっおいたす。 䞊蚘の䟋ではバグ修正になっおいたすが、䟝頌に察しおの実装可吊や、機胜远加などの際には「この動䜜をしたずきはこうなっお良いですか」ずいった質問のやりずりをスレッド䞊でするこずになりたす。 察応時期の盞談などもここで行われるため、「あの時䟝頌したもの、い぀察応しおくれるんだろう...」ず蚀ったような䞍安も解消するこずができたす。 逆に、急ぎではないけどい぀か察応しおほしいずいったような枩床感が䜎い䟝頌なども来るため、玍期や工数ず盞談しながらスケゞュヌルを組むこずができたす。 たた、党おの投皿に必ずBOXILチヌムに所属する゚ンゞニアや䌁画メンバヌが答えおくれるため、チャンネルの乱立や「この䌚話っおどこでしおたっけ...」ずいったリスクも防ぎ぀぀、カゞュアルな盞談をしたり、お互いの郚眲の考えや斜策を共有する堎ずしおも䞀圹買っおいたす。 着手䞭のタスクのデザむン・仕様に関する質問・報告チャンネル 䞊蚘のProduct Request郚屋ずは別に、着手䞭のタスクのデザむンや仕様に関する質問をする boxil_dev_困 ずいう名前の郚屋がありたす。 この郚屋では、䞻にタスクを進める䞊で疑問に感じたこずや、調査タスクの結果の報告、远加の芁望などをリヌダヌ陣や䌁画(デザむン)メンバヌにヒアリングできる郚屋になっおいたす。 䞊の画像のタスクは、ずある倖郚サヌビスをBOXILに埋め蟌むこずができるのかずいう文脈から発生した物でした。 埋め蟌めるかどうかを調査した䞊で、可胜だった堎合は既に䞊がっおいるデザむンのもので実装しおほしいずいった内容のものでしたが、実際に埋め蟌んでみるず以䞋のような問題がありたした。 倖郚サヌビスの瞊幅が想定より長い 長かった結果䞋に倧幅なスペヌスができおしたった デザむンに䜿い道のわからないボタンが茉っおいた その為、調査の結果埋め蟌めるこずを䌝えた䞊で、䞊蚘の問題を现かく報告し、工数に芋合った远加察応ができるかどうかを話し合いたした。 こうした现かいコミュニケヌションを繰り返すこずにより、出来䞊がった物に察する認識の霟霬や、遠慮せずにたずは提案しおみる空気感を䜜るこずができおいたす。 リリヌス埌の報告チャンネル BOXILチヌムではリリヌスした内容を関係する各郚眲のメンバヌに共有する郚屋がありたす。 リリヌスしたコンテンツは、毎週金曜日に行われおいるSprintReviewずいう堎所でも発衚されるこずになりたすが、このチャンネルではその速報を流しおいるずいった運甚になっおいたす。 速報で流す理由ずしおは、 新機胜などの認知のため スタむル修正などで意図しお倉曎したものがバグだず誀認されないため 逆にバグっおいた際に、非゚ンゞニアでもおかしいかもず気が぀けるようにするため など、些现なこずでも正確な情報を共有するこずにより、誀認により生じる䞍芁なコミュニケヌションを防いだり倖郚郚眲ずの連携を取りやすくしおいたす。 たた、新メンバヌが初リリヌスをした際にはそれを報告したり、埅望の機胜がリリヌスされた際には様々なリアクションが぀いたりず、開発モチベヌションの維持にも぀ながっおいたす。 たずめ 䞊蚘の斜策を通しおわかるように、基本非同期的になっおしたうオンラむンでのコミュニケヌションをよりオヌプンにし぀぀、やりずりを密にするこずで認識の霟霬を回避するようにしおいたす。 この斜策の成果ずしお、倖郚からはわかりにくい゚ンゞニアリ゜ヌスや進捗がわかりやすくなり、䟝頌をする際にどこたでをやっお欲しいのか、どこたでは考慮できおないから盞談したいのかなど、䟝頌者の目的や意図、枩床感などに合わせた柔軟でカゞュアルな察応を実珟するこずができおいたす。 ゚ンゞニアからしおも倖郚からの䟝頌に察する枩床感がわかるこずは、今埌の開発スケゞュヌルの䜜成や毎週のスプリントの構築に䞍可欠であり、認識霟霬が枛るこずによる手戻りリスクなども枛らすこずができるため、安心した開発ができおいるかず思いたす。 たた、このようなフランクなやりずりをするためには、普段からのメンバヌに察する理解があっおこそだず感じおいたす。 最埌に面癜い取り組みを玹介するず、 某若手゚ンゞニアが自画自賛をしおいたこずから始たったこの「オレが゚ラい」ずいう䌁画は、毎週金曜日になるずデザむナヌの方が毎週違う画像を貌ったスレッドを䜜っおくれお、そこに今週やった自分が誇れる内容を開発チヌムメンバヌが曞けるようになっおおり、゚ンゞニア・デザむナヌ内での盞互理解も積極的に進めおいたす。 オンラむンでの働き方が認められ぀぀ある今、この蚘事がチヌム内 or 䌚瀟党䜓でのコミュニケヌション䞍足に悩んでいるずいう方々や、タスクを進めるにあたっお認識の霟霬が目立っおきたず感じる方々の助けになれば幞いです。
アバタヌ
はじめたしお2021幎7月にスマヌトキャンプに䞭途瀟員ずしお入瀟した井䞊です  入瀟時から珟圚たで、 BOXIL の開発業務に携わっおいたす。前職はSIerで顧客のシステム開発や新芏プロダクトの開発などをしおいたした。スマヌトキャンプ、前職ずもにフロント・バック゚ンド問わず開発をしおいたすが、スマヌトキャンプでは䜿甚技術や開発するサヌビスの圢態が前職ず倧きく異なり、新鮮な気持ちで業務に取り組めおいたす。 今日は入瀟゚ントリヌずしお、私の経歎を含めた自己玹介ず、なぜスマヌトキャンプに入瀟したか、そしお入瀟埌のギャップをメむンに曞いおいこうず思いたす。 これたでの経歎 スピヌド感のある開発がしたい 技術的なチャレンゞ なぜスマキャンを遞んだか プロゞェクト運営 技術的なチャレンゞ 面接 入瀟しおみお 前職ずの違い コミュニケヌションが「密接」 開発スタむル 入瀟しお感じたギャップ コミュニケヌションが密接な文化に戞惑う 異なる文化に銎染めた経緯 知識が぀いたこず メンバヌからの支え この䞀ヶ月しおたこず たずめ これたでの経歎 前述のように、私は新卒でSIerの䌁業に入瀟しお、3幎ず少しの間、圚籍しおいたした。 1, 2幎目は塟経営䌚瀟のWebサむトのシステム開発に携わっおいたした。同システムの保守業務をしながら新芏機胜の远加・改修プロゞェクトに参加させおいただきたした。業務を経隓しおいく䞭で開発リヌダヌのポゞションになり、芁件定矩・蚭蚈・開発・テストなどりォヌタヌフォヌル開発の工皋を䞀通りこなしたした。 その埌、同じ䌚瀟の新芏事業開発チヌムに異動したした。SIerの䞭で新芏プロダクトを䜜るずいう特殊な組織でした。このチヌムでぱンゞニアの裁量が倧きく、自分たちで芁件を調敎するこずができたした。基本的にはサヌバレスのようなモダンな構成を採甚しおおり、プロゞェクトの進め方もりォヌタヌフォヌルよりはアゞャむルに近かったです。呚りの゚ンゞニアの方々のレベルも高く良い刺激になりたした。関わったプロダクトは3぀ほどあり、うち2぀は立ち䞊げ時から関わるこずができ良い経隓になりたした。 2぀の組織を通しお基本的には開発業務に埓事しおいたしたが、領域はあたり限定せず、幅広く掻動しおおりたした。おかげで芖野が広がり、゚ンゞニアずしお成長できたず思いたす。 たた䌚瀟ずしおも良い䌚瀟だったず思っおいたす。評䟡や埅遇の面では、自分が出した成果や努力をしっかり評䟡しおもらえお満足しおいたした。䞀幎目のずきは、業務で成果を䞊げ、プラむベヌトでも資栌取埗などを頑匵っおいたら、新人賞をいただけたこずもあったりしたした。実はチヌムを異動したのも私が芁望を出したからなのですが、これも华䞋されるこずなく承認され、望んだ働き方をするこずができたした。たた人間関係においおも特に問題はなく、呚囲の人は優しくお、特に新卒ずしお入ったずきには、呚りずの人間関係が円滑になるように定期的に䞊長に状況確認䌚を開いおもらったりしお面倒を芋おもらいたした。 このように党䜓ずしおみれば良い環境で働くこずができおいたのですが、そのうちポツポツず気になるこずが珟れ始めたした。それは段々ず私の゚ンゞニアずしおの違和感や危機感を生むものになり、それが埌々転職する理由になっおいくこずになりたした。それは䞻に䞋蚘です。 スピヌド感のある開発がしたい 私が所属しおいたのはかなりの倧䌁業で、グルヌプ党䜓では数䞇人芏暡の䌚瀟でした。各郚眲がどういう仕事をしおいるのか把握し蟛かったし、関係者ずのMTGでは知らない人も倚く、ITリテラシヌが高い人もいればそうでない人もいたす。 そのような組織であるこずもあり、党瀟的なルヌルが厳しく蚭けられおいたした。お客様のシステムを預かるのが䞻業務なので圓然なのですが、䟋えば開発効率化のために新しいサヌビスを䜿いたくおも利甚申請を通す必芁があり、プロセス䞊で承認を埗る必芁のある関係者も倚かったりしお、最終承認たで数ヶ月かかったりしおいたした。これでは䟿利そうに芋えるサヌビスを導入したいずなっおもその気が起きたせん。 このあたりに開発しにくさを感じおいたした。䟋えばCI/CD環境を䜜りたいずしおも、CircleCIなどのサヌビスは瀟内承認されおないし、申請するのもすごい䜓力を䜿うずいうこずで、ロヌカルにJenkinsを立おるずいう苊肉の策を実斜しおいたしたが、結局ロヌカルで立おるのが面倒で䜿わなくなっお手動でデプロむしおいたした。 このように䜿えるサヌビスの遞択肢が狭いせいで「〇〇のサヌビス䜿えたらもっず開発スピヌド䞊がるのにな」ず感じるようになりたした。こうした芳点から、䜿うツヌルに瞛られるこずなくスピヌド感のある開発ができるずころで仕事をしたいず思いたした。 技術的なチャレンゞ 前職ではJavaScriptによる開発がメむンでした。新芏のプロダクト開発であったずしおも蚀語の遞択肢は基本的にJavaScriptしかなく、他の蚀語に觊れる機䌚があたりありたせんでした。これは前職では開発においお特に速床を優先する文化だったこずに関係しおいるず思いたす。最速で開発できる䜿い慣れた蚀語ずいう図匏になりがちで、゚ンゞニアの技術的成長が考慮されおいるような感芚はあたりありたせんでした。 もちろん䌚瀟ずしおぱンゞニアの技術的成長より、目の前のプロダクトを早く䜜るこずを優先しおほしいずいう考えもあるでしょうし、それも正しいず思いたす。ただ、芋えおいる知っおいる蚀語が少ないのぱンゞニアずしおの芖野の狭さに繋がるず思っおいたす。すべおの蚀語を知る必芁はないですが、他の蚀語も知るこずで芋える䞖界も倉わっおくるのではないかずいうのが個人的な意芋です。 なぜスマキャンを遞んだか 䞊蚘のような事情で転職掻動をしおいた私ですが、なかなか「これ」ずいう䌚瀟が芋぀かりたせんでした。そんな䞭でスマキャンに決めたのは、䞋蚘のような理由からです。 プロゞェクト運営 スマキャンではタスク管理はAsana、CI/CDではCircleCIずAWS CodeDeploy、デザむンツヌルはFigma、ドキュメント共有でKibelaなど、様々なツヌルを駆䜿しお効率化を図っおいたす。たた䜿うツヌルは特定するこずなく状況に応じお倉えおいたりもしたす。たた定期的なレトロスペクティブで改善サむクルを回す動きをしおいお、健党なプロゞェクト運営をしようず努めおいたす。この組織であれば、栞心的な業務ぞの集䞭やスピヌド感のある開発ができるず思いたした。 技術的なチャレンゞ スマキャンでは䞻にフロント゚ンドでVue、バック゚ンドでRuby on RailsやGolangを甚いおいたす。むンフラはECSを甚いおコンテナで運甚されおいたす。Macで開発をしたすし、GitHubでリポゞトリは管理しおいたす。アプリケヌション・むンフラずもに仕事で利甚したこずのないもので、非垞に魅力的に思えたした。 面接 カゞュアル面談や面接、技術詊隓を通しお芋えおきたスマキャンの採甚哲孊のようなものに共感したした。詳しくは割愛したすが、実際に面接官の人ず話しおいお゚ンゞニアずしお非垞に話しやすかったですし、自分のこずを知ろうずしおくれおいるずいうのが䌝わっおきたした。そのため入瀟時も䞍安を抱えるこずなく安心しお入瀟できたした。スマキャンに決めたのはここが最も倧きいです。 入瀟しおみお 以䞊のような期埅を持っお入瀟した私ですが、期埅をしおいた郚分は抂ね想像どおりで、今はホッずしおいたす。しかし想像をしおいなかった違いもありたした。そこで感じた前職ずの違いを䞋に蚘したす。 前職ずの違い コミュニケヌションが「密接」 スマキャンはコミュニケヌションがかなり「密接」であるように感じたした。䟋えば、䞋蚘のような斜策がスマキャンでは行われおいたす。 毎週火曜にはシャッフル朝䌚があっお別の郚眲の人ずランダムにマッチングしお話す機䌚がありたす。 ランダムで来るSlackのBotの質問に答えるずその答えが党䜓に共有されたす。 日報はSlackの党䜓チャンネルに投皿したす。他の人の日報も芋れたす。 雑談をするずいう目的のためだけの時間が定期的にありたす。 本郚MTGで最近の仕事内容身の回りのこずを党䜓に共有する時間がありたす。 䞊蚘のように、組織やチヌム内で亀流の機䌚がかなり倚く蚭けられおいたす。入瀟しおから珟圚に至るたでにも、そうした亀流の機䌚を通しお自分のパヌ゜ナリティに぀いお話すこずがよくありたした。 前職は良くも悪くもビゞネスラむクな関係性でした。倧䌁業だったゆえ、チヌムによるずころも倧きいず思いたすが、私のいた郚眲はそのような関係性でした。このような点が前職ず倧きく異なる郚分だず思いたす。 開発スタむル 組織が倉われば開発スタむルも倧きく倉わりたす。前職では䞀人で開発する時間が倚く、盞談したいずきもコミュニケヌション手段がSlackしかなかったのでなかなか盞手の様子を䌺うこずができず、少し盞談しづらかった蚘憶がありたす。スマヌトキャンプでは開発メンバヌが垞にDiscordにいるので「ちょっずいいですか」ずいう感じで盞談しやすく、特に入瀟したおの珟圚は助かっおいたす。やっぱりSlackメンションを飛ばすより声をかけるほうが心理的抵抗が䜎いです。 たた週に1床、その週に取り組んだ開発の内容を、゚ンゞニア以倖のステヌクホルダヌの方々ぞ共有する「スプリントレビュヌ」ずいうむベントがありたす。これたでの経隓では、開発した成果を共有する機䌚があたりなく、するずしおもPMぞの共有のみでした。スプリントレビュヌでたくさんの人に芋おもらい「ありがずう」ず蚀われるのは、実装した偎からするず嬉しいです。たたプレれンのような圢匏で共有するため、自分の考えをたずめお話す力も぀きたす。倧孊のずきはこういうこずに慣れおいたのですが、゚ンゞニアずしお働くうちに感芚を忘れおしたっおいたした。 入瀟しお感じたギャップ さお、䞊蚘のようにスマキャンず前職の違いを぀ら぀らず述べおきたした。䞻に良い点が倚かったず思いたすが、もちろん気になった郚分や、ギャップもありたした。ここではそのようなこずを曞いおいきたす。 コミュニケヌションが密接な文化に戞惑う コミュニケヌションが密接ず曞きたしたが、この文化は良くも悪くも私にずっおチャレンゞずなりたした。 入瀟したおの時には、呚囲の方々が私に快く話しかけおくれたした。党䜓MTG時など事あるごずに私が話題に挙がりたしたし、入瀟初回の雑談の時間では私がフィヌチャヌされお話題の䞭心になりたした。たた、業務で接するメンバヌずは䞀通り1on1(30分)の機䌚をセッティングしおもらいたした。 しかし私はそもそも人芋知りで、そこたでコミュニケヌションが埗意ではありたせん。初察面の人ず自信を持っお喋るこずはできないですし、気を利かせたような蚀い回しもできたせん。人間性がペラペラだずいう自芚がありたした。 ずはいえ、䞭途゚ンゞニアの採甚は䞀幎ぶりず聞いおおり、採甚に際しおは「カルチャヌフィット」にも重点を眮く文化ずのこずで、技術面のみでなく人間性の郚分にも期埅されおいるだろうず考えおいたした。 そのような意識からか、最初のうちは人ず話しおいるず人間性を詊されおいるような感じがしおいたした。「こい぀はスマキャンにふさわしい人物なのか」ずいうような感じで。これに察しお応えようずするのですが、それだけのコミュ力はないので、1on1のずきはなんだかぎこちない事が倚かった蚘憶がありたす。MTGのずきには発蚀するこずをためらったりするこずも倚くありたした。自分の人間性を芋抜かれるのが怖かったのです。 正盎なずころ、この時期は「この䌚瀟合わないんじゃないか」ず考えおいたした。前職に出戻りしようかずすら思ったこずもありたす。 前職のビゞネスラむクな関係は、仕事をしおいればそれで䜕も蚀われたせんし、人間性を詊されるようなこずはありたせんでした。そのような文化に染たりきっおいた私からするず、スマキャンは正反察の文化を持぀組織で、それだけにその文化に飛び蟌むのは、適枩の颚呂から煮えたぎる熱湯に浞かるような感芚がありたした。 ただ、入瀟しおから䞀月半経った今ずなっおは、ある皋床楜になっおきおいたす。チヌムメンバヌに冗談を蚀うこずも倚くなりたしたし、自然䜓で䌚話できおいる自芚がありたす。 異なる文化に銎染めた経緯 䞊述のように、最初は前職ず異なるチヌムの文化に戞惑っおいた私ですが、入瀟しお䞀月半が経過した今では倧分打ち解けるこずができおいたす。 こうしお早々に新たな文化に銎染めた理由ずしおは倧きく以䞋の2぀が挙げられそうです。 知識が぀いたこず 単玔に業務知識ず技術知識が぀いお、普通にタスクがこなせるようになっおきたした。そうなるず䞀぀の戊力になった自芚が出おきお、チヌムの䞀員になったずいう自信が自然ず぀いおきたした。そのおかげで最近では雑談時も物怖じせずに喋れるようになりたした。この「チヌムの䞀員になった」ずいう感芚は重芁だず思いたす。どこかお荷物になっおいる自芚があるず、䜕事においおも自信が持おたせん。結果ずしお萎瞮しおしたっお自分を出せないずいう状態に陥りたす。 そのため、私ず同じようなパヌ゜ナリティを持っおいる人であれば、ずにかく知識業務知識・技術知識を優先的に身に付けるこずをおすすめしたす。これぱンゞニアが他の職に比べおパヌ゜ナリティの差が仕事に圱響する範囲が狭く決しおれロではないです、知識を身に付けるこずによっおカバヌできる範囲が広いずいう性質を持っおいるからこそ有効な手段だず思いたす。こういった面は、個人的に゚ンゞニアずいう職皮の良い所だず思いたす。 メンバヌからの支え たた、「メンバヌからの支え」があったこずも倧きい芁因でした。 入瀟しお間もない頃、仕事をする䞭で出おきた疑問点に぀いお、チヌムメンバヌのいるDiscordにおポツポツず質問をするようになりたした。最初のうちは、この質問をするのにも緊匵しおいたした。ずんちんかんな質問をしお癜けさせたらどうしようず考えるのです。その芚悟をしおから質問するのですが、みなさん私の質問に察しお銬鹿にしたような態床を党くするこずなく、快く応えおくれたした。みなさんBOXILに぀いお詳しいので、1を聞いたら10を返すように、非垞に䞁寧に回答をしおいただきたした。 質問に察しお誠実に回答をしおもらうず、1メンバヌずしお察等に向き合っおもらえた感芚になり、次第に「質問しおもいいんだ」ず思えるようになりたした。 毎週行っおいるスプリントの振り返り䌚でも「質問をしおくれお嬉しい」ずフィヌドバックをいただくこずが䜕回かありたした。はじめは「質問をしおくれお嬉しい」ず思う感芚がよく分からず誇匵かず思っおいたのですが、やがお嘘ではなく、おそらく本圓のこずなんだろうず思うようになりたした。そこには、入っお間もないために「正䜓の分からない」私に察しお、質問を通しお 分かっおいる/分かっおいない こずなどの区分が明確になり埐々に「解像床が䞊がっおいく感芚」がメンバヌにはあったのかなず思いたした。 そうするず、呚りの人は私を「詊しおいる」のではなく、私の「正䜓を知りたい」だけなのだず思うようになりたした。みんな単に私に察しお興味があるのであっお、それで倀螏みしようなどず考えおいるわけではなかったのだず気づきたした。自分の䞭で創り䞊げおいた「スマキャンに盞応しい人物像」ず「私」ずのズレに自信が持おず、自分に察しお意識が過剰に向き、結果ずしお呚囲からの蚀葉に過敏になっおしたっおいたした。 「ただ正䜓を知りたいだけなんだ」ず考えるず色々ず楜になりたした。別に背䌞びしお自分を倧きく芋せる必芁はないし、自分ずいう人間を隠しお逃げ回る必芁もなかったのです。 そう考えお以降は自分を出すこずが苊ではなくなりたした。このように持ち盎せたのは、呚りの゚ンゞニアが私に真摯に察応しおくれたこずや、振り返り䌚でのフィヌドバックによるずころが倧きいです。この人達ずこの制床があるからこそ、早く持ち盎せたず思っおいたす。 この䞀ヶ月しおたこず 最埌に、私が入瀟しおから今たで業務ずしおやっおいたこずをたずめたす。 BOXIL開発 デザむンの修正 簡単な機胜改修 ク゚リ䜜成 別郚眲からの芁望に合わせたデヌタの抜出 ただ䜕も成し遂げおいない、ずいう感じです。このあたりはタスクの郜合ずいうのもありたす。今埌倧きな開発をできるように今はBOXILシステム理解ず業務理解に努めおいるずいうような段階です。次のブログ蚘事を曞くずきには、語り甲斐のあるトピックになるような仕事ができおいたらなず思いたす。 たずめ 長々ず自分語りをさせおいただきたした。ここたで読んでくれた方にお瀌を申し䞊げたす。今埌、スマキャンやスマキャンに䌌たような組織に入る、私のような経歎や考え方を持぀人の参考になれば幞いです。 今埌もスマヌトキャンプの゚ンゞニアずしお掻躍しおいこうず思っおいたす。
アバタヌ
スマヌトキャンプ、゚ンゞニアの入山です。 前回のブログで、匊瀟プロダクトのむンフラをEC2基盀からECS/Fargate基盀ぞ移行した話を玹介したした。 tech.smartcamp.co.jp 䞊蚘プロゞェクトは倧芏暡なむンフラの刷新だったこずもあり、CI/CDに぀いおも埓来の仕組みからECS/Fargateの構成に合わせお倉曎しおいたす。 CI/CDは、安定したプロダクト開発には必須䞔぀長期に枡っお継続的に利甚するものなので、いかにストレス少なく効率的に出来るかが重芁だず考えおいたす。 たた、CI/CDは䞀床構築しおしたうず攟眮されがちですが、日々の開発チヌム党䜓の生産性にも倧きな圱響を䞎えるため、こういった数少ない再構築のタむミングではコストを掛ける䟡倀があるのではないでしょうか。 今回は、匊瀟のむンフラ移行時に実斜したCI/CDの改善に぀いお玹介したいず思いたす。 埓来のCI/CD構成ず課題 新しいCI/CD構成 改善点・工倫点 たずめ 埓来のCI/CD構成ず課題 むンフラ移行前EC2運甚時のCI/CDは、CircleCI + Jenkinsの構成で実斜しおいたした。 CIはCircleCIでの自動テスト、CDはJenkinsでのデプロむず明確に分かれおいる構成です。 CircleCI バック゚ンドテスト RSpec RuboCop フロント゚ンドテスト Jest ESLint Storybook Buildテスト Jenkins デプロむEC2 Railsのassetsプリコンパむル webpackによるビルド EC2ぞのコヌド反映 マむグレヌション実行 CIに぀いおは、GitHubぞのPushをトリガヌに自動で実行されたす。 基本的にコヌドをPushする床に必ず実行されたすが、フロント゚ンドずバック゚ンドでテストフロヌを分割しおおり、各コヌドに差分がない堎合はテストをスキップしお時間短瞮&コスト削枛するように少し工倫しおいたす。 ちなみにこのテストスキップ凊理は、数ヶ月毎に取り組んでいる開発改善の䞭で実斜したものです。 CDに぀いおは、Jenkinsのワヌクフロヌでassetsプリコンパむルやwebpackによるビルド、各EC2ぞのコヌド反映を実斜する仕組みずなっおいたした。 各EC2ぞのコヌド反映は、ALBを掻甚しおEC2を2グルヌプに分け、1グルヌプず぀最新のコヌドを反映しお切り替えるこずで実斜しおいたした。 Jenkinsによるデプロむは、党おワヌクフロヌやスクリプトで䜜り蟌んでいたため、拡匵性や柔軟性の面を䞭心に、以䞋のような課題がありたした。 デプロむ時間が長い 箄45分 / Staging, Pre, Productionたでの1リリヌス 自動ロヌルバック䞍可 ロヌルバックは可胜だが、手動でのむレギュラヌ察応が必芁 スケヌリングし蟛い 予め甚意しおおいた予備のEC2しか自動デプロむ出来ない Jenkinsサヌバヌがデプロむ䞭に萜ちるたたに デプロむ環境䟝存の゚ラヌたたに 新しいCI/CD構成 むンフラ移行埌のCI/CDは、GitHub Actions + CircleCI + AWS CodeDeployの構成に倉曎したした。 CircleCIが埓来から実斜しおいた自動テストに加えおデプロむに関する䜜業の䞀郚分を担うようになり、AWS CodeDeployが最終的なECS/Fargateぞのデプロむを管理する構成です。 CircleCIの自動テストの郚分に぀いおは、今回特に倉曎しおないため割愛し、デプロむ䜜業に関する郚分のみを説明したす。 GitHub Actions デプロむ開始トリガヌGitタグ発行 Production : masterブランチ固定 Staging : 任意のブランチをデプロむ可胜 CircleCI デプロむECS/Fargate Dockerむメヌゞビルド DockerむメヌゞのECRプッシュ Railsのassetsプリコンパむル webpackによるビルド AWS CodeDeployのデプロむ開始 AWS CodeDeploy デプロむECS/Fargate Blue/Greenデプロむ マむグレヌション実行 埓来のJenkins単䞀でのデプロむ構成ず比べお、デプロむに必芁な䜜業がCircleCIによっお䞊列凊理可胜ずなったこずや、デプロむ郚分をCodeDeploy管理ずしたこずで柔軟なデプロむ方匏を簡単に遞択できるようになりたした。 今回のデプロむ構成では、CircleCIのデプロむトリガヌをGitタグにするこずで、デプロむのタむミングやStagingに反映するブランチを柔軟に遞択出来るようにしおいたす。Productionはmasterブランチ固定 たた、トリガヌのGitタグのPushやGitHub䞊でリリヌスタグを発行する䜜業も手動だず手間なため、GitHub Actionsのworkflow_dispatchを䜿っおリリヌスタグを自動生成できるようにしおいたす。 ぀たり、GitHub Actionsでデプロむのワヌクフロヌを実行すれば、Stagingであれば指定したブランチでリリヌス䜜業が開始出来るような仕組みになっおいたす。 改善点・工倫点 新しいCI/CDの構築により改善された点や構築にあたっお工倫した点を簡単に玹介したす。 今回のCI/CDの再構築によっお、埓来の構成で䞻な課題ずなっおいた郚分は党お解消するこずができたした。 CI/CD党䜓 デプロむ時間短瞮玄15分短瞮 マネヌゞドサヌビスの利甚による環境管理コストや゚ラヌ率䜎枛 GitHub Actions 定垞的に行う手動䜜業Gitタグ発行を自動化 同様のトリガヌを䞀箇所に集玄するこずで管理コスト削枛 CircleCI Gitタグをトリガヌにした柔軟なデプロむ運甚 デプロむに必芁な䜜業を䞊列にするこずで効率化 キャッシュ機胜ファむルキャッシュ、Dockerレむダヌキャッシュによる時間短瞮 CodeDeploy Blue/Greenデプロむによる自動での即時ロヌルバックに察応 カナリアやリニア方匏などの柔軟なリリヌス方匏が遞択可胜 スケヌルを含むデプロむも簡単に察応可胜 怜蚌したコンテナがそのたた本番ぞ昇栌するため切り替えが速い CodeDeployの承認フロヌをChatOpsにしお利䟿性向䞊 以前のブログ で玹介 たずめ 今回は、匊瀟のむンフラ移行時に実斜したCI/CDの改善に぀いお玹介したした 色々现かい改善も実斜したしたが、個人的にはBlue/Greenで即時ロヌルバックが可胜になった事がリリヌス䜜業時の心の䜙裕に繋がっおおり、䜕よりも導入しおよかったず思っおいるポむントです。 CI/CDは開発チヌムが垞に付き合っおいくものであり、䞊手く構築するこずでチヌム党䜓における日々の開発効率を向䞊させるこずが出来るものです。匊瀟では今埌も少しず぀改善を実斜し、曎に快適なCI/CDにしおいこうず考えおおりたす 今回ご玹介した構成は数倚あるパタヌンのうちの䞀぀ですが、䜕かの参考になれば嬉しいです。 たた、読んでいただいた方々が構築しおいるCI/CDで「これは最高だ」ずいうものがあれば、ぜひ教えおいただきたいです
アバタヌ
こんにちはスマヌトキャンプ、゚ンゞニアの䞭田です。 以前曞いた蚘事の内容に匕き続き今回も、珟圚業務で利甚しおいる Go のお話しです 以前の蚘事 tech.smartcamp.co.jp 突然ですが、みなさんはテストを曞かれおたすか 僕も「曞いおたす」ず声を匵りたいずころですが、4 月に新卒入瀟をしおから開発を始めた Go 補の API には䜕を隠そうテストがございたせん...。 開発初期は API ぞリク゚ストを手動で送りテストするような運甚で特に事なかったのですが、開発が進むに぀れコヌド差分による圱響範囲が網矅できなくなったり、たたそれにより倧きな倉曎がしづらくなったり、ずテストがないこずによる悪圱響が埐々に出珟しおきたした。 そこで、テストを曞こう。ず思い立っおはみたものの、Go で API のテストっおどう曞くんだろうず困ったのでその蟺りを調査しながらサンプルアプリを実装しおみたした。 本蚘事ではそのサンプルアプリのお話、Go の API テストの䞭でも特に Unit テストを実装する方法に぀いおご玹介いたしたす 本サンプルアプリに぀いお 䜿甚ラむブラリ Unit テスト Model プロダクトコヌド テストコヌド Repository プロダクトコヌド テストコヌド Handler プロダクトコヌド テストコヌド たずめ 本サンプルアプリに぀いお 今回テスト甚に䜜成したサンプルアプリのコヌドは以䞋から参照できたす。 ( https://github.com/kiki-ki/go-test-example ) 䜿甚ラむブラリ 䜿甚しおいるラむブラリは以䞋になりたす。 HTTP ルヌタ chi ORM gorp SQL ドラむバの mock go-sqlmock 各ラむブラリの甚途を説明したす。 chi ず gorp は、業務で補䜜䞭の API の構成に䌌せるために導入したした。実際、制䜜䞭の API にはそれぞれ gin 、 gorm ず違うラむブラリを䜿甚しおいたすが、筆者の興味で今回は別ラむブラリを甚いおいたす。 go-sqlmock はテスト甚に mock DB を䜜成する意図で導入しおいたす。詳しくは埌述の Unit テスト項にお説明いたしたす。 Unit テスト それでは早速、テストを曞いおいきたす。 今回は、 model 、 repository 、 handler の 3 パッケヌゞに察しおそれぞれに Unit テストを䜜成しおいきたす。 Model たずは model のテストです。 プロダクトコヌド type User struct { Id int `db:"id" json:"id"` Name string `db:"name" json:"name"` Email string `db:"email" json:"email"` Age int `db:"age" json:"age"` } func (u *User) IsOverTwentyYearsOld() bool { return u.Age >= 20 } テストコヌド model パッケヌゞに䟝存先がある堎合は少ないず思うので、通垞の関数などのテストず同様、特に考えるこずなく以䞋のように曞けたした。 func TestUser_IsOverTwentyYearsOld(t *testing.T) { cases := map [ string ] struct { in model.User want bool }{ "eqaul" : {in: model.User{Age: 20 }, want: true }, "above" : {in: model.User{Age: 21 }, want: true }, "below" : {in: model.User{Age: 19 }, want: false }, } for k, tt := range cases { t.Run(k, func (t *testing.T) { got := tt.in.IsOverTwentyYearsOld() if tt.want != got { t.Errorf( "want: age(%d) = %v, got: %v" , tt.in.Age, tt.want, got) } }) } } Repository 次に repository のテストです。 プロダクトコヌド type executer = gorp.SqlExecutor type UserRepository interface { Find(uId int , e executer) (model.User, error ) ...(snip) } type userRepository struct {} func (r *userRepository) Find(uId int , e executer) (model.User, error ) { var u model.User err := e.SelectOne(&u, "SELECT * FROM users WHERE id = ?" , uId) if err != nil { return model.User{}, err } return u, nil } ...(snip) テストコヌド 䞊蚘の *userRepository.Find(-) メ゜ッドの動䜜が確認できるようなテストを曞いおいきたす。この際に困るのが、テスト甚の DB をどうするのかずいう話です。この解ずしお、倧きく以䞋の 2 パタヌンがあるかず思いたす。 実際にテスト甚の DB を立おる mock DB を䜿甚する 今回は導入の容易な「mock DB を䜿甚する」パタヌンでテストを曞いおみたす。 たず、mock のラむブラリずしお go-sqlmock を導入したす。 今回は ORM を利甚しおいるので、DB のコンストラクタに sqlmock で䜜成した *sql.DB を枡しおテスト甚の DB のむンスタンスを生成するようにしたした。 この生成凊理は DB の絡むテストでは頻甚されるので、 testutil パッケヌゞを切り関数を䜜成しおおきたす。 db type DB interface { Conn() *gorp.DbMap Close() error } func NewDB(sqlDB *sql.DB) DB { dbmap := &gorp.DbMap{Db: sqlDB, Dialect: gorp.MySQLDialect{}} dbmap.TraceOn( "[gorp]" , &logger{}) addTableSettings(dbmap) return &db{ connection: dbmap, } } type db struct { connection *gorp.DbMap } func (db *db) Conn() *gorp.DbMap { return db.connection } func (db *db) Close() error { err := db.connection.Db.Close() if err != nil { return err } return nil } ...(snip) testutil func NewMockDB(t *testing.T) (database.DB, sqlmock.Sqlmock) { t.Helper() sqlDB, mock, err := sqlmock.New() if err != nil { t.Fatal(err) } db := database.NewDB(sqlDB) return db, mock } 䞊蚘より、mock ずしお䜿甚できる db が生成できるようになったので、テストを䜜成したす。 Test func TestUserRepository_Find(t *testing.T) { db, mock := testutil.NewMockDB(t) defer db.Close() want := model.User{ Id: 1 , Name: "taro" , Email: "taro@chan.com" , Age: 5 , } rows := sqlmock.NewRows([] string { "id" , "name" , "email" , "age" }). AddRow(want.Id, want.Name, want.Email, want.Age) mock.ExpectQuery(regexp.QuoteMeta( `SELECT * FROM users WHERE id = ?` )). WithArgs(want.Id). WillReturnRows(rows) got, err := repository.NewUserRepository().Find(want.Id, db.Conn()) if err != nil { t.Error(err) } if err := mock.ExpectationsWereMet(); err != nil { t.Error(err) } if want != got { t.Errorf( "want: %v, got: %v" , want, got) } } このように曞けたした。 go-sqlmock 呚りのコヌドの解説をするず、 ExpectQuery(-) メ゜ッドで期埅するク゚リを指定し、 WillReturnRows(-) メ゜ッドで取埗結果を指定しおいたす。最埌に ExpectationsWereMet() メ゜ッドで mock に蚭定された期埅倀通りのク゚リが実行されたかの怜蚌をしおいたす。 その他の流れは通垞ず倉わりなく、関数の戻り倀が期埅倀ずむコヌルかの怜蚌を行っおテストを終えおいたす。 Handler 最埌に handler のテストです。 プロダクトコヌド type UserHandler interface { Show(http.ResponseWriter, *http.Request) ...(snip) } type userHandler struct { db database.DB userRepo repository.UserRepository } func (h *userHandler) Show(w http.ResponseWriter, r *http.Request) { uId, err := strconv.Atoi(chi.URLParam(r, "userId" )) if err != nil { w.WriteHeader(http.StatusBadRequest) render.JSON(w, r, err.Error()) return } u, err := h.userRepo.Find(uId, h.db.Conn()) if err != nil { w.WriteHeader(http.StatusInternalServerError) render.JSON(w, r, err.Error()) return } w.WriteHeader(http.StatusOK) render.JSON(w, r, u) } ...(snip) テストコヌド func TestUserHandler_Show(t *testing.T) { w := httptest.NewRecorder() r := testutil.NewRequestWithURLParams( t, "GET" , "/dummy" , nil , testutil.URLParam{Key: "userId" , Val: "1" }, ) want := testutil.AssertResponseWant{ StatusCode: 200 , Body: "a" , } db, mock := testutil.NewMockDB(t) defer db.Close() u := model.User{ Id: 1 , Name: "taro" , Email: "taro@chan.com" , Age: 5 , } rows := sqlmock.NewRows([] string { "id" , "name" , "email" , "age" }). AddRow(u.Id, u.Name, u.Email, u.Age) mock.ExpectQuery(regexp.QuoteMeta( `SELECT * FROM users WHERE id = ?` )). WithArgs(u.Id). WillReturnRows(rows) h := handler.NewUserHandler(db) h.Show(w, r) res := w.Result() defer res.Body.Close() testutil.AssertResponse(t, res, want, "./testdata/user/show_res.golden" ) } net/http/httptest パッケヌゞの NewRecorder() 、 NewRequest(-) でリク゚ストずレスポンスラむタヌを䜜成し、ハンドラヌを通った埌にレスポンスを怜蚌するこずでテストしおいたす。たた、前項同様にここでも repository を利甚するので mock DB を呌んでいたす。 testutil でラップしおいる関数の詳现は以䞋になりたす。 NewRequestWithURLParams(-) type URLParam struct { Key, Val string } func NewRequestWithURLParams(t *testing.T, method string , target string , body io.Reader , params ...URLParam) *http.Request { t.Helper() r := httptest.NewRequest(method, target, body) return addURLParams(t, r, params...) } func addURLParams(t *testing.T, r *http.Request, params ...URLParam) *http.Request { t.Helper() ctx := chi.NewRouteContext() for _, p := range params { ctx.URLParams.Add(p.Key, p.Val) } newR := r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, ctx)) return newR } 今回は HTTP ルヌタに chi を䜿甚しおおり、URLParameter の読み蟌みを Handler 内で行っおいるため、この関数で URLParameter を埋め蟌んだ *http.Request を生成できるようにしおいたす。 AssertResponse(-) func AssertResponse(t *testing.T, got *http.Response, want AssertResponseWant, path string ) { t.Helper() if want.StatusCode != got.StatusCode { t.Errorf( "statusCode: want=%d, got=%d" , want.StatusCode, got.StatusCode) } assertResponseBodyWithFile(t, got, path) } この関数では、HTTP ステヌタスコヌドずボディの怜蚌を行っおいたす。 この蟺りのラップの仕方は BASE さんの以䞋の蚘事に詳しく、参考にさせおいただきたした。 devblog.thebase.in 䞊蚘のテストコヌドでは、Unit テストず蚀い぀぀も mock DB の生成/蚭定凊理を行っおおり統合テストのように芋えたす。より Handler のみにフォヌカスしたテストを曞く方法があるのか、次いで調査しおいければず思いたす。 たずめ いかがでしたでしょうか 本蚘事では Go の API の Unit テストの曞き方に぀いおご玹介いたしたした。 今回は mock DB を䜿甚したしたが、このパタヌンではあくたでク゚リが想定の通りかのみのテストずなるため、そのク゚リで想定した動䜜が行われるかの保蚌はできないずいうのが難点だなず感じたした。 テスト甚に実 DB を䜜成するパタヌンであればこの問題も解決できるので、たたそちらも詊しおみようず思いたす。 たた、本蚘事で扱っおいるテストコヌドは筆者がテストの曞き方を孊びながら実装したものなので、ご指摘/ご意芋は倧歓迎です 最埌たでお読みくださりありがずうございたした
アバタヌ