TECH PLAY

Findy/ファインディ

Findy/ファインディ の技術ブログ

181

こんにちは!ファインディでTeam+開発チームのエンジニアメンバーの 西村 です。 この記事では、私が聞いたRubyKaigi 2024のセッション「Lightning Talks」より「Enjoy Creative Coding with Ruby」で紹介されたクリエイティブコーディングを試してみたので共有します。 クリエイティブコーディングとは クリエイティブコーディングとは、アプリケーションのような機能的なソフトウェアを作るのではなく、プログラミング言語を使ってビジュアルアートを創作することです。 クリエイティブコーディングをはじめるまでの背景 私は、RubyKaigi 2024の「Lightning Talks」より「Enjoy Creative Coding with Ruby」で、初めてクリエイティブコーディングについて知りました。 Miyuki Koshibaさんのスライド資料を引用させていただいています。 スライド内にある作例を見て、自分も創りたい!!と思う素敵LTでした!! speakerdeck.com DAY2の終わりに、クリエイティブコーディングを試しました。 すると、LTの内容通り、数行のコードでブラウザ上に図形を描画できたので、とてもワクワクしました! もう少し凝ったものを創りたいと思い、ファインディのロゴを創ることにしました。 セットアップ index.htmlに必要なスクリプトを読み込ませるだけで始めることができます。ローカルPCにRubyやほかのライブラリをインストールすることは不要です。 これをもとに、index.htmlを作成します。 github.com scriptタグには、次のライブラリを読み込ませる必要があります。 p5jsライブラリ ブラウザ上で円、四角や三角関数を使った図形等を描画できるようにするライブラリ p5rbライブラリ p5jsとRubyを橋渡ししてくれるライブラリ ruby.wasm ブラウザ上でRubyを実行できるライブラリ <script type="text/ruby"> タグ内に書いたRubyコードが実行され、 <main> タグ内に描画されます。 < html > < head > < script src = "https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@next/dist/browser.script.iife.js" ></ script > < script src = "https://cdn.jsdelivr.net/npm/p5@1.5.0/lib/p5.js" ></ script > < script type = "text/ruby" src = "p5.rb" ></ script > < script type = "text/ruby" > # ここにRubyで処理を書く </ script > </ head > < body > < main > </ main > </ body > </ html > 創ったもの ファインディのロゴをクリエイティブコーディングで描きました。 創作物は 外部公開 しています。 リポジトリは、こちら↓ github.com どう創ったのか ライブラリが対応している図形を組み合せることで、ファインディのロゴを創れそうだなぁと思いました。 ひとつずつ解説していきます。 まずは、外円部分を描画します。 def draw # 色設定 gray = color( 165 , 165 , 164 ) white = color( 255 , 255 , 255 ) blue = color( 26 , 90 , 164 ) background(white) # 輪郭を消す noStroke() # 外円 fill(gray) arc( 200 , 200 , 300 , 300 , radians( 0 ), radians( 360 ), PIE ) fill(blue) arc( 200 , 200 , 300 , 300 , radians( 130 ), radians( 300 ), PIE ) # くり抜き fill(white) circle( 200 , 200 , 210 ) end つづいて、外円部分の青い部分の端を鋭角にします。 外円とくり抜きの間に下のコードを追加します。 # 外円 ... fill(gray) arc( 284 , 115.5 , 150 , 90 , radians( 190 ), radians( 260 ), PIE ) fill(blue) arc( 96 , 270.3 , 150 , 90 , radians( -60 ), radians( 80 ), PIE ) # くり抜き つづいて、外円から横に伸びる青い部分を描画します。 ※ 青い部分はFindyのFを表しています。 このFの横棒が一番難しかったです。 複数の円を組み合わせて描画する必要があり、それぞれの図形の位置を調整することが大変でした。 # くり抜き ... # 外円から横に伸びる青い部分 fill(blue) rotate( -0.15 ) arc( 127 , 270 , 200 , 200 , radians( 200 ), radians( 290 ), PIE ) fill(white) arc( 127 , 270 , 132 , 132 , radians( 200 ), radians( 360 ), PIE ) arc( 190 , 231 , 125 , 125 , radians( 200 ), radians( 250 ), PIE ) 最後に、外円の右下に四角形を描画すれば、完成です!🎉 # 外円から横に伸びる青い部分 ... # 外円から伸びる四角形 fill(gray) translate(width / 1.25 , height / 1.25 ) rotate(radians( 55 )) rectMode( CENTER ) rect( -5 , 75 , 70 , 45 ) このように部品ごとにコーディングしていくと、簡単に創ることができます! デザインチェック 本物のロゴと並べて、デザイナーにチェックしてもらいましたが、Fの文字の形を中心にたくさん突っ込まれました。 いただいたフィールドバックの一例です! 「Fの2本の横棒の右端の角度がいまひとつ」 「外円から横に伸びる青い部分の描画が甘い」(画像を拡大しながら) 本物のファインディのロゴ クリエイティブコーディング作成ロゴ 自分のクリエイティブコーディングの技術力はまだまだなので、今後向上させていきたいです! 終わりに Xの#creativecoding を見ると、様々なクリエイティブコーディングが投稿されています。 気になる方は是非見てみてください。 また、少しでもクリエイティブコーディングに興味を持っていただけたら、嬉しいです! 5/28には「After RubyKaigi 2024〜メドピア、ZOZO、Findy〜」として、メドピア株式会社、株式会社ZOZO、ファインディ株式会社の3社でRubyKaigi 2024の振り返りを行います。 LTやパネルディスカッションなどコンテンツ盛りだくさんなのでぜひご参加ください!! findy.connpass.com ファインディでは、これからも新しいものを取り入れつつ、Rubyを積極的に活用して、Rubyとともに成長していければと考えております。 そして、一緒に働くメンバーを絶賛募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは、あるいはこんばんは。 @gessy0129 です。 沖縄、行ってきました! 観光、しませんでした! とても楽しかったです! 今回、ファインディブースでは、 Ruby歴×Ruby関連のカンファレンス参加回数は? というアンケートと 日替わりでRuby Code Quiz を実施しました! 全体的なブースの話はDevRelの まっきー がまとめているのでそちらをご覧ください! note.com 本記事では、エンジニアなら気になるであろうFindy Ruby Code Quizの解説をしていきたいと思います!では、早速見ていきましょう! 一日目 - Rubyバージョンの組み合わせ 問題 下記、実行結果のRubyバージョンの組み合わせを答えてください。 なお、ひとつのバージョンはひとつの選択肢にのみ回答できます。 Ruby versions: 3.3.0 or 3.2.0 or 3.1.0 or 3.0.0 ① irb> Time .new( " 2024-05-15T11:11:11Z " ) => 2024 - 05 - 15 11 : 11 : 11 UTC ② irb> Time .new( " 2024-05-15T11:11:11Z " ) => 2024 - 01 - 01 00 : 00 : 00 + 0000 ③ irb> Time .new( " 2024-05-15T11:11:11Z " ) <internal :timev >: 310:in ` initialize': invalid value for Integer(): "2024-05-15T11:11:11Z" (ArgumentError) ④ irb> Time .new( " 2024-05-15 " ) <internal :timev >: 409:in ` initialize': no time information (ArgumentError) 選択肢 ①: 3.2.0、②: 3.0.0、③: 3.1.0、④: 3.3.0 ①: 3.3.0、②: 3.2.0、③: 3.1.0、④: 3.0.0 ①: 3.1.0、②: 3.0.0、③: 3.2.0、④: 3.3.0 ①: 3.0.0、②: 3.1.0、③: 3.3.0、④: 3.2.0 正解と回答率 正解 ✅ 1. ①: 3.2.0、②: 3.0.0、③: 3.1.0、④: 3.3.0 回答率 14.15% 53.77% 19.81% 12.26% 解説 RubyのバージョンアップのNEWSを追いかけていれば解けるという問題です。 Ruby3.3.0のNEWS https://github.com/ruby/ruby/blob/v3_3_0/NEWS.md Time.new('2023-12-20') # no time information (ArgumentError) これを知っていたら④が3.3.0だとわかります。 Ruby3.2.0のNEWS https://github.com/ruby/ruby/blob/v3_2_0/NEWS.md Time.new now can parse a string like generated by Time#inspect and return a Time instance based on the given argument. Time.newはinspectが出力するstringからパースできるようになった。これで、①は3.2.0以上とわかります。 Ruby3.1.0のNEWS https://github.com/ruby/ruby/blob/v3_1_0/NEWS.md At the same time, time component strings are converted to integers more strictly now. Time.new(2021, 12, 25, "+07:30") #=> invalid value for Integer(): "+07:30" (ArgumentError) Ruby 3.0 or earlier returned probably unexpected result 2021-12-25 07:00:00, not 2021-12-25 07:30:00 nor 2021-12-25 00:00:00 +07:30. そもそも3.1.0までは文字列だけをいれるユースケースはなかったようです。3.0.0以前は文字列だけだとよくわからない挙動になっていたけど、この対応でチェックを厳密にしたことで文字列だけだとエラーになったのではないかと推測します。変更意図などはCommiterの方々に解説求めたい部分です。 ただ、このNEWSの内容を全てを記憶してるのは難しすぎになってしまうので、回答の選択肢を4択にしています。4択なので3.3.0の挙動を知っていたら1番目と3番目の2択に絞れると思います。 これに加えて、3.2.0の挙動を知っていたら①は3.2.0以上とわかるので1番目が答えだとわかります。また、3.2.0の挙動を知らなかったとしても、①〜③は全く同じコマンドを実行しており①が正しく挙動しているので①の方が新しいバージョンだと推測できます。これでも1番目が答えだとわかるようになってます。 二日目 - 代入されているオブジェクトはどれ? 問題 fooに代入されているオブジェクトは次のうちどれでしょうか? (Ruby: 3.3.0で実行した場合) irb(main): 001 > foo = ?? ? irb(main): 002 > foo.include?( 3 / 2 ) => true irb(main): 003 > (foo + [ 3 ]).inject( :+ ) => 9 irb(main): 004 > foo.last => NoMethodError 選択肢 1..3 [1, 2, 3] Set.new([1, 2, 3]) Enumerator.new { |y| [1, 2, 3].each { |i| y << i } } 正解と回答率 正解 ✅ 4. Enumerator.new { |y| [1, 2, 3].each { |i| y << i } } 回答率 25.37% 4.88% 39.02% 30.73% 解説 メソッドに対しての出力結果から元の値を当てる という問題形式を使ってみたかった問題です。 そこから逆算して、ちょっと似ているクラス(Range, Array, Set, Enumerator)を当てるようにしてみました。 irb(main):002 の出力は引っ掛けで、3/2 => 1になるのですべてtrueになる。 が、直感的には3/2 => 1.5という考えを利用して、1..3では?と思わせて問題を難しくしました。 irb(main):003 は、同じ値は重複しないというSetの特徴を利用から、Setを除外できるようになっている。また、Rangeには+メソッドがないのでエラーになる。 irb(main):004 は、Setには順番がなく、Enumeratorは外部イテレータなので最後の要素が特定できないという特徴を利用している。 実行結果を見るのが一番早いですね。 選択肢1 irb(main): 001 > foo = 1 .. 3 => 1 .. 3 irb(main): 002 > foo.include?( 3 / 2 ) => true irb(main): 003 > (foo + [ 3 ]).inject( :+ ) (irb): 3:in ` <main>': undefined method ` + ' for an instance of Range (NoMethodError) irb(main):004> foo.last => 3 Rangeには+メソッドがないのでNoMethodErrorになるのと、lastメソッドがあるので結果が返ってきます。 選択肢2 irb(main): 001 > foo = [ 1 , 2 , 3 ] => [ 1 , 2 , 3 ] irb(main): 002 > foo.include?( 3 / 2 ) => true irb(main): 003 > (foo + [ 3 ]).inject( :+ ) => 9 irb(main): 004 > foo.last => 3 lastメソッドがあるので結果が返ってきます。 選択肢3 irb(main): 001 > foo = Set .new([ 1 , 2 , 3 ]) => #<Set: {1, 2, 3}> irb(main): 002 > foo.include?( 3 / 2 ) => true irb(main): 003 > (foo + [ 3 ]).inject( :+ ) => 6 irb(main): 004 > foo.last (irb): 4:in ` <main>': undefined method ` last ' for an instance of Set (NoMethodError) 同じ値は重複しないというSetの特徴から 003 の結果が6になります。 選択肢4 irb(main): 001 > foo = Enumerator .new { |y| [ 1 , 2 , 3 ].each { |i| y << i } } => #<Enumerator: ...> irb(main): 002 > foo.include?( 3 / 2 ) => true irb(main): 003 > (foo + [ 3 ]).inject( :+ ) => 9 irb(main): 004 > foo.last (irb): 4:in ` <main>': undefined method ` last ' for an instance of Enumerator (NoMethodError) 正解ですね!! 有識者の方に解説モトム Setには順番がない と書きましたが、firstはあります。なので、こうなります。 irb(main): 001 > foo = Set .new([ 1 , 2 , 3 ]) => #<Set: {1, 2, 3}> irb(main): 002 > foo.first => 1 なんでfirstがあるのか、詳しい方のコメントを待っています。Enumerableを継承しているからと言われたらそれまでと言えばそれまでですがw 三日目 - 正しい出力結果は? 問題 次のコードを実行した出力結果で正しいのはどれでしょう? (文字コード UTF-8、Ruby: 3.3.0で実行した場合) hoge = [ ?1 , ?2 ].zip([ ?3 , ?4 ], [ ?5 , ?6 ]).transpose.flatten hoge.reject! hoge = hoge.map{|n| n.ord}.sort puts hoge.join( " , " ) 選択肢 1, 2, 3, 4, 5, 6 6, 5, 4, 3, 2, 1 49, 50, 51, 52, 53, 54 54, 53, 52, 51, 50, 49 正解と回答率 正解 ✅ 3. 49, 50, 51, 52, 53, 54 回答率 17.19% 14.06% 60.94% 7.81%  解説 問題文のコードを読みにくくするため、わざとインデントやスペースを入れていない。というちょっとイジワルをしました。 [Integer, Integer]に対して、なにかしら変換するのはひっかけるポイントが少ないので、String→Integerへ変換するようにして、複雑さを増すようにしています。 # zipメソッドを使う人はあまりいなそうなので、採用 > hoge = [?1,?2].zip([?3,?4],[?5,?6]) => [["1", "3", "5"], ["2", "4", "6"]] # ノーマルなRubyistは2次元配列を扱うことが少ないはずなので、transposeメソッドを採用 irb(main):003> hoge = hoge.transpose => [["1", "2"], ["3", "4"], ["5", "6"]] # Rubyistはflattenを結構使っている気がする。ここは配列を入れ子にしたくないから、採用 irb(main):004> hoge = hoge.flatten => ["1", "2", "3", "4", "5", "6"] # なにかやっていそうだけど、Enumeratorに変えているだけ irb(main):006> hoge = hoge.reject! => #<Enumerator: ...> # ordメソッドが、StringからIntegerへ変換することを知っているかチェック # sortメソッドが降順 or 昇順どちらで並び替えているか試す irb(main):007> hoge = hoge.map{|n|n.ord}.sort => [49, 50, 51, 52, 53, 54] irb(main):008> puts hoge.join(", ") 49, 50, 51, 52, 53, 54 さいごに 4/1 からクイズ作成を開始して、約4日ほどでほぼほぼ今の形まで出来上がりました。ラフで色んな案を出して、煮詰めていく過程がとても楽しかった(らしい)です。 また、 knuさんがブースに遊びに来てくれてPostしてくれていたのがとても嬉しかったです!来ていただいてありがとうございました! Findyさんの問題良問ですね! 自分がSetとEnumeratorとirbセッション4行目の登場人物すべての作者なのに、足し算を勘違いして誤答してしまったw #RubyKaigi pic.twitter.com/qkXyemZZkn — Akinori Musha (@knu) 2024年5月16日 問題は @hamchance0215 、 @aiandrox 、 @sontixyou が作成してくれました!ありがとうございました! 5/28には「After RubyKaigi 2024〜メドピア、ZOZO、Findy〜」として、メドピア株式会社、株式会社ZOZO、ファインディ株式会社の3社でRubyKaigi 2024の振り返りを行います。 LTやパネルディスカッションなどコンテンツ盛りだくさんなのでぜひご参加ください!! findy.connpass.com ファインディでは、これからもRubyを積極的に活用して、Rubyとともに成長していければと考えております。 そして、一緒に働くメンバーを絶賛募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは!ファインディでTeam+開発チームのEMをしている 浜田 です。 以前公開した記事「ファインディはRubyKaigi 2024 にPlatinum Sponsorsとして協賛します!」で紹介した通り、ファインディはRubyKaigi 2024に協賛しており、現地で参加してきました! tech.findy.co.jp 今週(5/20〜25)はRubyKaigi 2024の振り返りも兼ねてRubyKaigiに関連した記事を投稿していきます! この記事では、私が聞いたセッションの中の1つ「 Unlocking Potential of Property Based Testing with Ractor 」で紹介されたGem「 PBT 」を試してみたので共有します。 Unlocking Potential of Property Based Testing with Ractor 「 Unlocking Potential of Property Based Testing with Ractor 」は、Property Based TestingをRubyで実行するためのGemを作成し、さらにRactorを活用することでテストパフォーマンスを向上させる話でした。 speakerdeck.com セッションの中でも触れられていましたが、Property Based Testingを聞いたことがある方は20%ほどとのことだったので、この記事でも簡単に紹介したいと思います。 Property Based Testingでは、従来の入力値を開発者が列挙してテストする手法(セッションではExample Based Testingと呼んでいました)とは異なり、入力値の性質(プロパティー)を指定してテストケースを自動生成して網羅的なテストを行うことができます。 私は以前ファインディ主催で開催した「 t-wadaさん、ymotongpooさんに聞くテスト戦略最前線 」というイベントでt-wadaさんから紹介されて興味を持ちました。 スライドも公開されているので、興味がある方はぜひご覧ください。 speakerdeck.com この記事では、Gem「PBT」を使ってProperty Based TestingをRubyで実装しつつ、従来のテスト手法であるExample Based Testingとの違いを比較します。 試してみた それでは早速試していきます。 今回使用したRubyと主要なGemのバージョンは次の通りです。 Ruby 3.3.1 PBT 0.4.1 RSpec 3.13.0 今回は入力値を3倍にして返却する triple というメソッドを実装します。単純にするため入力値は整数のみ考慮します。 class PropertyBasedTest def self . triple (value) # valueを3倍にして返す end end それではまずいつも通り入力値を開発者が列挙してテストするExample Based Testingでテストを書きます。なお、テストはRSpecを使用します。 triple のテストを書く場合、皆さんはどのような入力値のパターンでテストを書きますか? 今回は、正の整数 / 負の整数 / 0 の3パターンのテストケースを書きました。 Example Based Testingの場合、開発者がテスト条件を満たす任意の値を選んでテストコードを書くため、適当に選んだ 22 / -5 / 0 を指定しました。 RSpec .describe PropertyBasedTest do describe ' .triple ' do context ' when example-based testing ' do subject( :add ) { described_class.triple(number) } context ' when input value is 22 ' do let( :number ) { 22 } it { is_expected.to eq 66 } end context ' when input value is -5 ' do let( :number ) { -5 } it { is_expected.to eq( -15 ) } end context ' when input value is 0 ' do let( :number ) { 0 } it { is_expected.to eq 0 } end end end end 実行結果は次の通り。無事テストが通りました🙌 PropertyBasedTest .triple when example-based testing when input value is 0 is expected to eq 0 when input value is 22 is expected to eq 66 when input value is -5 is expected to eq -15 Finished in 0.1124 seconds (files took 4.22 seconds to load) 3 examples, 0 failures ところが、 triple メソッドには未知のバグが埋め込まれていました。 3の倍数、もしくは3のつく入力値が与えられた場合は異常終了するというバグです。 今回のテストではたまたま3の倍数や3がつく数値をテストケースに含めていなかったため、このバグを見逃してしまいました。 このような見逃しを回避するための手法として、Property Based Testingが有効です。 Property Based Testingは、入力値の性質(プロパティー)を指定してテストケースを自動生成し、網羅的なテストを行うことができます。 では、PBTを使ってテストを書いてみましょう。 テストコードを見ていただければわかる通り入力値の具体的な値は指定しておらず、整数であること( Pbt.integer )のみを指定しています。 RSpec .describe PropertyBasedTest do describe ' .triple ' do context ' when property-based testing ' do it do Pbt .assert( verbose : true ) do # 入力値が整数であることを指定 Pbt .property( Pbt .integer) do |number| result = described_class.triple(number) # 結果が3の倍数であることを確認 expect(result).to eq number * 3 end end end end end end 実行結果は次の通り。正しくエラーが検出されました。 Randomized with seed 19396 PropertyBasedTest .triple when property-based testing example at ./spec/models/property_based_test_spec.rb:42 (FAILED - 1) Failures: 1) PropertyBasedTest.triple when property-based testing Failure/Error: Pbt.assert(verbose: true) do Pbt.property(Pbt.integer) do |number| result = described_class.triple(number) expect(result).to eq number * 3 end end Pbt::PropertyFailure: Property failed after 5 test(s) seed: 113103392077172016306707556593348939592 counterexample: 3 Shrunk 8 time(s) Got RuntimeError: (´Д`) サンッ!! app/models/property_based_test.rb:5:in `triple' spec/models/property_based_test_spec.rb:45:in `block (6 levels) in <top (required)>' (長いので省略) Encountered failures were: - 614700 - 307350 - 153675 - 76838 - 38419 - 4803 - 301 - 38 - 3 Execution summary: . √ -929894 . √ 440110 . √ -801140 . √ -194044 . × 614700 . . × 307350 . . . × 153675 . . . . × 76838 . . . . . × 38419 . . . . . . √ 19210 . . . . . . √ 9605 . . . . . . × 4803 . . . . . . . √ 2402 . . . . . . . √ 1201 . . . . . . . √ 601 . . . . . . . × 301 . . . . . . . . √ 151 . . . . . . . . √ 76 . . . . . . . . × 38 . . . . . . . . . √ 19 . . . . . . . . . √ 10 . . . . . . . . . √ 5 . . . . . . . . . × 3 . . . . . . . . . . √ 2 . . . . . . . . . . √ 1 . . . . . . . . . . √ 0 # ./spec/models/property_based_test_spec.rb:43:in `block (4 levels) in <top (required)>' Finished in 0.08717 seconds (files took 4.23 seconds to load) 1 example, 1 failure PBTではデフォルトで100通りのテストを実行します。 Property failed after 5 test(s) と表示されているので、5回目のテストでエラーが発生したとわかります。 counterexample にはエラーが発生した入力値のうちShrunkして発見した最小の値が表示されています。今回は 3 が入力された場合にエラーが発生したことがわかります。 また、 Shrunk 8 time(s) とのことなので、8回Shrunkして最小の値 3 を見つけたことがわかります。 無事バグが検出できたので、コードを修正して再度テストを実行します。 今回は無事テストが通りました🎉 PropertyBasedTest .triple when property-based testing example at ./spec/models/property_based_test_spec.rb: 42 Finished in 0.09535 seconds (files took 4.28 seconds to load ) 1 example, 0 failures このようにProperty Based Testingを活用することで、開発者に依存した入力値ではなく、網羅的なテストを行うことができるため、開発者が予見できていないバグを見つけやすくなります。 今回のサンプルコードは単純な処理なのでテスト実行時間にほとんど差がありませんが、通常はPBTの方が試行回数が多くなるためテスト実行時間は長くなります。そのため、様々なインプットのパターンを網羅すべきテストケースなど適材適所で活用いきたいと思います! 5/28には「After RubyKaigi 2024〜メドピア、ZOZO、Findy〜」として、メドピア株式会社、株式会社ZOZO、ファインディ株式会社の3社でRubyKaigi 2024の振り返りを行います。 LTやパネルディスカッションなどコンテンツ盛りだくさんなのでぜひご参加ください!! findy.connpass.com ファインディでは、これからもRubyを積極的に活用して、Rubyとともに成長していければと考えております。 そして、一緒に働くメンバーを絶賛募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは。 FindyのFreelance開発チームの久木田です。 今回は 自慢の作業環境を大公開 のPart3になります。 前回までの記事はこちら ↓ 👉 自慢の作業環境を大公開シリーズ Part3は関西特集ということで、大阪と京都からフルリモートでJOINしているエンジニアたちの作業環境を公開します! 作業環境を大公開 久木田 まずは大阪から JOIN している久木田の作業環境から紹介していきます。 作業環境の全体像はこんな感じになっています。 ディスプレイ3台PC2台おいても広々スペース 会社支給の MacBook Pro 14インチ をノート用スタンドに載せて使っています。 ディスプレイはノートPCのディスプレイを含めて4枚使っていて、左からブラウジング用・コーディング用・Slack用・Datadog等の監視ツールのダッシュボード閲覧用として使っています。 このデスクですが、工務店を営む父親に頼んで、一緒に手伝いつつ、天板の木材から切り出して、取り付けてもらったものになります。 音声環境周りですが、自分は Anker PowerConf S3 というスピーカーフォンを使っています。 スピーカーフォン:Anker PowerConf S3 マイクも色々試しましたが、途中で耳を塞ぐのが個人的に好きじゃなかったのに気がついてから、このスピーカーフォンを愛用しています。 ミュートボタンが Zoom と Google Meet のミュートと連動してくれているのもお気に入りポイントです。 ちなみにカメラは MacBook のカメラの方が、市販されている廉価なWebカメラより性能が良いと思っているので、そのまま使っています。 キーボードは HHKB Professional2 を使っていて、トラックボールは Kensington スリムブレードトラックボール を使っています。 HHKBのUS配列が好みです ボールを横回転させてするスクロールが慣れると快適 キーボードは大学院生の頃からHHKBが好きで(当時は廉価版のHHKB Lite2 for Macでしたが)、この画像のキーボードは社会人になった7年前くらいからずっと使っているものです。 トラックボールは前職の上司の方からお下がりとしてもらって以来、このKensingtonのスリムブレードを使っていて、今使っているものは2代目になります。 トラックボールも親指タイプのものなど色々試した結果、このデバイスに落ち着きました。 広い画面を移動するのに、トラックボールはおすすめです。 そして使っている椅子もこだわっているものの1つになりまして、ハーマンミラーの エンボディゲーミングチェア を使っています。 背面の青いデザインも気に入っています 大阪に ハーマンミラーストア心斎橋 があり、そこへ行って色々な椅子を試した結果、この椅子を選びました。 背もたれが背骨のカーブにフィットしているので体重重めの自分も快適に座れています。 後ろにデスクトップPCが見えていますが、これは私用のPCで左のディスプレイの入力切替をして使っています。 ディスプレイの奥にあるのが自分でパーツを取り寄せて組み立てたPC 前回や前々回の作業環境紹介では私用と仕事用でデバイス共用している人が多かったですが、自分はmacとwindowsでOSが違っていたり、トラックボールだとゲームがやりづらかったりするので、手元のデバイスも全く別のものを用意して使っています。 最後に机の角に飾っている好きなものごちゃまぜディスプレイを写して自分の作業環境紹介は終わります。 攻殻機動隊・ウマ娘・ガンダム・にじさんじ 金丸 次に京都から JOIN している金丸の作業環境を紹介します。 作業環境の全体はこのようになっています。 ディスプレイとノートPCを最小限のスペースで設置しています 会社支給の MacBook Pro 14インチ をノートPC用アームに載せて使っています。 デスクの幅が120cmのためノートPCを宙に浮かせることでスペースを節約しています。 デスクには COFOの昇降デスク を利用し、定期的に立ち上がって作業をするようにしています。 天板の裏がマグネットになっているため、マグネットフックで雑に収納できるところが気に入っています。 ディスプレイは HP社の曲面ディスプレイ を利用しています。 ディスプレイに設置したライトで常に明るい WQHD、USBハブ機能、USB-C(USB PD) に対応しているため、給電 + USB ケーブル1本で出来るところが気に入っています。 ウルトラワイドなディスプレイですが曲面になっているため違和感なく使えています。 スピーカーにはクラウドファンディングで購入した ovo を利用しています。 マットな金色がデスクに映えます コンパクトな本体でも音割れが少なく、気に入っています。 通話には eMeet Luna を利用しています。 有線/Bluetooth切替可能で取り回し◎ 本体にノイズキャンセリング機能がついているため、タイピング音などが軽減されるところが気に入っています。 キーボードは分割キーボードの 7sPro を利用しています。 レトロっぽいキーキャップが好み 「HHKBの配列で分割キーボードを使いたい」という要望を満たしているキーボードで、キースイッチを変えながら3年くらい使っています。 ホットスワップに対応しているのでキースイッチの変更が出来るところもお気に入りポイントです。 現在は alpacaスイッチ をセットして利用しています。 マウスは MX MASTER 3S を利用しています。 勢いよく動かしてもカーソルがブレない点がお気に入りです トラックパッド、トラックボールと試してみたのですが、結局マウスに戻ってきて以来、このマウスを利用しています。 最後に推しを詰め込んだディスプレイを紹介して、作業環境紹介を終わります。 カニさん・ガブモン・幽遊白書・ズートピア 西村 最後に、京都からフルリモートで Findyの転職サービス を開発している西村の作業環境を紹介します。 妻と同じ部屋でリモートワークをしているため、机を向かい合わせるように設置しています。奥に見えるのが妻側のデスクです。 あまり広くない部屋なので、作業スペースもコンパクトです ディスプレイは DELL U2720QM を使用しています。4K 27インチのディスプレイなので、これ1つでも十分に作業が可能です。 MacBook Pro 16 をスタンドに載せて、デュアルディスプレイとしています。MacBook は主に Slack 専用としています。 こだわりポイントとしては、目線を下げないためにディスプレイをスタンドの上に置いていることです。 猫背気味で首や肩に負担を掛けがちなので、それを軽減できないかなと考えてこのようにしています。 また、ディスプレイと正対するように座ることも意識しています。 リモートワークを始めた初期に、目線を左右どちらかに寄せ続けて首や腰の片側だけが痛くなってしまった。という苦い経験から、このような工夫をしています。 ただ、少し目が疲れやすく感じるので、本来であればもう少しディスプレイとの距離を取りたいと考えています。 しかし部屋の広さの関係で、これ以上奥行きのあるデスクを置くことができないので、この状態で我慢しています。 キーボードは Keychron K2 を使用しています。 Keychron K2 のキーボードと木製のパームレスト 元々は HHKB を使ってみたいなと思っていたのですが、値段が高くてなかなか手が出せていなかったところに前職時代の先輩に勧められて購入しました。 比較的安価だったので試しに使ってみたところ、とても打ちやすく非常に気に入っています。かれこれ3年以上経ちました。 マウスは Apple の Magic Trackpad を使っています。マウスに対するこだわりはなく、友人からプレゼントしてもらったものをずっと使い続けています。 また、手首から先の負担を減らす目的で、 FILCO のパームレスト を使っています。肌に優しそうという理由で木製のものを選びました。 今回はデスクの写真を撮るタイミングだったのでかなりスッキリとしています。Findyでは社内輪読会も行っており、業務時間中にもチームで同じ書籍を読みエンジニアのレベルアップを図っています。日常的には、その輪読会用の書籍が置いてあったりすぐに読み返したりできるようにしています。 購入して1年ほど経ってから成長の兆しが見え始めたお気に入りのサボテン まとめ いかがでしたでしょうか? やはり、キーボードにはそれぞれこだわりがありましたね! また、今回の記事を通して意外にもスピーカーマイクを使っているのが自分だけではないことに驚きました。 自分の環境でも記載しましたが、マイクの物理スイッチはおすすめなので是非試してみてください! 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは、ファインディ株式会社でフロントエンドのリードをしております 新福( @puku0x )です。 この記事では、転職サービス Findy の開発チームにおける開発生産性の向上に対する取り組みをご紹介します。 以前の状況 モノリスの解体 開発基盤の刷新 コンポーネント設計の刷新 テストの拡充 CI の高速化 改善の効果 まとめ 以前の状況 2020年頃の Findy は Ruby on Rails と React のモノリス構成で作られていました。 機能の増加に従いコードが複雑化し、しだいに開発スピードが伸び悩むようになりました。 ここで Findy Team+ で算出した当時のリードタイムを見てみましょう。 2020年のFindyのリードタイム 上記のグラフから次のことがわかります。 改修が本番に適用されるまで 約1週間 かかる プルリクエストがレビューされるまで 約5日 放置される プルリクエストのレビュー完了までに 約2日と半日 かかる 1年を通してプルリクエスト数の平均が2.0を超える日が無かったことからも苦しい状況であったことが推測できます。 モノリスの解体 前述の通り Findy は Rails モノリスで作られており、CI にフロントエンドとバックエンドの両方が含まれていることから、画面の文言を1つ更新するだけでも長い CI 待ちが発生します。 この状況を打破するために、Findy で最初に行われた取り組みは「Rails モノリスの解体」でした。 約3ヵ月かけてバックエンド側を Rails の API モード、フロントエンド側を Next.js で再実装するという大掛かりなプロジェクトでしたが、これによりフロントエンドとバックエンドで独立して動けるようになったため、先述した CI 待ちを大幅に短縮できました。 実際の効果は note の記事 にて弊社 CTO が紹介しておりますので、そちらも是非ご一読ください。軽微な改修であれば1日で修正するスピードを実現し、最速でユーザーに価値を届ける基盤を作ったのがモノリス解体の大きな効果と言えるでしょう。 開発基盤の刷新 2021年5月、モノリス解体後のフロントエンドが晴れてリリースされました。大きな不具合もなく無事に終わったと安心したいところですが、まだ残っている課題を解決しなければなりません。 フロントエンド側に残された課題は次の通りです。 バージョンの古いツール・ライブラリが多数 コンポーネントの書き方が古い 型(Flow)はあるがうまく動作していない テストが書かれていない 見通しの悪いフロントエンド設計 最初に、依存ライブラリのアップデートや使われなくなったライブラリを削除していきました。また、Dependabot を導入し定期的に更新する体制を整えました。 次に Nx を導入し、モダンな開発環境へ移行していきました。Nx は前職で利用した経験があり、コマンドひとつで TypeScript + React + Jest + ESLint + Prettier が揃った開発環境を作成できるため移行は短期間で済みました。ここで導入した Nx は、後の CI 高速化への布石となります。 Findy には開発当初から React が用いられておりましたが、この時はまだコンポーネントが Class Component で書かれてありました。今後の React エコシステムの発展に追従するべく Function Component への書き換えも同時に進めました。 Flow から TypeScript への移行は直接書き換えるのが難しかったため、一度全てのソースコードから Flow の型アノテーションを外して純粋な JavaScript にし、その後 TypeScript で書き直しました。移行の早い段階で strict: true で書くようにしたため、Null チェック漏れによる不具合を大幅に削減できたと思います。 当時は API レスポンスに対しても手作業で型付けを行っていましたが、API の仕様が複雑であったりドキュメントと同期するのが難しかったことから、後に REST API から GraphQL に移行し、 GraphQL Code Generator による型生成が採用されるようになります。 コンポーネント設計の刷新 当時の実装では、コンポーネントは Container Component / Presentational Component のパターンで書かれてありました。メンバーの習熟度やテストのしやすさを考慮し、基本設計は踏襲しつつ、下記に示すようなデータの流入元に着目した三層構造へと拡張しました。 コンポーネント名 カスタムフック名 扱うデータ Page Component Params Hook ブラウザURL Container Component Facade Hook API や ストレージ等 Presentational Component Presenter Hook フォーム 各層での責務が明確になったことで実装時の混乱が少なくなったと思います。 余談ですが本設計は筆者が Angular コミュニティから得られた知見を React アプリケーションに転用したものとなります。不思議な縁もあるものですね。 *1 テストの拡充 プロジェクト進行中にいくつかの不具合に遭遇することがありましたが、それらのほとんどはテストがあれば防げたものでした。将来的な変更に耐えられるよう、テストの拡充は早期に着手しました。幸いバックエンド側では既に「テストを書くのは当たり前」という文化が根付いていたため、フロントエンドのテスト導入のハードルは高くありませんでした。 当時はまだメンバー全員がフロントエンドのテストに慣れている訳ではなかったため、テストのお手本となるような実装例を増やしていくことから始めました。まず、ユーティリティ等の入出力の関係が明らかなものからユニットテストを書き、次にコンポーネントのスナップショットテスト、それからインタラクションテストや結合テストといったように範囲を広げていきました。 また、テストを書くモチベーションを向上させる工夫として Wallaby.js のような可視化ツールを導入しました。Wallaby.js については次の記事もご参照ください。 tech.findy.co.jp 今では全員が当たり前のようにフロントエンドのテストを書くようになりました。テストによって守られているという安心感もさることながら、テストを書くことが習慣化したことによって「テストを書きやすいように設計が洗練される」といった副次的な効果が得られたのも嬉しいところでした。 CI の高速化 コードベースが増え、ビルドやテストの実行時間が増えていくと、CIの待ち時間も長くなっていきます。CI 時間の増加はリードタイムの増加に直結するため、改善は必須でした。 開発基盤を刷新するにあたり、CI 時間の増加は予め想定されていたため Nx を導入し、 nx affected コマンドによる変更検知によって必要なジョブのみ実行することで CI の高速化を図りました。ジョブの再実行といった変更検知だけでは高速化が難しいものに対しては Nx Cloud を導入し、リモートキャッシュを活用した高速化を実施しました。 結果は次の通りです。CI 時間は平均6分で、キャッシュヒットしない場合は16〜17分かかることもありますが、早い時は2〜3分で終わるようになりました。 ジョブ単位の詳細を次の図に示します。 Nx Cloudによる高速化の内訳 Nx Cloud 導入により300時間以上の CI 時間を削減できました。ここではフロントエンド側のCI高速化を取り上げましたが、バックエンド側の取り組みも記事にされておりますので、ご興味のある方は是非ご一読ください。 tech.findy.co.jp 改善の効果 それでは、モノリス解体をはじめとした様々な取り組みの成果を見ていきましょう。次の図は2023年における転職サービスの Findy のフロントエンドとバックエンドそれぞれのリードタイムを計測した結果を示しています。 フロントエンド バックエンド リードタイムが100時間を超えていた状況から大幅な改善ができました。特にフロントエンドに関してはマージまでの時間が8時間を切っていることから、高速な開発を実践できていると言えます。 フロントエンドのアクティビティの変化についても見ていきましょう。モノリス解体が実施された2021年と比較すると、近年のアクティビティ量は著しく増加しています。 2021年 2023年 もちろんこれはメンバーの増加が主な要因として考えられますが(採用チームの皆さんいつもありがとうございます)、それだけでなく、一人あたりのアクティビティが増えた(=一人あたりのパフォーマンスが向上した)ことも結果に貢献していると思います。 2021年(1人あたり) 2023年(1人あたり) 2021年当時の倍のアクティビティを示しているので、単純計算で開発生産性も倍になっていると言えますね!頑張った甲斐がありました 💪 まとめ ファインディでは「モノリスの解体」「開発基盤の刷新」「CI の高速化」を実施し、開発生産性を向上させることに成功しました。 数年前まではファインディも開発スピードに伸び悩んでいたと知って驚いた方も多いかもしれません。ここ数年で大きく成長できたのは社内の優秀なメンバーの協力あってのものだと感謝しています。 ここまでご覧いただいた方は、 ファインディはそこまで特別なことをやっている訳ではない とお気付きになられたかと思います。 1つ1つの積み重ねが今の私達の開発を支えています。 日々の改善を大事にしていきましょう。 ファインディは積極的にエンジニアを採用しています。CI/CD を始め、Four Keys、開発生産性、技術トレンド、転職市場など興味のある方は、お気軽にカジュアル面談を受けてみてください。 ファインディの採用情報はこちら ↓ herp.careers *1 : https://dev.to/puku0x/angular-react-2h4j
アバター
こんにちは、あるいはこんばんは。 @gessy0129 です。 ファインディは昨年に続き RubyKaigi 2024 でPlatinum Sponsorsとして協賛します。RubyKaigi 2018からここまで継続して協賛できているのは、様々な御縁のおかげだと感じています。Rubyコミュニティおよびファインディを応援してくださる方には感謝の気持ちでいっぱいです。 Platinum Sponsorsとして実施すること 今年のファインディは、ブース出展とDrinkupを2件実施させて頂く予定です。 Drinkupはconnpass上にオープンさせて頂いています。 findy.connpass.com findy.connpass.com ほぼほぼ埋まってしまいましたが、ぜひご参加頂けると嬉しいです! ブースには、Findy Team+の開発リーダーである @ham0215 をはじめ、 @yuichiro826 、CTOの @ma3tk やVPoEの @kxmxyx が参加します。僕もいる予定ですので、ぜひ遊びに来てください! ブースはこちらです! ブース内容の全貌については、現在、最終の内容をFixさせるための作業を実施中です。ご期待頂ければ幸いです! 一部、公開させて頂きますと、Ruby Code Quizというクイズを用意しております。開催期間中は内容が毎日変わるので、ぜひ毎日挑戦しにきてください! 前年からの振り返り 昨年のRubyKaigiから早一年が経過しました。この間のファインディの変化を、一年前と比較しながらご紹介します。主にRubyに関係することをメインにピックアップさせて頂きました。 プロダクト開発状況変化 Findy Team+ を使って、弊社がRubyで開発している主要バックエンドリポジトリの確認をしました。 2023年4月と2024年4月の対比です。 直感的に分かりやすく増加してますよね! グラフだけだと分かりにくいかもしれないので、具体的な数字で表現させて頂きます。 コミット数: 1.49 倍 PR数: 1.56 倍 コミット人数: 1.34 倍 オープンからマージまでの平均時間: 13% 削減 人数が増えると開発時間が長くなったり指標が悪化することもあるのかな?と思いながら見ていたら主要スタッツが軒並み向上していて正直言って驚きました。 普段はこういうグルーピングで見ることがないのでなかなかに新鮮な図です。 Ruby biz Grand prix 2023 ソーシャルインパクト受賞 rubybiz.jp RubyKaigi 2023の参加をきっかけにRuby bizにも応募させて頂きまして、ソーシャルインパクト賞を受賞することが出来ました。本当にありがとうございます。 今回のRubyKaigiにも参加予定の @ham0215 からのRubyに関する熱いコメントもあり、これから先、Rubyへの貢献をより一層強めていきたいと考える事が出来ました。 この度はソーシャルインパクト賞をいただくことができ、誠に光栄に思います。エンジニア組織の開発パフォーマンス向上を支援するSaaS「Findy Team+」が、日本発の「Ruby biz Grand prix 2023」で受賞をできましたこと、大変喜ばしい限りです。当社では、今回受賞した「Findy Team+」だけではなく、多くのプロダクトでRubyが使われており、Rubyコミュニティや「Ruby on Rails」をはじめとした多くのライブラリなどのおかげでユーザーへ爆速で価値を届けることができております。今後も「Ruby」への恩返しの意味も込めて、Rubyを活用したサービス開発やエンジニア向けのイベントや事例記事の公開などを行い、Rubyコミュニティの発展に寄与してまいります。 ( エンジニア組織支援SaaS「Findy Team+」が「Ruby biz Grand prix 2023」でソーシャルインパクト賞を受賞 | ファインディ株式会社のプレスリリース の受賞コメントから引用) Rubyを使用した新しいプロダクトFindy Toolsがリリース Findy Tools は数ヶ月でプロダクトリリースができ、現在も着実に成長中のサービスです。プロダクトとしては未成熟な部分もありますので、皆様からのフィードバックも数多くお聞きしながらプロダクトに反映していきたいと考えています。ブースなどでぜひお聞かせ頂ければ幸いです! Findy Toolsに関する具体的な内容はテックブログに記載をさせて頂いたのでそちらもぜひご参照ください! tech.findy.co.jp いかがでしたか?ファインディのこの一年の歩みをダイジェストでお届けしました。 ファインディ社は引き続きRubyとともに成長していければと考えております。 そして、一緒に働くメンバーを絶賛募集中です。 興味がある方はこちらから ↓ herp.careers おまけ ファインディは4月29日にオフィス移転をしました!移転後のオフィスの会議室にもRubyがあります!Rubyでファインディ株式会社が大きくなったこともあり、会議室サイズは比較的大きめです!
アバター
こんにちは、2024/3/18 からファインディに入社した本田です。 ファインディでは、Findy Team+ という、エンジニア組織の開発生産性を可視化し、開発チームやエンジニアリングメンバーのパフォーマンスを最大化するためのサービスの開発に携わっています。 今回は、入社して一ヶ月ちょっとが経ったので、入社して新メンバーとしていいなと思ったことをご紹介したいと思います。 オンボーディングがわかりやすい 入社すると初めにオンボーディング用 Issue が作成、アサインされていて、いつまでにどういうことができるようになっているために何をしてくのか、というのが一通りまとまっていて、すごいわかりやすかったです。 オンボーディング用 Issue には、次のようなことが記載されています。 新メンバーがキャッチアップすべき事項の一覧 環境構築手順や必要なツールのセットアップ手順、設定項目など コーディング規約やその元となる思想 携わる各リポジトリの役割や、各アプリケーションのアーキテクチャ 各種定期ミーティングの一覧やその内容 いつ頃までにどういう業務ができるようになっているかの期待の目安 メンバーの経験、スキル、やっていきたいことなどを鑑みてマネージャーと個別にすり合わせもしている こんな感じにオンボーディングのゴールと期間が定義されていて、 この後にこれらのゴールに向けて知るべきことやそのための資料が記載されている感じです。 初日からこの Issue を見つつメンターの方と密にコミュニケーションを取りながら環境構築や携わるプロダクトの理解をスピード感持ってキャッチアップできました。 個別に知るべきことを逐次教えてもらうのではなく、全体として何を知ってどういう状態になるべきかがわかると、必要に応じて能動的に情報をキャッチアップする動きもでき、非常にやりやすく感じました。 good first issue からコードで貢献できる 急ぎでない簡易かつ新しく参画した人向けの Issue を good first issue というラベルを付けて管理していて、新メンバーはまず good first issue から着手して、開発の流れや携わるプロダクトのコードベースを理解、習得していきます。私もこの流れで開発を始めました。 各 good first issue の Description は新メンバーでも理解できるようちゃんと書かれていて、前述のオンボーディング Issue で紹介されているドキュメントも読みつつ理解しながら Issue を対応していきます。 実際私も他のオンボーディングプログラムを受けつつ3週間ほど good first issue を対応していきましたが、15営業日で 34 PR を出してコードで貢献できました。 他のオンボーディングプログラムもあって波はありますが平均して3PR/日くらいできています もちろんオンボーディング期間はしっかりインプットすることが大切ではありますが、それもやりつつ入社してすぐに何かしら貢献できることは自信にも繋がりましたし、いいバランスでインプットとアウトプットを両立できました。 レビューがすごく速い めちゃくちゃ速いです。 PR のレビュアーをアサインしてだいたい 10 分以内、遅くても 1-2時間以内にレビューされます。 もちろんレビュアーの方の状況にもよりますが、体感7-8割くらいの PR は 10 分くらいでレビューされる印象です。 レビュアー一人当たり4件/日、平均しても1h以内にレビューされてます これにはいくつかの要因がありますが、一番大きいのはバッチサイズを小さくしてリードタイムを短くすることで手戻りやコンフリクトを防ぐ、ということが文化として根付いていることが大きいと感じています。 そのために、 PR の粒度を極力小さくする レビュアーは極力優先してレビューする といったことが徹底されています。 なお、ここらへんの話は先日開催された Qiita Conference での弊社CTO佐藤の発表で詳しく触れていますので、ご興味ある方はぜひご一読ください。 speakerdeck.com まとめ 他にもご紹介したいことはたくさんありますが、今回は特に新メンバーにとっての開発者体験について3つピックアップして紹介させていただきました。 入社して1ヶ月経過しての感想としては、ファインディは開発スピードを大切にする組織文化が根付いているなと思いました。 より良いプロダクトを作ってより多くのユーザーに良いプロダクトを提供するためにも、開発スピードはその源泉になるものだと思っています。 それをエンジニアとして各々が理解して体現している組織なので、私にとって新しい挑戦ができる環境だと感じています。 このスピード感を自分も体現し、プロダクトの成長と自分の成長を重ねながら良いプロダクトを作っていきたいです。 ファインディでは一緒に働くメンバーを絶賛募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは。 FindyのTeam+を開発している西村( sontixyou )です。 【エンジニアの日常】エンジニア達の自慢の作業環境を大公開 Part1 と題して、公開したブログが好評でした。 それに続いて、弊社エンジニア達の作業環境を見ていきましょう! 作業環境を大公開 西村 私は、現在週3日ほど出社と残りはリモートワークしています。そんな私の作業環境をご紹介します。 デスクの全体像はこのような感じです。 デスクは新卒時代の先輩からおさがりです。幅120cmのものを使用しています。 ディスプレイはDELLの27インチ 4Kモニタを2枚使っています。1枚だけ縦置きにしている理由は、省スペース化と首の振り向きが大変だからです。 横置きのディスプレイでは、エディタとSlack専用になっています。 縦置きのディスプレイでは、ブラウザ専用になっています。ウィンドウを垂直に2枚置いて活用しています。 ディスプレイはエルゴトロンのアームで支えています。ディスプレイの縦置きを実現するために欠かせないアイテムです。また、ディスプレイの台座があると場所を取るためです。 Webカメラは10年前に買ったlogicoolのものを使用しています。マイクが内蔵されているため、外付けマイクは用意していません。そろそろ買い替えしたいので、乗り換え先を探し中です。 USBハブには、 サンワサプライのUSBハブ を使用しています。このハブは、HDMI(4k/60Hz対応)1本とUSB3.0 2本とUSB Type-Cの充電ケーブルを指すことができます。 キーボードは keychronのK6 Pro を使用しています。 キースイッチは Keychron Silent K Pro Switch を使っています。打鍵感がとても良いため、自宅用とオフィス用で2台購入してしまいました。 マウスは、 logicool ERGO M575S を使用しています。 手首を動かさせずに、カーソル移動ができます。そのため、手首の疲れは全然ありません。また、ボールを取り外すことができるため、マウス内部の清掃やボール交換が楽々です。 自分が好きなものをデスクに置くことで、仕事終わりまでモチベーションをキープしつつ仕事ができます。 まずは、フィギュアです。私は 海洋堂 制作のフィギュアが好きなため、ガチャポンで当てた怪獣ネロンガと恐竜を置いています。縦に長いものはミイラ展で当てた猫のミイラを題材にしたフィギュアです。 デスク横には、PS5を置いています。仕事終わった瞬間に、ゲームプレイできるためとても快適です。 仕事を快適かつ集中できる場所になるように意識して、デスク環境を整えています。 浜田 次は浜田( ham )の作業環境を紹介します。 コロナ禍のときにリモートワークを始め、コツコツリモート環境を整えました。 私のポリシーは「日々使うものは良いものを!」なので、予算の許す範囲で妥協せずに自分が良いと感じるものを選ぶようにしています。 ディスプレイは2枚ないと開発効率がガタ落ちするタイプのエンジニアなのでデュアルディスプレイです。 右側は4Kで31.5インチ、左側は27インチです。 4Kディスプレイは、ブラウザやZoomやGoogle Meetなどを表示しています。 27インチディスプレイは、Slackやメール、エディターなど文章を扱うツールを表示しています。 4Kディスプレイはメーカーなどにこだわりはないのですが、USB Type-Cで出力とPC本体への給電ができるものを選びました。ケーブルが少ないのは正義!! また、こちらのディスプレイは足が大きかったのでモニターアームを使っています。 デスクスペースを拡げるためにモニターアームを買ったのですが、モニターの角度を簡単に変えられるため、モニターの背面の配線を変えたり、モニター周りの掃除もしやすくなり地味にストレスだったことも解消されました。 27インチディスプレイは解像度などのスペックは劣りますが、文章を書く場合に4K解像度だと文字が小さくて使いづらいので、必要十分なスペックだと感じています。 リモートワークにおいてオンライン会議は生命線です。こちらの画質や音質が悪い場合は相手にストレスを与えてしまう可能性があります。 そのため、 Webカメラ / マイク は良いものを選ぶように心がけました。 また、自室では前からの光が当たらず、顔が暗く見えていたためライトも買いました。見た目の印象も大事です。 椅子は Ergohuman PRO2 Ottoman を使用しています。足を伸ばせるようにオットマンがついているものにしましたが、全然使わないので不要でしたw なお、足置きと一緒に使うことで椅子の高さ調整がやりやすくなるので、足置きとセットで使うことがお勧めです。 冒頭に書いた「日々使うものは良いものを!」のキーボードから始まりました。 REALFORCE から始まり、HHKB Professional(手元にないので写真なし)、 HHKB Professional Hybrid Type-S 、そして今は HHKB Studio を使っています。 また、分割キーボードを使っていたこともありました。 Corne Cherry V3 はキーが少ない代わりにレイアーを活用するのですが、使いこなせず挫折しました・・・ HHKBライクな 7sPro は、気に入っていたのですがキーの反応が鈍いことが多々ありストレスを感じたのでHHKBに戻りました。 髙橋 週に2日程度リモートしている髙橋( @nokv )です。 オフィス勤務が主体のため自宅はシンプルな環境にしています。 デスクの全体像はこんな感じです。 200cm程度の大きいデスクを妻と半分ずつ使っています。 妻はリモートワークが多いため、MTGが被った際はどちらかが移動しないといけないなど不便なこともありますが、作業の合間に会話がしやすくリフレッシュできるので1つのデスクにして良かったと感じています。 自分の作業環境はMacBook Proと外部ディスプレイを縦並びに配置したシンプルなデュアルディスプレイ構成で作業しています。 以前はもう1枚ディスプレイがあり横に配置していましたが、首や目に負荷がかかると感じたため現在の構成にしました。 外部ディスプレイは DELLの27インチの4Kモニタ を使っていて、PCへの給電もケーブル1つで可能な点がお気に入りです。 エディタやGitHubなど閲覧頻度の高いものは外部ディスプレイに表示し、首への負荷を軽減するため視点がなるべく下がらないようにしています。 キーボードはNuPhyの Halo75 で、スイッチはNight Breezeを使っています。打鍵感と静音性のバランスが良く、長時間使用しても疲れにくいのが気に入っています。 MacBook Pro本来の配置に慣れているため、マウスやトラックパッドを別で用意することはなくいわゆる尊師スタイルにしています。 椅子はHerman Millerの セイルチェア を使っています。椅子の選択は体の負荷に直結するので機能性の高さを重視しました。それに加えて普段はhamさんと同じように足置きを使っています。 性格的にものが多いと落ち着かないので、必要最低限のものだけを配置して作業に集中できるような環境を作っています。 まとめ いかがでしたでしょうか? 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは。 Findy Freelance の開発チームでエンジニアをしている 2bo です。 この記事では私が開発生産性を上げるために開発をする前に考えていることについて書きます。 ここで「開発をする前」というのは次のようなタイミングを指します。 PdMなどから新規施策の仕様について相談を受けたとき 起票された開発Issueを最初に確認するとき 自分がIssueを作成するとき なぜこのタイミングで考えるかというと、開発を進める上での方向性を間違える可能性を減らし後から軌道修正をしやすくするためです。 なおこの記事においては、開発生産性を「開発成果物の提供価値を投入リソースで割ったもの」とします。 いくら頑張って開発をしても、そもそもやるべきことの方向性を大きく間違えると提供価値が0に近づくため開発生産性が低下します。 特に開発が高速なチームで方向性を誤ると高速に間違った方向へ進んでしまうことになります。 そのような事態を避け、提供価値を少しでも上げるために考えていることを記します。 なぜ、いつ、だれがつかうか? 開発する必要があるか?しなくて済む方法はないか? シンプルにできないか? リリースを分割できないか? 実例の紹介 プロジェクトの概要 請求フローの理解 設計の見直しによるシンプル化 スコープの決定とリリースの分割 終わりに なぜ、いつ、だれがつかうか? 大前提にはなるのですが、まずは以下を考えます。 なぜ:なぜその機能が必要なのか?ユーザーはなぜこの機能をつかうのか? いつ:いつその機能を使うのか?そのときユーザーはどういう状況にいるのか? だれ:どういう属性のユーザーか?ユーザーが社内にいる場合、どの部署/役割の人か? これらの情報はありがたいことに PdM から普段提供してもらえています。しかしながら自分でも考えるようにしています。 エンジニアの視点からも考えることで、それを実現するための別の形の機能やアプローチが良いのではないかと提案できることがあります。 たとえ提案が採用されなかったとしても現行案の妥当性を確認できるため、方向性を間違える可能性を減らすことができると考えています。 開発する必要があるか?しなくて済む方法はないか? 提供価値を極力変えないまま、投入リソースを減らせるアプローチがないか次のことを考えます。 既に同じ機能が存在するか、または全く同じではないものの実質的に同じ提供価値を持つ機能があるか? 既存の機能を利用、または組み合わせて実現できるか? 外部サービスやライブラリをつかうことで実現できるか? 例えば、画面Aで情報の表示追加を要望された際、その情報をすでに表示している画面Bがあるため、画面Aへの直接追加ではなく、画面Bへのリンクを設けるだけで十分というケースがあったりします。 このように要望機能そのままでなくても必要十分をみたせば問題ないというケースでは、開発リソースを減らせることがあります。 シンプルにできないか? 機能が複雑になるとその後のメンテナンスや改修の工数が増加したり、作り直しが発生したりしてトータルで見ると生産性が落ちるということが起きがちです。 そのため次のことを考えます。 複数の関連性のない異なる目的を担う機能になっていないか? その場凌ぎでワークフローや処理の分岐を増やすことになっていないか、またはそれらを極力減らして開発できないか? 過度に自動化、抽象化することでなにをしているかわからなくなったり、イレギュラーケースに対応しづらくなっていないか? 私は過去にシンプルさよりもリードタイムを優先して機能追加をしたことがあります。その時は本来異なる目的をもつ既存機能に付け足す形で機能追加をしました。 最初のリリースまでのリードタイムは短縮できましたが、処理の分岐とデータのパターンが増えてメンテナンスとデータ集計がしづらくなり、結局は一から作り直すことになりました。 トータルで考えると最初からシンプルに別の機能として設計/開発をしたほうがよかったと考えています。その反省も踏まえての内容になります。 ただし、特にベンチャー企業においてはどうしてもリリースまでのリードタイムを短くしなければならない状況もあると思います。 そのため完全に否定できることでもないですが、単にそのほうが楽だからという理由ではやらない方がよいと考えています。 リリースを分割できないか? ユーザーへの価値提供を考えて立案された施策や機能が、本当に有効かどうかは実際に提供してみないとわかりません。 また、大きな施策の場合は必須なものと必須ではないがあれば嬉しいというものが混在しがちだと考えています。 それらすべての内容をつくってからリリースする場合、期待通りの結果が得られなかったときに投入した開発リソースを無駄にしてしまう可能性があります。 これを避けるため、今回の開発で一番実現したいことはなにか?を考えて、もっとも重要なものから段階的にリリースすることを考えます。 いわゆるMVP(Minimum Viable Product)を開発ごとに考えるようなイメージです。 次のメリットがあると考えています。 ユーザーに素早く価値提供ができる 効果やユーザーのフィードバックを早く得られる 結果が素早く得られるため、軌道修正や撤退の判断が早期にできる リリースあたり開発ボリュームを減らせるため見積もりのブレを減らせる エンジニアのモチベーションの観点からも、早期にリリースすることで開発者のモチベーション向上につながりやすく、すべて作り込んで無駄になった場合のモチベーション低下も回避しやすいと考えています。 実例の紹介 ここからはこれまで紹介した考え方を実際に活かした「請求フローのシステム化」プロジェクトの事例を紹介します。 プロジェクトの概要 Findy Freelanceではユーザーの稼働後サポートとして請求書の作成代行と業務委託報酬の代理徴収を行っています。 そのため、ユーザー個々の稼働状況を確認し、内容に応じて請求書を作成して企業に送信する必要があります。 これらの作業の多くは手作業で行われていました。サービス利用者の拡大に伴い運用の限界が見えたため、請求フローをシステム化するプロジェクトが立ち上がりました。 請求フローの理解 私は開発リーダーとしてプロジェクトを途中から引き継ぎました。その時点で請求業務のドメイン知識がほとんどありませんでした。そのためPdMにヒアリングしながら請求フローの図を作成し、どの役割の人がどのタイミングで何をするのかを把握しました。つまり「なぜ、いつ、だれが?」の観点を確認しました。 情報を整理することでエンジニアユーザー、企業担当者、社内の営業担当者および経理など多くのステークホルダーが関与しているとわかりました。以後の開発で各々の視点を意識でき、先を見据えながら起案時よりもさらに価値のある仕様に繋げることができました。 設計の見直しによるシンプル化 次に、設計の見直しを行いました。プロジェクト引き継ぎ前は、手作業で管理されていた情報をそのままデータベースに移す形で設計が進んでいました。 例として、Findy Freelanceの契約スキーム上「企業とファインディ間の契約条件」と「ユーザーと企業間の契約条件」の2種類の契約情報が必要です。 当初はこれらを1つのテーブルで管理する設計でしたが、本来は別の情報であり、それぞれの契約変更のタイミングも異なるため、別のテーブルで管理することにしました。 これによりテーブルとモデルクラスの役割が明確になり、シンプルになりました。 また、2種類の契約情報がそれぞれいつ変更されたのかも管理できるようになりました。 設計の見直しには時間がかかりましたが、その後の改修や運用コストを考慮すると、見直して良かったと考えています。 スコープの決定とリリースの分割 プロジェクト引き継ぎ時、システム化に必須な機能と便利な機能がIssueに混在していました。 せっかくシステム化するならと多くの要望が積み上がっていましたが、スコープが不明確でした。 そのため、PdMを中心に関係者と協議してスコープを決めました。 早期の運用開始を目指し、必須機能のみを最初にリリースしました。例えば、次の機能は最初のリリースから除外しました。 社内管理画面の利便性向上 ダッシュボードの作成(初回リリースではBigQueryからのデータ参照で代替) ユーザーがログインページから報告した稼働時間の確認(報告時にユーザーへメール送信しているため) これらの機能は実運用後に必要性を再検討することにしました。スコープを決定し、リリースを分けることで運用開始までのリードタイムを短縮しました。 また、実運用をしたことで発覚した必要となる機能や改修があり、最初からすべて作りこまなくてよかったと考えています。 終わりに 以上が開発をする前に私が考えていることとその実例です。誰かの参考になれば幸いです。 ここに書いてあるようなことは普段から考えているという方も多いのではと思います。 読んでくださった方々が開発に際して考えていることなど是非コメントをいただけると嬉しいです。 また、ファインディではエンジニア領域のプロダクトの開発をするため、開発エンジニアが提供価値を考えるにあたり自然とユーザーの視点にたって考えることがしやすい環境であると感じています。 エンジニアへの価値提供に少しでも興味を持っていただけた方は、ぜひカジュアル面談のお申し込みをお待ちしております。 ファインディの採用情報はこちら↓ herp.careers また、ファインディの開発メンバーが登壇するイベントを4/24(水)12:00~13:00で実施します! 開発生産性や開発のパフォーマンス向上にご興味ある方はconnpassページより是非お申し込みください! developer-productivity-engineering.connpass.com
アバター
こんにちは。 Findy で Tech Lead をやらせてもらってる戸田です。 先日、弊社から Findy Tools がリリースされました。 今回は、そのFindy Toolsがどのようにして開発されたのか、開発の背景や工夫点などを紹介していきます。 それでは見ていきましょう! Findy Toolsの概要 紹介 Findy Tools は開発ツールに特化したレビューサイトです。第三者の視点で実際にツールの選定をした企業の生の声を集めることで、ツール選定に関する不安を解消し、導入検討に必要な情報を提供します。 「Findy Tools」を開発ツールの導入検討をしているユーザーが利用すると、実際にツール選定をした大手企業やメガベンチャー企業の技術責任者やエンジニアによるレビューを集めることができ、導入検討がスムーズになります。 また、開発ツールを掲載するベンダーには、実際の利用企業の声を活かしたコミュニティマーケティングによる新規顧客の獲得や、認知向上をご期待いただけます。 システム構成 システム構成は次の通りになっています。 Ruby on Rails React Next.js App Router bulma GraphQL AWS S3 CloudFront Aurora Fargate 上で挙げた構成に特に強いこだわりはなく、既存資産の流用をしやすかったことと、リプレイスや変更しやすいという理由でこの構成になっています。 APIとフロントエンドを疎結合で設計し、どちらか一方を作り直しやすくしたり、GraphQLを用いることでqueryそのものを変更することなく、呼び出し先のエンドポイントを切り替えることでアプリケーションの振る舞いを変えずにAPIを切り替えることができるような構成にしています。 開発 スケジュールとリソース 今回の開発はα版、β版と2回に分けて段階的にリリースしました。 α版は2023年9月から2023年10月で開発し2023年11月上旬にリリース、β版は2023年11月から2024年1月まで開発し、2024年1月下旬くらいにリリースしています。 開発リソースはα版は1人、β版は2024年に入ったあたりから2人で、それに加えてインフラ担当1人で開発をしました。 基本的にβ版リリースまではアプリケーション側の1人で開発していました。 新規サービスが当たるかどうかは実際に世に出してみないとわからないので、「最小限のリソースで最速でリリースする」という方針でした。 開発のポイント 既存資産を活用 最小限のリソースで、最速でリリースするという方針だったので、まず「全てを1から作る」という選択肢は可能な限り避けました。 幸い弊社には既に運用されてるシステムがあり、そこからの流用を決めました。 具体的には次の内容を流用しました。 アプリケーションの実行基盤まわりの共通コード フレームワークの各種設定ファイルや設計思想 デプロイやCIのワークフローのコード 共通コードや各種設定ファイル、設計思想は既存の各サービスでほとんどが統一されており、コピペして少しいじったらすぐに使えるような状況に整備されています。 またデプロイやCIまわりは全てGitHub Actionsに統一されており、こちらもワークフローのファイルをコピペして少しいじるだけですぐに使えるようになっています。 これらの既存資産を流用することで、コードを書き、テストで守り、動作環境にデプロイし、最低限動くものを確認できる環境をすぐにセットアップできました。 ゼロからモノを作るうえで動くものを用意することは非常に重要です。動くものをメンバーと共有して確認することで、認識の齟齬を防ぎ、余計な修正作業を減らすことが出来ます。 データ投入を簡略化 データ投入は開発の中でも時間を取られる作業の1つです。 レビュワーの方から頂いたレビューデータや、各種マスターデータをデータベースに投入する必要があります。 α版の時点ではデータ投入を簡略化するために、全てのデータをseedで投入することにしました。 本来であればデータ投入用の管理画面を作るのがベストなのですが、α版のリリース前に1人で開発してる状況で管理画面を作るようなリソースはありませんでした。 機能の取捨選択 初期リリースの目的は多くのユーザーを獲得することではなく、「サービスが受け入れられるかどうかを可能な限り早い段階で判断する」ことにあります。 そのため、「サービスが受け入れられるかどうかの判断に必要のない機能」を初期リリースのスコープから外しました。 具体例を挙げると、β版リリースまでは画像アップロードの機能を外しました。 レビューデータやアバター画像などをアップロード出来るようにしたかったのですが、画像アップロードを実現しようとすると、色々と考えないといけないことがあります。 画像のアップロード先はどうするのか?削除は許可するのか?画像サイズはどこまで許すのか?などなど色々出てきます。 今回は画像のアップロードを許可せず、運営チームが用意した画像をS3に直接アップロードして、そこへのパスをseedに直接書くことで画像ファイルの管理を単純、簡略化しました。 この機能を簡略化するだけだと良くて1,2日程度の開発工数削減に留まると思います。しかし、このような取捨選択をいくつかすることによって、結果的に半月や1ヶ月程度の工数削減に繋がりました。 この機能を削減して大量に工数削減、といったものではなく、ミニマムな削減の意思決定を大量に行うことによって実現しているのです。 テストコード 色々な取捨選択の意思決定の中で、テストコードだけは切らずに必ず用意していました。 「時間が無いからテストを書かないのではなく、テストを書かないから時間が無い」というのは事実で、結果的にテストが守ってくれているおかげで、余計なことに時間を取られずにやりたいことに集中できるのです。 テストコードのお陰で、α版リリース以降に本番環境で発生した不具合、障害は記憶しているだけですが片手で数えられる程度でした。 管理画面を内製 α版のリリースにより、「このサービスが世に受け入れられる」ことを確認できたため、β版のリリースに向けて着手しました。 α版からβ版に向けて何を実現させるのかを検討している間、開発するものがなくて時間を持て余していたので管理画面を内製で実装することにしました。 各種マスターデータやレビュワーの方から頂いたレビューデータなど、運営で管理したいデータは多数あります。 それらの変更のたびにseedの再実行、データの変更を依頼するようなフローにしてしまうと、エンジニアが機能追加の作業に集中できなくなってしまいます。 β版リリースからはエンジニアを介さずにデータの追加、変更を運営メンバーだけで完結出来るようにしました。 管理画面の画面数は25個程度で、APIとフロントエンド込みで1人で2、3週間程度で開発しました。 管理画面はSSRが必要ないので純粋なReactのSPAで、CSSフレームワークに Bulma を採用しました。 管理画面を用意できたことによって、β版以降の開発時に運営メンバーからのデータ管理周りの依頼が無くなるので、開発作業に集中できるようになりました。 反省点 Findy Toolsの開発では、チャレンジ枠としてNext.jsのApp Routerを採用しました。 既存プロダクトに用いられているPages Routerからの移行を検証する狙いもありましたが、今回は上手くいかなかったと反省しています。 誤解を与えないように言うと、Next.jsのApp Router自体は悪いものではありません。 何が上手くいかなかったかというと、既存資産の流用をした結果、利用していたライブラリがApp Routerに対応出来ておらず、想定していた以上の工数を取られてしまったことです。 弊社ではApp Routerを初めて採用したケースであり、社内にノウハウが蓄積していなかったため、問題解決に時間がかかってしまいました。 今後、他サービスでのApp Routerの採用時に今回のノウハウを活用できるようになったと思いますが、今回のような開発スピードを優先されるケースで採用するべきではなかったかなと思います。 まとめ いかがでしたでしょうか? 新規サービスの開発時にはリソースやスケジュールに大きな制約が課せられます。そのような状況下でやるべきこと、やるべきではないことの取捨選択の意思決定が非常に重要になってきます。 半年近く1人で開発をしてきた Findy Tools ですが、みなさまのおかげもありサービスが順調に成長しており、今では開発に着手しているエンジニアの人数を増やすことができました。 今後もFindy Toolsをより良いサービスにしていくために、引き続き開発を進めていきます。 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
Findy Team+でフロントエンドエンジニアをしている 川村( @peijun333 )です。 Findy では、フロントエンドのコード品質と安定性を確保するために Jest などのテストフレームワークを積極的に活用しています。通常、Jest は CLI から実行してテスト結果をコンソールで確認しますが、コマンドを用意する手間や、テスト経過のデバッグのために都度 console.log などでその内容を確認しなければならずとても不便です。 そこで、今回はテストの自動化とリアルタイムなフィードバックを提供する JavaScript の統合テストツールである Wallaby.js を紹介します。Wallaby.js を導入することで、開発効率の向上が期待できます。 Wallaby.js とは? 前提条件 VS Code でテストの修正 Wallaby.js はリファクタリングに強い スナップショット の更新 ユニットテストにおけるデバッグ機能の紹介 Wallaby.js を使ってみて 最後に Wallaby.js とは? Wallaby.js is an integrated continuous testing tool for JavaScript. It runs your tests immediately as you change your code (you don’t even have to save the file) and displays various results (including the code coverage, error and console messages) right inside your code editor, next to your code. Wallaby.js is great for doing JavaScript TDD (Test-driven development) or BDD (Behavior Driven Development), but it works great for other approaches as well. 公式ドキュメントより Introduction: What is Wallaby.js? Wallaby.js は JavaScript の統合テストツールで、次のような機能があります。 リアルタイムなフィードバック Wallaby.js は、テストの実行に手動のステップが不要なため、コードを変更するとリアルタイムで結果をフィードバックしてくれます。 エディタ内でのテスト結果表示 Wallaby.js は、コードエディター内にテスト結果を表示してくれます。エラーやカバレッジ情報などが、コードの隣に直接表示されるため、エディタから離れることなく、テスト結果を確認できます。 デバッグ機能 Value Explorer を使用することで、任意の場所で値を調査し、呼び出し元のコールスタックを確認できます。また、コンソールログをエディタ上に表示する機能も備えており、デバッグプロセスをスムーズにします。 また、サポートしているコードエディタとテストフレームワークが 豊富 で導入がとても容易です。 Wallaby.js は OSS 開発では無料で利用できますが、商用利用の場合は 有料 です。ファインディではフロントエンドを開発するメンバーにアカウントを発行しています。 前提条件 ここから実例を交えて機能を紹介します。実例に使った動作環境は以下の通りです。 VS Code VS Code 上に Wallaby.js の拡張機能 をインストールする必要があります VS Code 以外のコードエディタ もサポートされていますが今回は VS Code を使った紹介になります React version 18.2.0 Jest version 29.6.1 React Testing Library version 14.0.0 Wallaby.js の導入に関する詳細な手順や設定方法については、 公式ドキュメント を参照してください。 VS Code でテストの修正 Wallaby.js は サポートされているエディタ 上で動作します。今回は VS Code で普段テストを書いている様子を紹介します。 以下は、GraphQL を用いてユーザーデータを正しく取得できているか確認するテストの例です。 + expect(result.current.users).toStrictEqual([{ id: '1', name: 'name' }]); - expect(result.current.users).toStrictEqual([{ id: 1, name: 'name' }]); id が number 値ではなく string の '1' であるべきなのですが、上記動画の例では誤った結果を書いています。 Wallaby.js ではこのようにテスト結果がコードエディタ上(VS Code の例)にリアルタイムに反映されます。 予想される結果と実際の結果が異なる場合、赤色のテキストでエラー文が表示されます。そこにカーソルを合わせることで、具体的に差分内容を VS Code 上で確認できます。 - Expected - 1 + Received + 1 Array [ Object { - "id": 1, + "id": "1", "name": "name", }, ] また、VS Code 上では左側の余白に四角のテストカバレッジインジゲーターが 赤色 から 緑色 に変わった様子が確認できたかと思います。これにより視覚的にテストのカバレッジを確認できます。 詳細: Editor Code Coverage Indicators この機能のメリットは、エディタ上でテストの操作が完結でき、さらにリアルタイムに優れている点です。テストの実行や結果、失敗時のエラー原因の迅速な特定、ナビゲーション、差分ビューなど、すべてをエディタ上で行うことができます。 Wallaby.js はリファクタリングに強い 特にリファクタリングでは、 Wallaby.js の機能の 1 つである「リアルタイムにテスト結果がフィードバックされる機能」が発揮されます。 以下は ユーザーデータから空の name を取り除けることを確認するテストの例です。 テスト結果と関数のインターフェイスはそのままで、ロジックのみをリファクタリングしています。こちらの例のように、リアルタイムにテストが失敗し、リファクタリング後ファイルを保存せずともテストが成功しました。 このようにリアルタイムにテストが落ちてくれるので、関数の影響範囲がわかりやすく、テスト結果からすぐにフィードバックされることで効率よくリファクタリングが可能です。 スナップショット の更新 次にスナップショットテストの更新について紹介します。スナップショットテストとは、UI が予期せず変更されていないかを確かめるテストです。Findy Team+では @testing-library/react を使い コンポーネントのスナップショットを撮影し、必要に応じて差分を更新しています。 はじめに Wallaby.js を使わずに Jest のスナップショット を更新する手順をみてみましょう。 次の例は title と description を表示するコンポーネントのスナップショットテストです。 import { render } from "@testing-library/react" ; import { TestComponent } from "./test.component" ; const props = { title: "title" , description: "description" , } ; describe ( "TestComponent" , () => { it ( "表示確認" , () => { const { asFragment } = render ( < TestComponent { ...props } /> ); expect ( asFragment ()) .toMatchSnapshot (); } ); } ); 実装コード type Props = { title: string ; description: string ; } ; export const TestComponent = ( { title , description } : Props ) => { return ( <> < div > { title } </ div > < div > { description } </ div > </> ); } ; @testing-library/react の render 関数を使いスナップショットを撮影しています。このテストを初めて実行すると次のようなスナップショットファイルが作成されます。 // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`TestComponent 表示確認 1`] = ` <DocumentFragment> <div> title </div> <div> description </div> </DocumentFragment> `; 仕様の変更により、description を表示するタグを <span> タグに変更してみます。 - <div>{description}</div> + <span>{description}</span> そしてテストを再度実行すると UI の差分によりテストが失敗します。 ● TestComponent › 表示確認 expect ( received ) .toMatchSnapshot () Snapshot name: `TestComponent 表示確認 1` - Snapshot - 2 + Received + 2 < DocumentFragment > < div > title </ div > - < div > + < span > description - </ div > + </ span > </ DocumentFragment > 12 | const { asFragment } = render( < TestComponent { ...props } /> ); 13 | > 14 | expect(asFragment()).toMatchSnapshot(); | ^ 15 | }); 16 | }); 17 | › 1 snapshot failed. 今回は description を表示するタグは div ではなく span タグが正しいのでスナップショットを更新する必要があります。 Jest でスナップショットを更新するには --updateSnapshot や -u オプションを使い更新します。 (または ウォッチモードで対話的に更新) 以上の手順を踏むことでスナップショットの更新が完了します。 今回は 1 ファイルのみの修正で変更差分も軽微なものですが、複数のテストが失敗した場合、目的のテストを見つける手間と時間がかかります。また、エディタからターミナルに移動しコマンドを実行する必要があるため、コンテキストを切り替える必要があり、多くの時間が消費されます。 次に Wallaby.js を使ったスナップショットの更新をみてみましょう。 エラーにカーソルを合わせ、差分を確認した後、右上のカメラアイコンをクリックしただけです。 失敗したテストをエディタで確認し、スナップショットを直接更新するだけなので、目的のテストを見つける手間も時間もかかりません。 ユニットテストにおけるデバッグ機能の紹介 Wallaby.js には Value Explorer という機能があります。これを活用することで、デバッグ作業を効率化でき手動でのログ出力作業を大幅に削減できます。 また、テスト実行ログに記録されている値に対して、呼び出し元(実装コード)の Call Stack を調べることもできます。 Value Explorer を使用することで、標準出力をコードに仕込まずともデバッグ作業を可能にしますが、使い慣れている console.log を使ったデバッグも Wallaby.js は対応しています。エディタ上にログの結果を表示できるため、コードとログを同時に確認しながらデバッグ作業を行うことができます。 Wallaby.js は多様なログの確認方法があり、当記事では紹介しきれないので気になる方はチェックしてみてください。 Introduction: Advanced Logging Wallaby.js を使ってみて Wallaby.js を使ってみて特にリアルタイムにテスト結果がフィードバックされる点はとても便利だと感じました。Wallaby.js を導入する前はファイル単位やテストケース単位で、テストを実行させる必要があり時間がかかっていましたが、リアルタイムにテスト結果を反映してくれるので実装に集中して開発を進めることができます。リファクタリングでは、リファクタリングの前後でインターフェイスが保たれているかをエディタ上のテストカバレッジインジゲーターから確認できる点は Wallaby.js の強みだと感じました。 FAIL PASS また、 Smart Start という機能により、コードの変更により影響を受けた箇所のみ自動的にテストが実行されるので、とても高速にストレスフリーで動作してくれます。Findy Team+のように大規模なプロジェクトでも高速に動作してくれるのは非常に強みだと思います。 最後に 今回の記事では、JavaScript の統合テストツールである Wallaby.js について紹介しました。 Wallaby.js の導入により、開発プロセスの効率化やコードの品質・安定性の向上が期待できます。是非、Wallaby.js を活用して、よりスムーズなフロントエンド開発を実現してみてください。 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは、あるいはこんばんは。 @gessy0129 です。 このたび、ファインディに入社しましたので、入社エントリーをさせていただきます。 お時間のあるときにご覧いただければと思います。 ファインディに対する想いと気持ち 改めて、この度、ファインディ株式会社に正式に参加することとなりました。 パチパチパチパチ 昨年からいくつかのnote記事を執筆させていただいたところでございますが、それに絡めつつ、今回の気持ちを綴りたいと思います。 参考記事: ANDPADを退任しました|げっしー 2024年目標と決意と挑戦と|げっしー 相変わらず、自身の掲げるミッションは、 半径数メートルから幸せの連鎖を生み出す という事だと思っています。 過去の在籍企業で、VPoEや開発本部長として長い間勤務をしてきました。 その中で、ものづくりに集中しているエンジニアたちを支えていく事というのは相当なやりがいでした。 エンジニアたちが幸せに業務出来る環境を整え、それが連鎖していくようにすること。 これはとても楽しかったです。 ※ もちろんVPoE としての業務はこれだけではないです。 この領域を更に深め、挑戦するエンジニアを応援していきたいという思いが強まりました。 そして、その想いが高まった時、多くの選択肢の中からファインディと出会いました。 ファインディのミッション、ビジョン、バリューに共感し、これは非常に大きな出会いであると感じております。 エンジニアの可能性を拡げ、スタートアップのエコシステムに貢献できることを願っています。 やろうとしてること ファインディは色んな事業を展開してます。 エンジニアの転職を支える転職事業 フリーランスエンジニアを支えるフリーランス事業 国内外のエンジニアと企業をつなげるグローバル事業 活躍するエンジニアを支えるTeam+事業 技術選定や意思決定をサポートするTools事業 などなどがあります。 これらの事業がすべて、挑戦するエンジニアのプラットフォームを作り上げ、エンジニアの可能性を広げることにつながると考えております。 そして、CEOの山田さんやCTOの佐藤さんが、この領域で挑戦しようとしていることに感銘を受けております。 ここで、素晴らしいメンバーと共に、挑戦するエンジニアが必要とするサービスを積極的に提供していきたいと思っております。 しかし、まだまだファインディ自体が、挑戦するエンジニア、挑戦したいエンジニアに積極的に選ばれる状況にあるとは言えないのではないかと考えております。 これは、ファインディにとっても僕にとってもさらなる 伸び代 だと思っております。 「ファインディに相談すればなんとかなる」という状況を作り上げることができればと考えております。 最後に ファインディの対外活動にも積極的に参加していく予定でございます。 その際は、皆様、よろしくお願いいたします! 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
Findyでエンジニアをしている松村( @shakemurasan )です。 以前、弊社の栁沢が「RailsのCIのテスト実行時間を10分から5分に高速化した話」という記事を投稿しました。 tech.findy.co.jp 本記事ではその少し前のお話、そもそもRSpecの実行時間自体にまだまだあった伸びしろ、特にFactory周りの問題をTestProfというgemを活用して解消していった話となります。 当時のRSpecの実行時間状況 TestProfとは TestProfでの分析結果 改善1. 関連したレコードを複数件作成しているFactoryを1レコードに減らす 改善2. テストで必要最小限なレコードのみを作成する RSpecの実行時間の改善結果 考察 当時のRSpecの実行時間状況 これまでにもテスト実行時間の短縮のための取り組み(CI側でのマシンの並列起動および並列実行)はしており、そこまでストレスのある環境ではありませんでした。異様に実行時間を要しているテストが存在することはメンバー間で認識しており、何となく原因のアタリはついていたものの、並列実行導入で快適な環境が得られていたので、テスト軽量化の優先度が落ちている状況でした。 しかし、じわじわとテスト実行時間は伸びていき、並列実行の導入当初は10分程度だったものが、15分を超えるケースが目立つようになってきました。いよいよテスト軽量化に着手しようかという話になり、実際に対応していくことになったのでした。 更に並列化を推進しようという案もその時点であったのですが、そもそも前述の「異様に実行時間を要しているテスト」が原因でマシンごとのテスト実行完了時間に度し難いバラツキが生じており、まずはここを解決しなければならないよねとなりました。 TestProfとは テスト軽量化にあたって、まずは何となくアタリをつけていたところに本当に原因があるのか測定することにしました。解析/測定に際し、TestProfが使えそうということは様々な記事、他企業様のテックブログ事例から知っていたので、これを採用することにしました。 github.com TestProfには様々な機能があるのですが、アタリをつけていたのはテストデータ生成周りだったため、FactoryProfというFactory周りの解析機能を使っています。FactoryProfを用いることで、Factory別の 総呼び出し回数 / 総実行時間 / 1回あたりの実行時間 あたりをレポーティングでき、この機能を用いて改善に着手しました。 ※ この後の章で登場するファイル名、Model、Factoryは仮名に置き換えていますが、数値は実際のものを掲載しています TestProfでの分析結果 まず大前提、時間がかかっているテストケースの状況を見てみます。 spec Before After Reduce Worst1 78.37s ??? ??? Worst2 75.71s ??? ??? Worst3 48.76s ??? ??? Worst4 48.16s ??? ??? Worst5 88.01s ??? ??? Total of worst 339.01s ??? ??? 実にテストケース5本で5分39秒を越えている状況で、これはちょっと辛いな.... というのがわかります。ここから、一番重たいテストケースのみを指定してFactoryProfの解析をかけてみます。 FPROF=1 bin/rspec spec/models/worst_spec.rb:2244 すると次のようなレポートが得られます。 [TEST PROF INFO] Factories usage Total: 1586 Total top-level: 8 Total time: 01:32.432 (out of 01:59.446) Total uniq factories: 12 total top-level total time time per call top-level time name 309 0 80.7570s 0.2613s 0.0000s full_item 103 0 0.8972s 0.0087s 0.0000s shop_user 103 0 90.3245s 0.8769s 0.0000s item_like 103 0 88.4511s 0.8587s 0.0000s shop ... ... ... この結果を見ると、 item_like shop が呼び出し回数と1回あたりの実行時間あたりが1s弱と長いことがわかります。ここから段階的に改善の手を打っていきます。 改善1. 関連したレコードを複数件作成しているFactoryを1レコードに減らす そこで実際のコードを読んでFactory間の依存関係を見てみると次のような状況でした。 item_like -- create --> shop ┬-- create --> full_item ├-- create --> full_item └-- create --> full_item テストの要件は割愛させていただくのですが、テストを実行するうえで full_item は3件も必要なく、最低1件はshopにぶら下がっていれば十分という状況でした。 item_like というのはここ以外でも結構色々なところで使われているFactoryで、ほとんどのテストは最低1件のshopがぶら下がっていれば問題ない状況でした。 そこで、 item_like のFactoryを修正して full_item を1件だけに限定して再解析したところ、次のような結果が得られました。 [TEST PROF INFO] Factories usage Total: 659 Total top-level: 8 Total time: 00:36.813 (out of 01:14.075) Total uniq factories: 11 total top-level total time time per call top-level time name 103 0 32.7865s 0.3183s 0.0000s shop 103 0 27.1212s 0.2633s 0.0000s full_item 103 0 0.8971s 0.0087s 0.0000s shop_user 103 0 34.5748s 0.3357s 0.0000s item_like ... ... ... 単純に full_item の生成回数が1/3に減り、それに比例して実行時間も約1/3に圧縮できました。 改善2. テストで必要最小限なレコードのみを作成する 別の重たいテストも解析していくと、共通して同じ問題が見えてきます。 [TEST PROF INFO] Factories usage Total: 3157 Total top-level: 582 Total time: 02:05.161 (out of 04:30.214) Total uniq factories: 48 total top-level total time time per call top-level time name 322 6 6.2221s 0.0193s 0.1149s user_profile 276 70 74.0465s 0.2683s 5.2776s shop 230 0 63.5779s 0.2764s 0.0000s full_item ... ... ... 次に着目したのは、 full_item の実行時間の長さです。1回あたり 0.2764s ということでそんなに長く感じないかもしれませんが、呼び出し回数が非常に多く、塵も積もればこのテストでは230回呼ばれて 63.5779s は無視できない実行時間になっています。 またまたコードを読んでみると、 full_item は関連するデータを全部盛りで作る.... というFactoryになっていました。 item というモデル自体、システムの中でコアなドメインのモデルとなっており、非常に多くの関連を持ちうるものなのでした。しかし、大部分のテストにおいてはそこまで完全な状態の item は要らないという状況でした。 そこで、 shop 生成時のデフォルトは full_item ではなく item というスリムなFactoryを使うように切り替え、再度解析をしてみることにしました。 [TEST PROF INFO] Factories usage Total: 2697 Total top-level: 582 Total time: 01:06.857 (out of 02:53.458) Total uniq factories: 47 total top-level total time time per call top-level time name 322 6 4.7178s 0.0147s 0.0844s user_profile 276 70 29.5793s 0.1072s 4.0465s shop 230 0 10.8307s 0.0471s 0.0000s item 結果、1回あたり 0.2764s かかっていた full_item から、 0.0471s で済む item に取り変わったことで、このテストの実行時間は半分にまで圧縮できるようになりました。 RSpecの実行時間の改善結果 他にもTestProfを用いて細かな改善は入れていき、最終的にワースト5のテスト実行時間は次のように変化しました。 spec Before After Reduce Reduce Rate Worst1 78.37s 17.55s -60.82s -77.6% Worst2 75.71s 15.73s -59.97s -79.22% Worst3 48.76s 8.28s -40.48s -83.01% Worst4 48.16s 7.84s -40.31s -83.72% Worst5 88.01s 18.1s -69.9s -79.43% Total of worst 339.01s 67.5s -271.51s -80.08% 339.01s から 67.5s に圧縮され、この最悪値だったテスト5本に限定して言うと、実行時間を8割以上削減できました。さらに上記のテスト以外でも今回改善したFactoryは使われているわけですから、テストの総実行時間にも効いてくるわけです。 考察 今回、TestProfを用いて、何となく重たいんだろうと思っていたところが想定以上に無駄なことをしていたことがわかりました。 「とりあえずデフォルトで全部入りのテストデータ作っておくか!」というのは、ともすればやりがちですし、歴史の長いコードベースだと気づきにくいように感じました。 「推測するな、計測せよ」という言葉がありますが、実際に計測して打ち手をピンポイントに打っていくことで、着実に改善している感覚を得られて周囲にも説明しやすかったのも学びです。 また、今回Factoryの挙動を大胆に変更することで実行時間削減を実現していますが、これは常日頃みんながテストコードをかなり手厚く書いていてくれたおかげというのが大きいです。システムが壊れないことを担保するため、不安と戦うために我々はテストを書くわけですが、テスト自体のリファクタリングにもテストコードが有効であるということは学びになりました。 ファインディは積極的にエンジニアを採用しています。CI/CDを始め、Four Keys、開発生産性、技術トレンド、転職市場など興味のある方は、お気軽にカジュアル面談を受けてみてください :) ファインディの採用情報はこちら↓ herp.careers
アバター
こんにちは。 Findy で Tech Lead をやらせてもらってる戸田です。 Findy 社の Tech Blog を開設して 1 ヶ月程度が経とうとしています。 このブログを通して弊社の技術情報だけでなく社内のエンジニアのことをもっと知ってほしいと考えた結果、今回から 自慢の作業環境を大公開 と題して、社内のエンジニアの作業環境と、そこに対する考え方、思いなどを発信していく事になりました。 弊社のオフィスは東京にありますが、北は北海道、南は福岡まで遠隔地からのフルリモートで JOIN しているエンジニアが多数在籍しております。 エンジニアの多くが各自の自宅から作業しており、きっと自分にとっての最高の環境を整えているはずです! それでは、弊社エンジニア達の自慢の作業環境を見ていきましょう! 作業環境を大公開 戸田 というわけで初回は福岡から JOIN している Tech Lead の戸田の作業環境から紹介させてもらいます。 作業スペースの全体像はこんな感じです 基本的には DELLの32 インチの 4K モニタ を使い、クラムシェルモードで作業をしています。 スピーカー はモニタのアーム部分に接続しており、イヤホンを繋げてボタン一個で出力切り替えが可能なので、普段はスピーカーを使い静かにしたい時はイヤホンを使う。ということが簡単に切替可能です。 Web カメラ と マイク は別途購入して外付けで利用しています。リモートでの作業がメインとなるため、映像、音声環境は最低限のマナーと思い投資しました。 デスクは bauhutte というメーカーの 昇降デスク を使っています。 この昇降デスクは電動でボタン一つで高さを自由に変更でき、横幅も奥行きも大きいので色々な作業シーンに合わせて利用することが出来るので非常におすすめです。 そして安心と信頼のバグ退散お守り。CI を通すときや重要なリリースの前に祈りを捧げます。 手元周りはこんな感じ キーボードは HHKB Professional HYBRID Type-S を使っています。 今まで色々なキーボードを試しました。その結果、個人的に作業終了後の手元の疲れを一番小さく感じたのはこのキーボードでした。 特殊なキー配列ですが、慣れたらコードを書いたりコマンドラインを叩いたりしやすいキーボードだと思います。 マウスは Apple の Magic Trackpad を使っています。マウスに対する拘りはなくて、正直 Mac のショートカットアクションが使えれば何でもいいです。早くマルチペアリングに対応して欲しいです。 また、変わり種としては指の筋トレ用具を手元に置いてます。 事の発端は格ゲーをしてた時に思っていたより指が動かなくて、「人類は薬指と小指を思ってるより使ってないな?」と感じ、この二本の指を鍛えるために買いました。 リモート会議中とか、コードを考えてる時とかずっとこれで指を鍛えてます。これで鍛えだしてから薬指と小指がスムーズに動くようになり、キーボードのタイピングが今までよりもスムーズになった気がします。 作業用 BGM は HomePod mini と Apple Music の合わせ技を使っています。 iPad を HomePod mini とペアリングさせて、サブスクには新曲やサントラがどんどん追加されます。 作業スペースの横には趣味のプラモ作成スペースを、後ろには本棚とプラモケースと積みプラ。 自分の好きなものに囲まれているというのは、毎日1人で黙々と作業する環境としては想像以上に重要だと思います。 毎日部屋に籠もって1人で作業しているので、五感に入るもので飽きが来ない環境を作ることが大事だと思います。 熊野 青森からフルリモートの熊野( @shoota )です。 フルリモートは 2017 年夏からで 7 年目になります。 まずはメインのデスクから。 自宅に備え付けのデスク MacBook Pro 16” をノート用スタンドに載せ、デュアルディスプレイで作業をしています。 MacBook ディスプレイは基本的には Slack 専用で、ほぼすべての作業は 外部ディスプレイ + 仮想デスクトップでこなしています。 外部ディスプレイは DELL の 4K ハブモニター に仕事用の MBP と個人用の Mac mini を繋いでいて、画面を切り替えると接続しているキーボードも自動で切り替わるのが気に入っています。 デスクライトを Amazon Alexa に接続し、デスク左側の Amazon Echo から音声操作できるようにしています。デスクから離れたあとにライトの消し忘れに気づくので、遠くからでも声でライトのオンオフができるのが便利です。 Echo は Spotify などの音楽再生をしたり、他の家電の操作にも使っています。 デスク右側は Anker の無接地タイプの充電器 で iPhone のスタンバイ表示をしています。 その隣には iPad mini をおいていて、ちょっとしたメモをしたり、作業をしながらオンラインイベントを見たりするときに使っています。 全体的に黒で統一するのが好きで、トラックパッド だけが白なのでそろそろ黒の方に買い替えちゃおうかなと思っています。 キーボードは Keychron の分離式キーボード Keychron Q11 QMK Custom Mechanical Keyboard 、ポイントデバイスは Magic Trackpad2 です。 分離式キーボード 肩こりがひどくなりやすいので分離式キーボードをずっと使っていますが、Q11 はキースイッチごと交換したりキーマップのカスタマイズが簡単で、多機能なのでかなり気に入っているキーボードです。 いまは赤軸スイッチと標準仕様のキーキャップなので、そろそろキーキャップを変えたいな〜と思っているところです。 またフルリモートとしてはビデオ通話の品質を大事にしたい&自宅では子どもたちの声などの環境音が混ざりやすいので、自分も音響はしっかりと用意しています。 マイクは指向性の Yeti Nano で自分の声だけが入るようにスタンド設置しています。 Yeti 以前はヘッドセットを使っていましたが、いずれも「物理スイッチでミュートできる」ことがこだわりです。 急にくしゃみしたいときにソフトウェアミュートは間に合わないので 逆に出力側は周りの音が聞こえないと不便なので、オープンイヤータイプを愛用していて、いまは shokz の OPENFIT を使っています。 指向性マイク 最後にデスクの後ろに DIY で作ったコミック棚があるので、自慢がてらに紹介したいと思います。 自分が好きなものや集めたものに囲まれて仕事をするのが好きなので、コミック(たぶん 800 冊くらいあります。もう数え切れません。)やゲームグッズ、お気に入りのウイスキーをおいています。 安全率を含めた荷重計算をして設計図をつくり、部材の切り出しから組立て、取り付けまでひとりでやりました。 だいたい 2 万円強くらいですべて揃い、先日の震度 5 以上の地震でも コミックは 1 冊も落ちませんでした。 2023 年下半期の総会、 Fine-day で MVP を受賞 したときのトロフィーも飾っています。 DIY本棚とMVPトロフィー 仕事場でありながら自分らしさを出しつつ、仕事における自分なりの「快適性 / 合理性」を求めたデスクに仕上がっていると思っています。 主計(かずえ) 福岡からリモートでフロントエンドの開発をしている主計( @nesskazu )です。 デスクの全体像はこのような感じです。 デスク全体 4k ディスプレイを 2 枚配置しコーディングしながらデバッグできるようにしています。 ミーティング時にドキュメント等を参照できるのも便利です。 サブモニターはデバッグしやすく、web等の閲覧性が良いため縦配置にしています。 コーディングとデバッグの画面配置 Thunderbolt ケーブルで会社支給 PC と私用 PC で全ての機器の接続が切り替わるようにしています。 ドッキングステーションには CalDigit TS3 Plus Dock を使用しています。 Thunderboltケーブル1本でPC切替 ドッキングステーション キーボードは静電容量無接点方式やメカニカルなどいろいろ試してきましたが、 自分はキーストロークの深いキーボードは苦手(疲れる&タイプミス多い)なことがわかったのでキーストロークが浅いキーボードを使っています。 MX Keys mini がお気に入りでしたが、途中からチャタリングが発生したり Touch ID が欲しかったので現在は Apple Magic Keyboard を愛用しています。 また、切り替えや充電の手間をなくすため有線で接続しています。 Apple Magic Keyboard リモートワークということもありミーティングが相手と自分双方にとって快適なものになるように構築しています。 マイクは周囲の音を拾いにくいダイナミックマイク(SHURE MV7)を採用しています。 カメラはなるべく目線の高さに合うようにディスプレイ間のスピーカーの上に設置しています。 マイクとカメラ ミーティングや BGM の音は OWNDAYS の HUAWEI Eyewear で聞いています。 普段メガネ付けている人であればメガネが変えるだけでスピーカーが着いてくるので便利です。 ミーティングのたびにイヤホンを装着したりする必要がなくなります。最近電池持ちが悪く昼休みに充電する必要があるため Eyewear2 の購入検討中です。 Eyewear を使い初めてから休みの日にしかコンタクトを使わなくなりました。 Eyewear 我が家でもバグ退散のお守りが後ろから見守ってくれています! バグ退散お守り このように仕事をするうえで不便な点を排除し、快適に作業等ができるように意識してデスクを構築しています。 まとめ いかがでしたでしょうか? 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから ↓ herp.careers
アバター
こんにちは。こんばんは。 開発生産性の可視化・分析をサポートする Findy Team+ のフロントエンド リードをしている @shoota です。 Findy Team+はエンジニア組織の開発生産性を可視化し、開発チームやエンジニアリングメンバーのパフォーマンスを最大化するための支援をしています。 そして(当然のことながら)Findy Team+ を作っている自分たちも、チームや個人でドッグフーディングをして、チームや自分自身の働き方やエンジニアリング組織の健康チェックをしています。 今回はそんな Findy Team+の開発チームのうち、フロントエンドチームがどのような開発環境・開発インフラで働いているかの概要をご紹介したいと思います。 フロントエンド技術スタックとCI高速化 技術スタック まずはじめにフロントエンドの技術スタックを簡単に紹介します。一般的なSPA構築の技術スタックを採用しており、それほど特別なものではないことをご理解いただけると思います。 React React Router Redux TypeScript GraphQL Apollo Client GraphQL Codegen Emotion Storybook Testing Jest @testing-library/{react,jest-dom,user-event} reg-suit Linter / Formatter ESLint Stylelint Prettier ここまではいわゆる一般的なSPAの構成ですが、Findy のフロントエンドはモノレポ管理ツールである Nx を利用することで高速化を図っています。 Nxの機能詳細についての説明はここでは省略しますが、トップページに「Smart Monorepos・Fast CI」とある通り、CIの高速化が簡単に管理できるところが最大の特徴と恩恵だと思っています。 NxでCIを高速化する Nxは内部に複数のプロジェクトを持つことができ、且つ、それらの依存関係を自動で解析します。 この「プロジェクトの依存関係」をもとに、プルリクエストでの「変更されたプロジェクト」と、その「変更部分が依存しているプロジェクト」のみのテストを実行する手段を提供しています。 これによって開発者が開発しているものに関係のない部分は省略されるためCIが高速化します。 それ以外の変更についてもNx Cloudにキャッシュが残っていればその結果を採用してテスト等をパスさせ、CIが高速に完了します。 CIの実行結果を載せてみました。 GitHub Actionsの様子 共通のhooksを修正してる3段目のプルリクエストではほぼ全てのテストを実行(そして新たにキャッシュ)しているため、20分以上のテスト時間がかかっています。 一方でその他をみてみると、新しい画面などの通常開発の場合は変更内容がプロジェクト内で完結しているので、CIの実行時間は数分で終わっています。 また単にCIが高速化される以外にも、Nxは開発生産性の向上に寄与してくれます。 それは 「プルリクエストはできるだけ小さく作ろう」という開発文化を「CI時間」という数値で可視化 してくれることです。 前述の通りプルリクエストの変更の依存関係が小さいほどCIは早く終わりますので、逆にプルリクエストが広範な範囲で大きくなってしまうほどCI時間が長くなります。 プルリクエストの粒度が大きいと、1) CIが遅くなり、2) レビュー依頼するまでの時間が空いて忘れがちになり、3) レビュー量も多くて時間がかかるという悪循環に陥ります。 そこでプルリクエストを作る側はどうにかこれを避けようとする力学が働き、CIが高速であれば作業内容に集中し、レビュー指摘の反応や修正も楽になっていくのです。 プルリクエスト / レビューに反応する 前述の通りNxの依存管理を基盤としてCIを高速化していますが、Findy ではレビュー依頼やレビューコメントなどGitHubでのやり取りをSlackに移植してコミュニケーションのトリガーを通知しています。 実際のSlackの画面はお見せできませんが、以下のようなタイミングでSlackに状況が実況され、レビュー依頼が来た場合は通知もされます。 プルリクエストを作った時 プルリクエストにコメントされた時 プルリクエストがApproveされた時 プルリクエストをマージ(クローズ)した時 またGitHub標準のSlackアラート機能も併用していて、レビュワーにアサインされたままのプルリクエストがあれば1時間ごとに通知されます。 これによって「レビュー依頼に気づかなかった」状況を減らし、レビューが放置ぎみのときには「なにか事情があるのかな?作業に入れない状況かな?」と察したり、レビュワーを変更するなどの対処もできます。 このSlack Appは弊社テックリードの github-to-slack-notification をベースに構築されています。 Findy謹製のSlack通知App プルリクエストを分類する Findy Team+ は、開発メンバー、開発チーム、リポジトリ、プルリクエストのラベル、日時やカレンダー情報などの複数の条件をディメンションとして、個人やチームのリードタイムやアクション数などのパフォーマンスを計測できます。 プルリクエストは機能開発やリファクタリング、バグ修正、ドキュメンテーションなど内容が様々になってしまうため、パフォーマンスがどのような部分で発揮されているかを分類するのは非常に困難ですが、Team+ではプルリクエストのラベルを利用して一定の分類ができるようにしています。 しかし一方で、「プルリクエストにラベルをつけておく」という作業を定常的に、すべてのエンジニアが、漏れなく、間違いなく、実施していくのはプルリクエストの分類以上に困難なことでしょう。 Slackを見返すと入社3日目の自分がいきなり本質をついています。 ラベル運用について気づくshoota そう思っていたときが私にもありました。 Findy Team+のフロントエンドのプルリクエストは自動でラベルをつけています。 そもそもgit上の全てのコミットは Conventional Commits に則るよう、 commit lint で制約を設けています。 そしてプルリクエストのタイトルもConventional Commitsの形式にするようにルール化しているので、プルリクエストのタイトルにはこれらの接頭句が必ずあり、これを検知してGitHub Actionsで分類、対応するものにラベルをつけるようにしてます。 プルリクエストの種類は、タイトルから自動で分類させておく デプロイする 小さなプルリクエストが無事にマージされたら、デプロイしていきます。Team+ フロントエンドは、GitHub Actionsの schedule cronを利用して一日に2回定期デプロイをしています。 gitはgit-flowをベースにした運用をしつつ、プルリクエストテンプレートにリリース時に必要な確認項目を入力する欄を設け、リリース時にはこの確認項目を自動生成するようになっています。 まずはgitの運用フローを簡単に図式化してみました。 ブランチ運用 ※ の部分はリリース用プルリクエストのcommit hashをmasterからdevelopへ移動するための操作で、基本的には差分は発生しないものです developブランチを定時間でリリース用ブランチに派生して、ステージングにデプロイします。 このときの主なチェック項目として、 バックエンドで先行するプルリクエストがないか(ある場合はそのプルリクエストのリンク) APIレスポンスの変化やエラーハンドリング、後方互換性など、開発者のみが確認できる確認項目がないか 実装機能と想定仕様の合致など、機能リリースのためのQAが必要でないか をプルリクエストテンプレートで記載するようにしており、リリースプルリクエストにはこれらすべてを列挙して簡易的なリリース判定を行っています。 まとめ 今回は Findy Team+ の開発フローに焦点をあてていくつかの要素をご紹介しました。 これ以外にもさまざまなツールやサービスを利用して品質とスピードを両立させるための開発基盤を持っていますが、ひとことではお伝えしにくいものもあるので、それぞれより詳細な記事でご紹介して行ければと思います。 スピードを意識したフロントエンド領域の開発環境として高いレベルで整備し、可視化して改善するように心がけています。 自分の開発能力、スピードをフルに発揮したいという方は、ぜひ下の採用情報もごらんください。 herp.careers
アバター
こんにちは、ファインディ株式会社で機械学習エンジニアをしていますsasanoshouta( @Edyyyyon )です。この記事は、言語処理学会第30回年次大会(NLP2024)に社で初めてプラチナスポンサーとして参加してきましたので、その参加報告になります。 NLP2024とは? 言語処理学会第30回年次大会(NLP2024)は,2024年3月11~15日の期間,5日間の日程で開催いたします.チュートリアルは3月11日午後1時に開始,本会議は3月11日午後4時半から14日午後7時までの4日間です.現在,現地とオンラインのハイブリッド開催の形態で準備を進めています.現地とオンラインの両方から参加し,発表・聴講・議論をすることができます. *1 大会概要は引用文の通りで、今年は神戸ポートアイランドの神戸国際会議場で開催されました。 参加の背景 今回初参加となりますが、スポンサーするに至った背景は以下の通りです。 機械学習、データサイエンスを初めとするデータ系職種・界隈への認知拡大や打ち手が足りておらず、その足がかりとしてのスポンサード ファインディでもデータ系職種を絶賛募集しているが、そもそも機械学習やデータサイエンスにも取り組んでいる会社であるとの認知が広げきれていないので、「何を?なぜ?どのように取り組んでいるのか?」を知って頂きたい 「エンジニア開発を支援する企業」であることをアピールできている一方で、実は内部でデータ活用・機械学習を使っている事の認知を広げられていない背景があり、まずは知って頂きたいと言う事で、今回スポンサーとして参加してきました。 会場の雰囲気 前述の通り、弊社ではNLP2024を含む学会への参加経験が全くなかったので、過去のNLP202X年度の雰囲気や、他社さんの過去参加記事を参考に準備を進めていました。また、私自身や今回同行したメンバーの中にも学会参加経験者が数名いた事もあり、普段弊社が参加するカンファレンスイベントなどよりも少しかっちりとした準備を進めていました。いざ当日会場に着いてみると想像していたよりもラフに参加できそうな雰囲気でした。(筆者が最後に参加していた頃の学会がX年前で、真面目な雰囲気の印象があった為か、時が流れて参加しやすい雰囲気になっているのは驚きました。) ポスターセッションの雰囲気 弊社スポンサーブース こちらの画像の、掲示スペースが少しもの寂しげなブースがファインディのスポンサーブースになります。ポスターの用意が間に合わなかった為、苦肉の策として弊社のデータ系職種採用資料を印刷して掲示していました。 弊社スポンサーブースの雰囲気 どうしてこんなに寂しくなってしまったのかと言うと、もともと筆者がポスター準備担当だったんですが、直前の体調不良により作業を進める事ができず、敢えなく準備期間が過ぎ去ってしまった為でした。しかたない側面はありますが、沢山の方とお話できたので伸びしろと捉えて次回参加時こそは掲示物を作って参加したいと思います。 スポンサーブースでお話したこと 今回は、弊社データソリューションチームの採用資料から、機械学習による取り組み事例をいくつか持参し、モニターに投影しながらこられた方に弊社のデータ活用先とその実現方法について紹介をさせていただきました。また、言語処理学会と言う事もあり、実際に社内でも検討しているNLPも取り入れた今後の方向性も反映したものになっています。採用資料から2つ抜粋して簡単に紹介します。 1つ目は「LLMを用いたキャリアサマリの作成」です。👇 LLMを用いたキャリアサマリの作成 1年ほど前の取り組みになりますが、OpenAI API公開後に活用施策第1弾と言う事で、1週間でのリリースを目標に作成した機能になります。 職務経歴書などの情報を入力すると、それを要約して二つ名をつけてくれると言った機能でした。 私の場合は、「AIの魔術師」「AIのキラーコンサルタント」と言う名前をつけてくれました。 2つ目は「行動ログを活用した転職意欲や志向の検知」です。👇 行動ログを活用した転職意欲や志向の検知 こちらの機械学習モデルは、転職意欲が高いにも関わらず、プロフィール上転職意欲が低いままになってしまっている方向けの機能としても使うことができますが、どちらかといえば 転職活動の意欲がないのにスカウトが送られてくる 事での煩わしさを軽減する防御の役割を持った機能として運用しているものになります。 プロフィールのステータスは転職意欲が高いままになっているが、実際には 転職活動が完了したままステータスを変更するのを忘れてしまっている というケースがあったりします。 そうした方に、スカウトを追撃してしまうと転職サービスとしての不信感に繋がりかねないので、事前に予防できるものは出来る限り予防するようにしています。 ブースに立ってみて 当初想定していたよりも多くの方がブースに来てくださり、筆者もブースに立って意見交換をさせて頂きました。ブースに聞きに来て頂いた皆様ありがとうございました。 ファインディ自体が「 エンジニアに特化した中途転職サービスを中心に事業を展開している 」事と、学会に参加されている方々の属性が、 機械学習・データサイエンスを生業とされている社会人参加の方 大学・大学院大学から学生参加の方 の2属性の方々がメインであった事と相まって、「 ファインディ株式会社 」と「 何をしている会社か? 」の知名度にはかなりの伸び代を感じました。一方で、完全アウェーだった訳でもなく、「 スキル偏差値の会社 」として認知いただいている方が多かったです。データ界隈での機能とサービス・会社名の繋ぎ込みにまだまだ課題を残しつつも、機械学習・データサイエンスの界隈にも一定取り組みが届けられている事を感じられました。 個人的な聴講セッションの感想 スポンサーとしてブースに立つ傍ら、いち聴講者としてセッションをいくつか聞いたり他社スポンサーさんの企業ブースにお邪魔してお話を伺わせていただいたりしたので、メモベースにはなりますが個人的な感想を書き連ねておきます👇 オーラル・ポスターセッションそれぞれに共通して言えたのは、大前提 LLMに関する研究発表である 事がほとんどでした。 だからと言って、 OpenAI API をそのまま使って研究をしていたり、サービス実装してコア機能としている企業さんや研究もほとんどないような印象でした。 リクルートさん、サイバーエージェントさんなどのテキストデータを潤沢に持ち合わせており計算資源も豊富な企業でも、一部プロセスに取り入れられているとお聞きしました。 社内向けに、全社の業務効率化を目的としてRAGや文章埋め込み(embedding)を使い、LLMの弱点であるhallucinationを低減した仕組みを取り入れたお問い合わせbotを実装・運用している。 様々お話を伺った所、現在のLLM界隈のトレンドでは、お問い合わせbotのような活用がトレンドとなっていそうで(個人の見解)、このような流れはしばらく続きそうな雰囲気を感じた。 一方で、勢いが若干失速した感はありましたが、 自社専用のLLMをスクラッチで開発する という企業さんのお話もいくつか伺えました。 「ChatGPTとかClaude3とか低価格で高性能なAIが出てるし、今後もその流れは変わらないはずなのになぜ?」 と思い、お話を聞きいてみました。 自社でLLMを作っておく事で、GAFAMOが提供するLLMの規約が変わった時のリスクヘッジになる との方針で、研究をやめていないとの事。 どの企業さんにも共通していたのは、1つ自社のLLMを作れておくと用途に合わせて柔軟にカスタマイズができる点も、内製化のメリットの1つとの事でした。 為になったセッション 全てのセッションが興味深く考えさせられたり、明日使えるものたちが多数でしたが、個人的に1番勉強になったセッションを共有します。全体の発表スケジュールは こちら から。 文章のチャンクに基づく知識グラフを活用したRAG(産総研さん) 元論文は こちら から RAGを使ってLLMの回答精度を高める為の取り組みはいくつもありますが、LLMに与えられるクエリにcontextを付与する為に知識グラフをDBとして構築しておき、知識グラフからの情報検索プロセスをRAGに組み込む、と言うものでした。弊社でもRAGを用いた質問回答botを作って運用したりしており、オーソドックスに類似度計算した上位N件から回答を作成すると言うシンプルな構成を取ったりしています。こちらの研究にある通り「クエリの文脈はすべて類似度で測れるとは限らない」と言う事を痛感しているので、こちらの研究を参考にしてみたいと思いました。 参加してみての感想 初めて言語処理学会にスポンサーとして参加してみて、やはりデータ系職種・界隈での認知拡大の伸び代がある事を強く実感しました。 その理由はいくつかあると思いますが、これまで今回のようにデータ系職種の方が集まる学会やカンファレンスに積極的に参加していけてなかった所が大きいと感じました。 もちろんこれだけではなく、社内でもデータを活用した取り組みは沢山動いたりこれから始まったりしている最中なので、そうした取り組みをもっと積極的に発信する事で、より多くの方にファインディを知って頂きたいなと思います。 いち参加者としても、短い期間でまとまった数のNLPに関する研究発表を自分の五感で感じる機会は中々なかったですし、多種多様な取り組みや企業さんとお話できてとても良い刺激になりました。すぐに試せそうなノウハウを沢山得ることもできましたし、忘れないうちに現在の取り組みの参考にさせていただこうと思いました。 今後は、言語処理学会をはじめ学会へのスポンサー、ポスター発表などにも力を入れていきますので、どこかで見かけた際は何卒よろしくお願いいたします。 さいごに ファインディでは、機械学習エンジニア・データサイエンティスト・データアナリストを絶賛採用中です。以下のページから応募頂けますので、興味のある方は是非カジュアル面談などでお話しましょう。 findy-code.io findy-code.io *1 : ※ NLP2024公式ページ より抜粋
アバター
1. はじめに Findyでデータエンジニアとして働いている ひらき( hiracky16 )です。 この記事ではFindyで取り組んでいるデータ基盤について紹介します。 Findyでは2023年からデータエンジニアを採用し本格的にデータ基盤構築に着手しています。 これまではBigQuery(Google Cloud)を中心としたデータ蓄積・利活用をしていました。 今後もっとデータ分析、機械学習などのデータ利用を加速するためにデータマネジメントが不可欠だと考えており、データエンジニアを採用しています。 まだ1人目のデータエンジニアがジョインしてから半年間くらいの取り組みですが、現時点のアーキテクチャや技術スタック、伸びしろや展望などを記します。 1. はじめに 2. これまでのデータ基盤の伸びしろ 3. 現状のデータ基盤アーキテクチャ 3.1. 本番環境のIaC化と開発環境の準備 3.2. データロード系のツール刷新 3.3dbtからDataformへの変更 3.4. データを4層で管理 4. 今後やりたいこと 4.1. 全体を統括するオーケストレーションツールの導入 4.2. データ基盤の利用者拡大に向けたルールと権限 4.3. 複数部門またいだデータ基盤の設計、構築 5. 終わりに 2. これまでのデータ基盤の伸びしろ 僕が入社する前のアーキテクチャがこんな感じです。 プロダクトのRDSからEmbulkを使って1日1回必要なデータをBigQueryへ転送していました。 プロダクトのデータだけでなくGAイベントデータを蓄積していました。 昨年からTransformのツールにdbtを導入しており定期的に実行されるクエリを徐々にdbtへ移行している状態でした。 データ利用で言うと定期的に見るべき数値はLooker Studioで可視化したり、GASからBigQueryへクエリ発行してスプレッドシートで表示しています。 また別Google Cloudプロジェクトにある機械学習用のデータセットにコピーもされていました。 上記を踏まえて現場の課題感やアーキテクチャ図を見ての客観的な伸びしろをまとめてみました。 Embulkなどデータロード系のジョブが失敗した場合のリカバリに負荷がかかっている dbtを使ったクエリが増えない スプレッドシートとGASで実行しているクエリの正確性が担保できていない データソースの変更に対する影響範囲が見積もれない(データリネージが追えない) データ基盤と機械学習用の検証環境がないため新規開発やアップデートにハードルがある 機械学習のプロジェクトとデータ基盤のプロジェクトが別になっておりデータ鮮度が異なる 3. 現状のデータ基盤アーキテクチャ 3.1. 本番環境のIaC化と開発環境の準備 まず取り掛かったのが本番環境のIaC化でした。 上記に示したアーキテクチャ図を書く前に本番環境の主要なリソースをTerraformにインポートしてコード管理できるようにしました。 その過程で不要なリソースを整理でき、本当に必要なものだけを見極めることができます。 おまけにコスト削減にも繋がります。 一通りTerraformへの書き起こしが完了したら、あとは開発環境のGoogle Cloudプロジェクトを作りTerraformを適用するだけです。 データに関しては1日1回、Data Transferでデータセットごとコピーしています。 開発環境に本番環境相当のデータとGoogle Cloudリソースが揃ったので、後に紹介するDataformを使った定期実行クエリの開発を増やしています。 これによって本番環境にて検証用テーブルができたり、間違えてテーブルを消してしまうなどの問題を減らせたと思います。 3.2. データロード系のツール刷新 データを取り込むツールとして trocco と Datastream を採用しました。 troccoはもともと別チームで管理しているものに相乗りさせてもらう形で使っています。 MAツールや他のクラウドサービスといった様々なデータソースに対応可能なため重宝しています。 またロードだけでなくReverse ETLにも役立っており、作ったデータマートを別サービスに読み込んで活用しています。 DatastreamはCDCのサービスでサーバレスなので運用に手間がかからない点でEmbulkの代わりに採用しました。 一方でリアルタイムにソースが変わるため集計のたびに数値が変化するため、問題発生時の原因調査が困難になりました。 現状運用上でカバーできていますが、再現性と説明の容易さを向上させるべく集計に使ったデータを別で持つべきか悩んでいるところです。 またスプレッドシート上で管理しているマスタデータにも対応すべくBigQueryの外部テーブルとして扱っています。 3.3dbtからDataformへの変更 データ変換のためのツールをdbtから Dataform へ変更しました。 dbtはDataformに比べて開発が活発で、ライブラリが充実しているため採用しました。 この前提でdbtにクエリや知識を集約させるべくBigQueryのユーザーを巻き込み利用を促していましたが、なかなかモデル(テーブル)の数が増えませんでした。 理由として2つのハードルがありました。 1つ目がBigQueryでクエリを記述後エディタを開き、dbt 用に書き足す一手間かかってしまうことが大きなハードルになっていること。 2つ目はdbt側の制約(主にモデル名の一意制約)やデータ基盤側の設計から定めたルールが気軽にコミットしづらい状況を作ってしまいました。 これらのハードルをクリアすべくDataformの利用を検討しました。 Dataformはブラウザで完結しBigQueryのメニューにあるため多少ツール間の移動コスト軽減されます。 かつDataformにはモデル名の一意制約がなくBigQueryと同様にデータセット間で被らなければ同名のモデルがプロジェクトに複数存在しても問題ありません。 導入した結果、モデル数はdbtプロジェクトに比べて3倍ほどできており、実際に使いやすいという声もあるので一定成功だったのかなと思っています。 Dataformからdbtへ乗り換えた話は見聞きしたことがありますが、dbtからDataformへのケースは見たことないので一定期間経ったらまた振り返りの記事を書こうと思います。 3.4. データを4層で管理 参考にしたのはdbtのベスプラの1つである「How we structure our dbt projects」です。 dbtをツールとしては不採用にしましたが、考え方は利用させてもらっています。 🙏 docs.getdbt.com 当初3層(lake/warehouse/mart)で作ろうとしていましたが、データソースに対して直接クエリしようとするとBigQuery上で不都合なことがありました。 例えばDatastreamで転送してきた日時のデータがすべてDATETIME型になってしまい、TimeZone を考慮した計算ができませんでした。 毎回TIMESTAMP型に変換する処理をwarehouse層に書かせるのも厳しいのでstaging層を設けて型変換などの簡単な変換をすることにしました。 4. 今後やりたいこと 4.1. 全体を統括するオーケストレーションツールの導入 現在、データ抽出と読み込みはtroccoやDatastreamで行われますが、Dataformによる変換はその読み込みが終わった頃を見計らって実行しています。 もしtroccoによるデータロードが失敗した際にDataformによる変換が実行されてしまうので、データを閲覧する方が古いデータを見てしまう可能性があります。 また現状troccoやDataformそれぞれでエラー検知の仕組みを備えており、日常業務の監視に一定コストがかかっています。 データの抽出から提供までの流れを効率的に管理・監視し、運用コストをかけずに行うためにもオーケストレーションツールの導入が今後必要です。 4.2. データ基盤の利用者拡大に向けたルールと権限 せっかく作ったのでもっと新しいデータ基盤を使ってもらいたいのですが、ルールがないとせっかくの設計が腐敗してしまいます。 例えばGASから直接クエリを発行することはSQLの内容がGASに閉じてしまいメンテができなくなってしまうので新環境では禁止していきたいと考えています。 4層のアーキテクチャも開発上意識しなくてはならないルールなので、なぜ必要なのか理由とともに作るつもりです。 また、適切な権限や公開範囲の設定も必要です。 どのチームがどの範囲のデータセットを扱うことができるか整理しないと予期せぬ変更をしてしまうなどの事故につながってしまいます。 皆が安心して使えるデータ基盤にするためにも適切な権限設定やルール作りが急務だと考えています。 4.3. 複数部門またいだデータ基盤の設計、構築 最後に壮大な話をして終わりたいですが、複数部門でのデータ基盤運用を今後やってみたいと考えています。 実は今まで説明してきたのは弊社の一事業部内での話で弊チームでは他事業部とはあまりまだ関われていない状況です。 エンジニア領域の事業をやっており事業部間のドメインは近いのでデータ文脈でコラボレートできることはあると考えています。 また事業部別で使われるマスタも数々存在しており共通化すると横断してデータ利用できる土壌が整うと考えています。 そのためには複数事業部のデータ基盤を管理するための設計、ルールと開発・運用を担当するデータエンジニアが圧倒的に足りていません。 5. 終わりに 以上がここ半年間で整いつつあるファインディのデータ基盤アーキテクチャと技術スタックの紹介でした。 やりたいことにも挙げましたが、データの攻守においてエンジニアが足りていない状況です。 エンジニアのためのデータプラットフォームを作るためにも、少しでも興味が湧いた方はカジュアル面談お待ちしております。🙏 herp.careers
アバター
こんにちは。 FindyでTech Leadをやらせてもらってる戸田です。 昨年(2023年)、 Findy Team+ にて、4名で3ヶ月ほどかけて大規模なフロントエンドの設計刷新を行いました。 Findy Team+はエンジニア組織のパフォーマンス向上を支援するSaaSサービスで、2020年から開発がスタートしました。 3年以上の間、機能開発を行ってサービスを伸ばしてきましたが、同時に様々な課題も生じていました。 今回はそこに至るまでの経緯と、実際に行ったことを紹介します。 なぜフロントエンドの設計刷新を決断したのか 当時、自分は他のプロダクトの開発チームでコードを書いていたのですが、ある日Findy Team+の開発チームへ異動することになりました。 異動後に2週間ほどFindy Team+のフロントエンドの開発をしたのですが、あることに気づきます。 コード設計が思ったより複雑かもしれない 異動前後で理解のしやすさやプルリクを上げるまでの時間に差があるように感じたので、Findy Team+での自分の生産性の数値を比較してみることにしました。 すると、異動前と比べて自分のアウトプットの量が半分以下まで下がっていることが明らかになりました。 感覚値と実際の生産性の数値が一致したため、どこかしらに何か問題があるのでは?という仮説を立てました。 異動前後での変化を洗い出してみた結果、コードの設計に問題がある高いことを突き止めました。 しかし、コードの設計を刷新しようにも、そこには大きなコストと時間が掛かります。 その大きなコストを、異動前後の生産性低下の感覚値だけで周りの人間を納得させることは不可能です。 そこで、今のコードの設計の問題点を洗い出して、何がどう問題で生産性が低いのか具体的な洗い出しに着手しました。 問題点の洗い出し 過度な共通化 まず全体的に過度な共通化が行われていました。 例を上げると、グラフやテーブルに数値を表示する際に表示するcomponent内で、データ取得も同時に行っていました。 こうなってしまった場合、グラフやテーブルの見た目は同じだけど表示するデータが異なる場合に対応できなくなります。 このような複数責任を持ったコンポーネントが幾つも存在していたため、コードリーディングやデータの流れを追うことが非常に困難になっていました。 データの取得と描画は責務が異なる処理なので分けて実装するべきでした。 処理に一貫性がない APIの呼び出しに関するルールが存在しておらず、複数個所から色々なタイミングで呼び出されており、データの流れを追うことが非常に困難になっていました。 前述した過度な共通化がこの問題を引き起こしており、1つのcomponent内で全てのことを処理しようとしていました。 データ取得と描画が密結合で実装されているので、この部分は共通化してるのでcomponent内でデータ取得して描画してるけど、この部分は共通化してないからデータをprops経由で貰ってきてる。といったような状況が多発していました。 これにより、どこからデータを取ってきているのか探しに行く作業が多発し、コードリーディングに必要以上の時間を取られているような状況でした。 テストコードを書きにくい 過度な共通化によりデータの取得と描画が同時に行われていたため、責務の分担がほとんどできていない状況でした。 そのため、テストコードを書きにくい状況にも陥っていました。 描画に専任するべきcomponentの中でデータ取得もしているせいで、データ取得部分のモックを用意しなければテストができず、テストコードが必要以上に肥大化していました。 設計刷新に対する認識合わせと合意形成 メンバーとの認識合わせ Tech LeadやCTOが「やってほしい」と言って作業してもらうことは比較的簡単ですが、自分たちで「やる」と決意してやることは価値が大きく違います。 ある程度の問題点を洗い出すことが出来たので、これを元にメンバーと意見交換をすることにしました。 この時メンバー全員を一同に集めて話すのではなく、メンバー1人ずつ時間を取って話をすることを決めました。 メンバー全員を一同に介してこの手の話をすると、声が大きいメンバーの意見が反映されがちだと考えたからです。 真に自分たちで「やる」と決意して貰いたかったので、1人ずつ時間を取って本音を聞くことにしました。 フロントエンドのメンバー全員と1on1で話を聞いてみた結果、現行の設計に対する意見と感覚値がほぼ一致していました。 ずっとリファクタを入れたかったけど、この規模まで来るとリファクタ自体に時間が掛かりすぎてしまう 機能追加に時間を取れなくなってしまうので、リファクタをやりたくても言い出せなかった 今の設計の状態のまま、更に開発スピードを上げていくのは難しい これから先の開発スピードを更に加速するためにも、フロントエンドの設計刷新は必要不可欠であるとチーム全体で結論が出ました。 経営陣との合意形成 そこで経営陣やPdMのメンバーと、設計刷新に対する合意形成を作りに行きました。 全体的に作り直す必要があるため、新規開発を可能な限りストップして、一定期間を作り直しに集中する必要があります。 これに関しては大きな反対意見が出ることもなく、比較的スムーズに了承を得ることが可能でした。 議論したのは、どのくらいの期間を新規開発ストップするかどうかくらいです。 なぜ大きな反対意見が出なかったかと言うと、 以前にも同様のシステムの設計刷新 を行ったことがあり、それに対する成功体験が大きかったためです。 確かに大きなコストは掛かりますが、比較的早い段階でそのコストを回収できたという成功体験があり、リファクタや設計刷新に対する抵抗感が比較的低い点は弊社の良い点です。 過去の成功体験と現在の状況を比較し、掛かるコストと回収期間を提示できたため、比較的スムーズに了承を得ることが可能になりました。 着手前の準備 新設計の方針を固める 新設計の基本方針として、多少冗長となっても構わないので共通化を最小限に留めることとしました。 最初から共通化して実装するのではなく、実装後に共通化するべきかどうかを議論し、その議論が通ったものだけ後から共通化対応することにしました。 また、コードの責務を明確にし、必要以上のことを1つのファイル内で実行しないことを徹底しました。 更にcomponentとロジックを分離することを基本とし、依存関係を単方向にさせました。 データ取得と描画の処理を明確に分け、描画に必要なデータは全てpropsリレーで受け取ることを義務付けました。 propsリレーが長くなるとツラくなる可能性もありますが、責務が混在してテストコードを書きづらくなることと比べたらマシという判断です。 小さな画面を新設計で1つだけ作り直してみる 新設計の方針がある程度見えてきたタイミングで、簡単な画面を1つだけ作り直して、メンバーに方針を展開することにしました。 方針を文字や口頭で説明するよりも、実際のコードを見てコメントベースで説明する方が理解しやすいからです。 そこから新設計に対する意見をメンバーから貰い、1ヶ月程度で方針が固まりました。 実際の作り直しの流れを決める 実際に本番環境が動いており、多数のクライアントが利用している状況だったので、次の3つを大原則に掲げました。 現状の機能を維持する 現状のスタイルを維持する 安全に移行する ページ単位で作り直しを進め、APIは既に利用しているものを使い回すことを決定しました。 作り直しの流れ 基本的な作り直しの流れは次の通りになります。 同じ画面を別URLで実装 既存画面のコードに手を加えるのは基本NG 一時的に同じ画面が異なるURLで公開される 既存画面と異なるコードで実装しているので、Pullrequestをガンガンmergeできる 新設計での実装が完了後、本番環境で動作確認を行う 動作確認がOKであれば旧設計のURLのルーティングを新設計の画面に向ける 新画面で何かしら不具合が発生した場合は、ルーティングを戻すことですぐに切り戻しが可能 一定期間様子を見て、問題なさそうなら旧実装のコードを全削除 この流れにより、旧実装の画面のことを気にすることなく新設計のPullrequestをmergeすることが可能になり、問題が発生しても切り戻しが容易になります。 振り返り 結果として新設計のコードへの移行完了後のチーム全体の生産性が、前年比で2.5倍程度まで上がりました。 作り直しやリファクタ、設計刷新を提案する前に、まず感覚値と実際の数値を見比べ、メンバーと認識合わせをすることが重要です。 また、経営陣を始めとした決裁権がある人間を納得させるために数字は必要不可欠です。 成功体験があれば次の提案は思った以上にスムーズに進みますが、一番最初の成功体験を作ることは非常に難しいものです。 小さくてもいいので数字を出し、小さな成功体験を多く詰むことが重要です。 まとめ いかがでしたでしょうか? リファクタや作り直し、設計刷新を検討している方の参考になれば幸いです。 現在、ファインディでは一緒に働くメンバーを募集中です。 興味がある方はこちらから↓ herp.careers
アバター
こんにちは、ファインディで Findy Team+ (以下Team+)を開発しているEND( @aiandrox )です。 私が入社したのが2023年2月だったのですが、気がついたら1年間が過ぎていました。 せっかくなので、自分がこの1年でやったこと、感じたことを通してファインディの開発組織について知っていただけたらと思います。 1年でやったこと Team+の画面ベースで振り返る 入社から1年1ヶ月(2023/2/1~2024/2/29)のアウトプットについては以下のようになっています。 プルリク作成数:1229件(4.8件/日) コミットからオープンまでの平均時間:4.2h オープンからマージまでの平均時間:10.3h アウトプット量自体は、エンジニアの中では多めの部類だと思います。ただ、画像上部のアクティビティの推移を見るとわかる通り、とてもばらつきがあります。 開発の他にも下記業務を担当しているのと、外部連携サービスのAPI調査やQAなどのプルリクエストを伴わないタスクもあるためです。 問い合わせ対応 アラート調査 障害対応 リードタイムに関しては以下のようになっています。 外れ値の影響を受けていますが、それ以外の箇所では入社当初より現在の方がリードタイムが減少しています。現在は、開発に集中しているときのリードタイムはある程度安定するようになりました。 日頃から開発のパフォーマンスを上げるために意識したのは以下の点です。 事前に設計レビューやタスクを見てもらうようにする descriptionでタスクの流れを書いておく レビュー後のリードタイムを短縮する 事前に設計レビューやタスクを見てもらうようにする 設計に関しては、イシュー内で確認することもあれば、事前にDraftプルリクを作成してレビューしてもらったりします。 これによって、手戻りを減らすことができました。また、事前に見てもらうことでレビュアーの負荷を下げることもできました。 descriptionでタスクの流れを書いておく プルリクを細分化する関係上、descriptionを書く手間が増えます。レビュアーの負荷と自分の手間の間を取った結果、自分はよくこのフォーマットを使っています。 タスク1 ↓ タスク2 ←イマココ ↓ タスク3 レビュー後のリードタイムを短縮する 基本的には、ファインディのエンジニアはレビュー依頼からレビューまでが爆速です。しかし、入社当初は自分がレビューを受けてから再レビュー依頼をするまでに時間がかかっていました。そのため、レビューされたときに別のプルリクで作業をしていたとしても、レビューへの対応を優先するようにしました。 また、プルリクをすぐにマージする必要がなかったとしても、レビュアーのカレンダーの予定を見てレビュー依頼を個別でメンションするようにしました。 ファインディでは爆速レビューis正義の価値観があるので、圧はあまりない……はず。 プロジェクトベースで振り返る この1年で、主に以下のプロジェクトに関わりました。どれもTeam+の根幹の機能で、アーキテクチャの理解が深まりました。また、後半はプロジェクトのリードに挑戦できました。 プルリクのレビューロジックの変更 多言語化対応 のバックエンド全般とフロントエンド少し GitHub連携をOAuth AppからGitHub Appに移行 Bitbucket Cloud連携 のバックエンド 振り返ってみると、この1年は連携処理をメインで開発していたようです。 プロジェクトの中で、サービスに応じてどういうアーキテクチャにするかだとか、既存の設計だと無理がある箇所なども改修しつつ進められています。設計をどうするか考えるのは自分も好きなので、そういったことを任せていただき、壁打ちや相談させてもらえるのがとてもいい経験になりました。そして、すでに若干設計のつらみを感じています。これを次に活かすのだ……。 また、プロジェクトの進め方についても学びがありました。Team+では、大きめの開発は、PdMが企画を行う→エンジニアとすり合わせつつ仕様をまとめる→開発→QA→リリースという流れになっています。 そのため、調査段階からPdMと認識のすり合わせを行いつつ、開発着手後に出てきた懸念点などは適宜PdMに共有するようにしました。また、QAでも開発者QAとQAチームによるQAをどう担当していくかなどを調整するようにしました。結果として、それぞれのプロジェクトに反省点はあるものの、都度リカバリーできるような開発体制にはできました。 イベント参加 特に記憶に残っているのは以下のイベントです。今までは小規模のオフラインイベントに入ったことがあるものの、大規模なカンファレンスには参加したことがなかったです。 ファインディでは、エンジニア系イベントへのスポンサーや積極的に自社イベントを開催しているので、運営を手伝いつつ参加する機会やLTなど登壇させていただく機会を得やすいです。 RubyKaigi 2023 RubyKaigiはずっと気になっていたのですが、有給を取るのはハードルが高く、2023年に初めて参加しました。思っていたよりも技術的なハードルは低く、わからないとわかるの間を楽しめました。また、カンファレンス中のイベントも多く、たくさん交流ができたのが貴重な経験となりました。2024も行くので、出会った方はよろしくお願いします。 また、 After RubyKaigi で初めてのLTをしました。初参加のパッションでやりましたが、次回は技術的なことを試してみた、みたいなのをやりたいです。 開発生産性カンファレンス 2023年、ファインディでは2回の開発生産性カンファレンスを主催しました。私はTeam+を開発しているのもあり、ドメイン理解を深めるために参加しました。特に役割もなく、一参加者として楽しませていただきました。 dev-productivity-con.findy-code.io こちらのカンファレンスは、開発生産性に関する理論的なセッションが多かったです。書籍などでなんとなく頭にあることがつながったり、今まで友人のエンジニアに聞かれたことについての転換的な話もあり、「そういう考え方があるのか」と気付きを得たりしました。 特に、SLIを決めることで許容可能な不具合の量(エラーバジェット)が決まるので、それは通常の運用の障害ダウンタイムとして使ってもいいし、挑戦的な取り組みによってのダウンタイムとして使ってもいいという考え方が目から鱗でした。 findy.connpass.com こちらのイベントでは、具体的な取り組みを中心に聞きました。全社的に文化を根付かせるためにどうするか、といった啓蒙活動の取り組みが印象に残っています。 経営層・ビジネス部門への理解促進を促し、ステークホルダーを巻き込みつつ成果を出して価値を示すことを積み重ねていました。取り組みを泥臭くやっていくしかない中で、Team+は成果・価値を示すためのツールとして使われていることを感じました。 その他オフラインイベント ファインディ主催のイベントを中心に、さまざまなオフラインイベントに参加しました。ホームなので安心感があり、気軽に行きやすかったです。 オフラインイベントのいいところは、オンラインでは話しづらい内容を聞けることと後半の交流だと思っています。イベントを通して、いろんなエンジニアの方と話すことができました。その中では、Team+を使っているエンジニアの方もおり、生の声を聞けたのがよかったです。機能の要望だったり、Team+への感謝などをいただけて、日頃の開発のモチベーションになりました。 1年で変わったこと 組織の拡大 入社時は社員数も120人くらいでしたが、現在は200人を超えました。エンジニアも増えて、今年からTeam+のエンジニアは2チーム体制になりました。チーム編成としては、外部サービス連携に注力するチームとその他の機能を開発するチームです。 qiita.com また、Bizサイドの人数が増えていくに従って事業全体の勢いを感じています。メンバーがどんどん入社し、爆速オンボーディングですぐに立ち上がっていて本当に尊敬です。 そして、自分が作っているプロダクトの価値をたくさんの人に知ってもらえているのが純粋に嬉しいです。 組織の拡大に伴って課題も生まれた 単純に人数も増え、開発チームとしてできることも増えました。その中で、チームの構成や、プロジェクトの進め方については手探りの状態です。 現在、チームリーダーを中心に、いろんなやり方を試しつつよさそうなやり方を探っています。改善サイクルを回していきながら、その時々に適したチーム・開発体制で進めていけるようにしたいです。そのためにも、自分の視点からもたくさんアイデアを出していきたいです。 その他には、以下のような課題も出てきました。これは現在時間を取って対応しているところです。 Bizサイドの増加に伴い、エンジニアへのプロダクトに対する技術的な質問が増加 ドキュメントの不足 / 更新されてない 1年で変わらないこと 根本的な社風は変わっていないです。 前向き・誠実・チームワーク・スピード・No.1 のバリュー通り、自分自身がやりたいと言ったことはどんどんチャレンジさせてもらえています。 他のメンバーにサポートしていただきながら、GitHub App, Bitbucket連携をリードできた 自分主導で連携周りの設計の刷新やGitHub ActionsによるOps改善にチャレンジできた 「ISUCONに出てみたい」と1on1で言ってみたところ、社内の有志チームで出場できた( レポ記事 ) 今後の1年に向けて 基本的には、爆速開発しながらプロダクトを成長させるのが一番の目標です。そのためにも、自分自身も成長したいと思っています。 自分ができる幅を広げていきたい これは技術についてもそうだし、技術以外についてもです。ありがたいことに新しいことに挑戦することを歓迎されている組織なので、さまざまな挑戦をしていきたいです。技術的には、設計周りの引き出しを増やすこと、インフラやフロントエンドのタスクをもっとこなせるようになるのを目標にしています。 組織の拡大に伴って生まれてきた課題の解消もやりたい 開発生産性を高めるプロダクトを作っているからこそ、うちのチームは生産性が高いぞ!と胸を張って言える状態でいたいです。 他のメンバーはメインのプロジェクトを進めつつ課題解消の取り組みもしているので、自分もそんな風に動けるようになるのが目標です。現状は、プロジェクトがあるとそっちでいっぱいになっているのでさらなるレベルアップを目指します。 発信も頑張りたい 自分がやったことやそのときに考えたことを残しておきたい気持ちがあります。結果として、ファインディのことを知ってもらうことにもつながるので、三方Winにしたいです。 この記事もそうですが、テックブログを活用していろいろなことを発信していけたらいいなと思っています。なので、こんなことが気になるといったものがあればご意見いただけるとありがたいです。 最後に 現在、ファインディでは一緒に働くメンバーを募集中です! 興味を持った方は、ぜひカジュアル面談で話を聞きに来てください! 採用情報はこちら↓ herp.careers
アバター
FindyでEMをしている栁沢( @nipe0324a )です。 今回は、FindyのとあるRailsのCIのテスト実行時間を10分から5分に高速化した話をご紹介します。 「CIのテスト実行時間が遅い...」 「CIの実行時間を短くしたい!!」 と感じている方はぜひご覧くださいませ。 Findyでは2024年2月現在、1人あたり1日4プルリクを平均で作っています。静的解析や自動テストなどを即時に行うCI環境がないとスピード感のある開発ができなくなるため、CIを高速で回しタスクを完了させる必要があります。機能も増え、テストケースも拡充したことでCIの高速化が求められるようになりました。 また、個人的には、CIは遅くても10分、理想は5分以内で終わるのを1つの目安にしています。これぐらいのスピード感でCIが完了すると、「プルリク作ってレビュー依頼する」、「レビューコメントもらって対応する」といったことがサクサクできます! 1. CIテスト実行時間の高速化の結果 2. テスト実行時間の高速化の前提条件 3. 今回のテスト実行時間の高速化で実施したこと 3.1. 不要なカバレッジレポートの作成をなくす 3.2. テスト実行の並列度を高める 3.3. テスト実行時間の偏りを減らす 4. 最後にGitHub Actionsのコストについて 5. CIテスト実行時間の高速化のまとめ 1. CIテスト実行時間の高速化の結果 最初にテスト実行時間の高速化の結果を紹介します。 弊社では、ソースコードをGitHubで管理しているので、CIツールももれなくGitHub Actionsを使っています。 GitHub Actionsの「並列化の促進」や「テスト実行の偏り」を減らすことで、CIのテスト実行時間を約2分の1にしました。 対応前:約10分 対応後:約5分 また、費用対効果もよかったと考えています。 月間のGitHub Actionsのコストが2万円ぐらい増加 1ヶ月あたりのCI待ち時間が約7日分減る 2. テスト実行時間の高速化の前提条件 そもそも既存でも、CI上のテストは、「5台のマシン」かつ「1マシンあたり4コア」と20並列でテストを実行していました。 テストを20並列で実行するために、GitHub Actionsのワークフローで次のようなテクニックを使っていました。 5台の複数マシンでテスト実行 GitHub Actionsのmatrixを使い5台のマシンを動かす 対象のテストファイルを5台のマシンに分散させる簡易なshellスクリプトを使う 4コアでテスト実行 4コアのUbuntu Runnerを利用する(参考: より大きなランナーの概要 ) parallel_tests を使ってCPUコア数の並列度でテスト実行できるようにする このような対応をしてもプロジェクト規模の拡大とともにCIのテスト実行時間が遅くなってきたので、さらなる改善を実施しました。 3. 今回のテスト実行時間の高速化で実施したこと 今回のテスト実行時間の高速化にあたり、具体的には次の3つを実施しました。 不要なカバレッジレポートの作成をなくす テスト実行の並列度を高める テスト実行時間の偏りを減らす それぞれ効果があったのですが、「テスト実行時間の偏りを減らす」が他の対応との相乗効果をうみだし、テスト実行時間を大きく減らすことができました。 3.1. 不要なカバレッジレポートの作成をなくす 対応前のテストのワークフローを見ると、テスト実行後に「Post coverage report」というジョブでカバレッジレポートをプルリクにコメントしていました。 これは、自動テストを拡充するときに使われていたのですが、既にテストカバレッジは90%以上になっているためほぼ必要ないためリリースプルリク以外では実行しないようにしました。 これで、テストの実行時間が30秒ぐらい早くなりました。 3.2. テスト実行の並列度を高める 次に、マシン台数を5台から10台に変更することで、並列度を20から40と2倍に高めました。 マシン台数の増加は既存で仕組みが揃っていたので、変更は次のように実施できました。 # .github/workflows/test.yml strategy: fail-fast: false matrix: - ci_node_total: [5] - ci_node_index: [0, 1, 2, 3, 4] + ci_node_total: [10] + ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] steps: # 省略 - name: Run tests env: CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} run: | TEST_FILES="$(find ./spec -type f -name "*_spec.rb" | xargs ./scripts/ci/rspec_split_files.sh)" bundle exec parallel_rspec -- --format progress --color -- $TEST_FILES これでテスト実行時間が2-3分ほど早くなり、6-7分ぐらいになりました。 3.3. テスト実行時間の偏りを減らす 最後に、テスト実行時間の偏りを減らす取り組みをしました。 テストの並列度を2倍にしたのに、いまいちテスト実行時間が早くなりませんでした。そのため、どこがボトルネックになっていそうか調べてみると、テスト実行時間の偏りがボトルネックになっていそうでした。 以下の例ですと、「 Test (10, 8) 」が2m25sなのに比べて、「 Test (10,3) 」が5m30sとなっており、テスト実行時間の差が最大3分ほどあります。 さらに、詳細をみていくと、「マシンごとのテスト実行時間の偏り」と「マシン内のコアごとのテスト実行時間の偏り」の両方が発生していました。そのため、次の対応をしてテスト実行時間の偏りを減らしました。 マシンごとのテスト実行時間の偏りの対応 マシンへのテストファイルの振り分けをファイル名からテストファイルのサイズ順に変更 「ファイルサイズ ≒ テスト実行時間」と考えて、時間がかかるテストファイルを偏らないように変更 コアごとのテスト実行時間の偏りの対応 マシン内でコアごとにテストファイルが割り当てられて実行されていたので、時間がかかるテストファイルを割り当てられていたコアの実行時間がかかっていた ファイル単位からチャンク単位でテストを実行するために、 parallel_tests を parallel_split_test に置き換え(※parallel_testsと作者同じ) # .github/workflows/test.yml - name: Run tests env: CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} run: | - TEST_FILES="$(find ./spec -type f -name "*_spec.rb" | xargs ./scripts/ci/rspec_split_files.sh)" + TEST_FILES="$(find ./spec -type f -name "*_spec.rb" -exec ls -l {} + | sort -n -k 5 | awk '{print $9}' | xargs ./scripts/ci/rspec_split_files.sh)" echo $TEST_FILES - bundle exec parallel_rspec -- --format progress --color -- $TEST_FILES + bundle exec parallel_split_test $TEST_FILES --format progress --color これでマシンとコアのそれぞれでテスト実行時間の偏りが減少し、5分以内にテストが完了するようになりました。 4. 最後にGitHub Actionsのコストについて 並列度を2倍に増やしましたが、コストはそこまで高くなっていません。 GitHub Actionsの料金は「OS x vCPU数 x 分あたりの料金」で課金されます(参考: GitHub Actionsの課金について )。今回は、並列度を2倍に増やしましたが、Billable timeは30分前半から40分ぐらいと1.2〜1.3倍ぐらいなので、コストも1.2〜1.3倍ぐらいの増加になっています。 1ヶ月単位だと、「 ざっくり2万円ぐらいのコスト増加(※1)になりますが、CI待ち時間が7日分ぐらい削減(※2) 」できました。必ずしもCI待ち時間がムダではないですが、エンジニアの人件費を考えると費用対効果は高いのではと考えています。 ※1. 4coreの分あたりの料金 $0.016 x (変更後のBillable time 40分 - 変更前のBillable time30分) x 月間CIテスト実行回数 700回 x 為替150円 ※2. 待ち時間の削減時間 5分 x 月間CIテスト実行回数 700回 ÷ (60分 x 営業時間 8時間) 5. CIテスト実行時間の高速化のまとめ 最後にまとめです。 今回は、FindyのRailsプロジェクトで、CIのテスト実行時間を10分から5分と2分の1に高速化した話をご紹介しました。 具体的には、次のテクニックで高速化を実現しました。 不要なカバレッジレポートの作成をなくす テスト実行の並列度を高める テスト実行時間の偏りを減らす また、費用対効果もよかったと考えています。 月間のGitHub Actionsのコストが2万円ぐらい増加 1ヶ月あたりCI待ち時間が約7日分減る なにか、参考になる内容があれば嬉しいです。 最後に、弊社のエンジニアが次のようなスライドも公開しているので興味があればご覧くださいませ。 speakerdeck.com また、Findyは積極的にエンジニアを採用しています。CI/CDを始め、Four Keys、開発生産性、技術トレンド、転職市場など興味のある方は、お気軽にカジュアル面談を受けてみてください :) Findyの採用情報はこちら↓ herp.careers
アバター