やなぎにっき

学んだことの記録

#minneで買ってよかったもの 2023

この記事は #minneで買ってよかったもの Advent Calendar 2023 の25日目の記事です🎅

adventar.org

minneでエンジニアをしているyanagiです。minneの色々な思い出と共に買ってよかったものを紹介していきます 🙌

minneのハンドメイドマーケット2023 で買ったもの

💫 leapさんの流れ星のフォークリング

minne.com

leapさんは元々好きな作家さんで、minneでも購入していました。懐かしいようで新しいような、落ち着いているようでキラキラしているような雰囲気がとても好きです。

当日は作家さん本人に対応していただいたのですが、すごく良くしていただいて楽しい時間だったな〜と今でも指輪をつけるたびに思い出したりします。サイズの調整もその場でしていただいたりと、対面ならではのよさを感じたお買い物でした。

🌷 haru さんの チューリップ ハンカチ

minne.com

アナログで描いた絵をイラレで取り込んで加工しているらしく、アナログとデジタルが融合されている感じが好きです。それをさらに綿に印刷しているのがまた素敵。

🤜 ol さんのバングル

minne.com

(minneではバングルは取り扱っていない模様)

ブースのテーブルの代わりに買い物カゴを使っていたり(ちゃんとメタルラック的な棒で固定されていた)作品のコンセプトが一貫されていて、作品・ブースの雰囲気が素敵でファンになってしまいました。このバングルはステンレスを加工して作っているものとのこと。

リリース記念で買ったもの

🍪 atelier Claire さんのクッキー缶

minne.com

入社して初めての深夜メンテ明けに動作確認という名目で購入。何を食べても美味しい。ココナッツが好きなのでココナッツの塊のようなクッキーが一番好きでした。

🐈 Zacchino!さんの スマホ用壁紙「こねこ」

minne.com

こちらは物品ではなくダウンロード販売の壁紙。

ダウンロード販売のリリースに関わっていたのですが、こちらはリリースした後に購入した思い出深い作品です。手持ちのiPhone壁紙にしているのですが、同僚や友人に「かわいいね!」とよく褒められます。

minneとものづくりとで紹介したもの

🌿 刺繍・布小物 emuさん のクリスマス 刺繍リース

minne.com

厳密には今年ではなく去年の12月に買ったもの。クリスマス用のリースとして探していたのですが、どの季節でも馴染むのでクリスマス以外の季節でも飾っています。

minneとものづくりとでも取り上げていただきました。

minne.com

来年もたくさんお買い物するぞ 🤘

graphql-ruby 関連の CustomCop を作ってみる

この記事は 🎅GMOペパボエンジニア Advent Calendar 2023 - Adventar 11日目の記事です🎅🎄

adventar.org

私が所属しているminneのプロダクトではGraphQLを採用しています。

Ruby on Rails で開発するにあたり、以下のGemを使用しています。

普段開発している中で rubocop-graphql にあるcopだけでなく、「こういうcopがあればいいな」と思うことがしばしばあるので作ってみます。

作りたい CustomCop

作品情報のProductモデルと購入情報Saleモデル があるとします。ProductとSaleは一対一の関係です。

一時期、既存のコードで以下の様なクエリで呼び出せるスキーマのようになっていたことがありました。(例なので実際のクエリとは異なります)

query ($id: String!) {
  sale(id:$id) {
    id
    product_id
  }
}

このようにsaleに関連づくproductの情報が product_id field のみの場合、クライアントはsaleに関連づくproductのデータを取得する際はproduct_id を元にQuery productから再度クエリ必要が出てきてしまいます。それでは一度で求めたい情報を取得できるというGraphQLのメリットが活かせません。そのため、ProductType の様なオブジェクトを取得できる product fieldが取得できるとよさそうです。

そのため、nodeのfield名が xxx_id のようにidを末尾で終わる場合にwarningを出すcopを作りたいと思います。

module Types
  class SaleType < Types::BaseObject
    field :id, ID, null: false
    field :quantity, Int, null: true
    field :total_amount, Float, null: true
    field :product_id, String, null: true # ここで warningを出したい
  end
end

warningを出したい条件

  • fieldで始まる第一引数の名前
  • かつその名前が_idで終わる

CustomCop を作ってみる

実装は Development :: RuboCop Docs や記事を参考にしました。

rubocopはパーサーライブラリを使用して、抽象構文ツリー(AST)を取得しています。

parser gemで取得対象にしたいコードのASTを取得してみます。

$ gem install parser
❯ ruby-parse -e 'field :product_id, String, null: false'
(send nil :field
  (sym :product_id)
  (const nil :String)
  (kwargs
    (pair
      (sym :null)
      (false))))

今回はfieldから始まる行の、シンボル名を検知したいため、検知したいコード 'field :product_id' をparseしてみます

❯ ruby-parse -e 'field :product_id'             
(send nil :field
  (sym :product_id))
  • send ノードはメソッドの呼び出しを表す。nilはレシーバーがnilであり、send nil :field はレシーバーのないfieldメソッドを表している
  • fieldメソッドの引数として、 product_id というシンボルが渡されている

このASTを元に、CustomCopを作ってみます。

matcher

field :field_name のパターンにマッチし、field_name だけを取得するmatcherを書いてみます。

def_node_matcher :field_name, <<~PATTERN 
  (send nil? :field (:sym $_) ...)
PATTERN
  • nilのレシーバーからfieldのメソッドが呼ばれた時
  • 引数に指定されたシンボルを受け取る

メソッド

def on_send(node)
  field_name = field_name(node).to_s

  return unless field_name.end_with?("_id")

  add_offense(node)
end
  • nodeからfield_nameを抽出する
  • 末尾が _id であれば add_offenseを呼び出し、警告を発生させる

最終的なコード

最終的なCopのコードとテストです。 自動修正とテストも書いてみました。

# frozen_string_literal: true

module RuboCop
  module Cop
    module GraphQL
      #  This cop checks whether field names are ending with _id.
      #
      # @example
      #   # good
      #
      #   class UserType < BaseType
      #     field :profile, ProfileType, null: true
      #   end
      #
      #   # bad
      #
      #   class UserType < BaseType
      #     field :profile_id, String, null: true
      #   end
      #
      class FieldNameWithId < Base
        extend AutoCorrector

        MSG = "Field names should not end with _id."

        def_node_matcher :field_name, <<~PATTERN
          (send nil? :field (:sym $_) ...)
        PATTERN

        def on_send(node)
          field_name = field_name(node).to_s

          return unless field_name.end_with?("_id")

          add_offense(node) do |corrector|
            rename_field_name(corrector, field_name, node)
          end
        end

        private

        def rename_field_name(corrector, field_name, node)
          name_field = field_name
          new_line = node.source.sub(name_field, name_field.gsub(/_id$/, ''))
          corrector.replace(node, new_line)
        end
      end
    end
  end
end
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::GraphQL::FieldNameWithId, :config do
  context "when end of field name is not _id" do
    it "not registers an offense" do
      expect_no_offenses(<<~RUBY)
        class UserType < BaseType
          field :product, ProductType, null: true
        end
      RUBY
    end
  end

  context "when end of field name is _id" do
    it "registers offense" do
      expect_offense(<<~RUBY)
        class UserType < BaseType
          field :profile_id, String, null: true
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Field names should not end with _id.
        end
      RUBY

      expect_correction(<<~RUBY)
        class UserType < BaseType
          field :profile, String, null: true
        end
      RUBY
    end
  end
end

rubocop-graphql のクラスを使う

と、ここまで手順通りにやってきましたが、rubocop-graphql ではFieldをcopする用のメソッドが定義されているので、わざわざmatcherを定義する必要はなかったのでした。

include RuboCop::GraphQL::NodePattern
def on_send(node)
  return unless field_definition?(node)

  field = RuboCop::GraphQL::Field.new(node)
  return unless field.name.to_s.end_with?("_id")

  add_offense(node) do |corrector|
    rename_field_name(corrector, field, node)
  end
end

感想

CustomCopを作り、アプリケーションに導入すると過去のコードを統一できるだけでなく、今後もレビューでのやりとりが減ること、コード規約が明文化されることなど嬉しい場面が多いことに気づきました。

今までparserに触れてこなかったのですが、いざやってみると思ったよりハードルが低いことにも気づけてよかったです。さらによほど複雑な条件・厳密にチェックしようとしない限り、rubocopのコードを参考にすれば実現できそうです。今後も気軽に作ってみようと思います。

参考

Development :: RuboCop Docs

RuboCopの新しいルールを追加する方法(Custom Copの作り方) - アジャイルSEの憂鬱

RuboCopにカスタムルールを実装する方法について - BOOK☆WALKER inside

RubyKaigi 2023 in 松本 に行ってきました

RubyKaigi 2023 in 松本 に行ってきました

2023年5月11日から13日に長野県松本市で行われた RubyKaigi 2023 に行ってきました。

当日中はメインコンテンツであるセッションを聴きつつ、休憩の合間にRubyistたちと立ち話をし、本の著者に話しかけて本を買いサインをしてもらい、スポンサーブースを周り、松本のごはんを食べ、松本の山を見ながら川沿いや街並みを歩き、Twitterで盛り上がっている #rubykaigi タグを見て周り、夜には懇親会があり……と起きたことをその場でツイートする暇もないくらい、忙しく刺激のある充実した3日間でした。

RubyKaigiには去年の2022年がオフライン初参加でしたが、去年と比較しても参加者が800人ほどから1200人ほどに増え、公式が主催するパーティーもあったりと、新型コロナウィルス前のRubyKaigiを知らない自分でも、オープニングトークで松田さんがおっしゃっていたように「Kaigi is back!」だということを肌で感じる盛り上がりでした。

セッションを聞いて

スピーカーの熱量にやる気を貰った

RubyKaigi のセッションはどれも技術的なレベルが高く、始終理解できた発表はほとんどなかったのが正直なところです。ただ、どのセッションのスピーカーにも共通して言えることは、誰もが熱意とプライドを持って、毎日のように手を動かし、沢山の時間を使って何かしらの成果物・作ったものがある人たちです。どの発表を聞いても、自分もこの人たちのように日々研鑽していこうという気持ちになりました。

どの発表も構成が綺麗に組み立てられており、一見順調に進んだ結果のように見えてしまうのですが、発表を聞いているだけの自分には計り知れないほどその裏の試行錯誤や苦労があると想像しています。

あるスピーカーの方と話した時に(発言の内容があやふやなのでお名前は控えますが)「スムーズに行なっているように見えるけど、時間や構成の都合で簡略しているだけで、実際は泥沼のようにやっていますよ」と話されていたのが印象的でした。自分も改めて日進月歩で日々研鑽していかないな、と改めて思わされました。

セッションの「分からない」が面白くなってきた

去年と比べてセッションの内容がより分かるようになった、という手応えはなくこの分からなさに落ち込むこともあったのですが、この点は事前に StoresのCTOである藤村さんがPodcastで話されていた内容に助けられました。

すげー面白いんですけど、正直僕も半分以上よくわからないんですよね。半分ぐらいはわかるかな、でも結構わからない話が多いですね。

「うーん、わからん。こうなっているってことはなんとなくわかったし、こういう仕組みなんだろうってことはなんとなく理解できるけどわからん!てかこんなのあったんだ」「こんな世界があったんだ!」みたいなのが無限に降ってくるのがRubyKaigiで、それがすげえ面白いって感じですね。

RubyKaigiは刺激を受ける場。CTOが語るRubyKaigiの好きなところ【ep.21 #論より動くもの .fm】 - STORES Product Blog

ある会社のCTOでさえ全部理解できる話ではなく、この「分からない」を楽しんでいいんだ!と知れたおかげで、セッションを聞く間はこの分からなさを心置きなく楽しむことができました。

「parser.y はどうやら曲者らしいぞ」「この人たちがRubyを早くしてくれているんだ!」「この人は本当にキーボードが好きなんだな」とか。

内部の仕組みについてそこまで理解できていなくても、こうした人たちがどのようにRuby本体やGemなどの周辺にまつわる環境をより良いものにしてくれているのかを知ることは、知らないことに比べてずっと大きな差があると思います。今回のRubyKaigiのセッションを聞く(もはや浴びる)ことで、Rubyと自分の距離が縮まった気がしています。

分からなさを楽しんでも良いと知ったとしても、話を聞くからには分かることが増えた方より楽しめることは確かです。来年のRubyKaigiではさらに分かることが一つでも増えるよう、少しずつRubyの知識を深めていきたいとも思います。いろんな人からRuby技術者認定試験Gold取得のための勉強がRubyの仕組みを知るのに役立ったと聞いているので気になっています。

セッションの各感想

技術的なしっかりした感想は言えないけど自分がその時思ったことは書いておきたいので簡素でも感想を書きます。もっと書きたいので随時追加していきたい。

  • UTF-8 is coming to mruby/c

    「mruby/cにUTF-8対応しませんかと言われ、この時代にUTF-8対応を0からやる機会を逃すには行かない!と思い始めた」とおっしゃっていて、普段からima1zumiさんが文字列を追求していたからこそ声が掛かったのだろうし、それに応える気概と実装できる技術力があるのがかっこよすぎる。

  • RBS meets LLMs - Type inference using LLM

    Rubyの型定義をChatGPTが推測できるのか試してみた発表。「Act as Ruby type inferrer」という書き出しを見て、今までChatGPTにプロンプトを書く時に振る舞って欲しい職業や立場を指定していたけど、振る舞って欲しい内容は人の属性じゃなくてもいいのかという気づきがあった。

  • Adding custom rule for Rubocop in the 2 month of employment

    RubocopにカスタムCopを実装する話。以前に会社の上司が業務用のCopを実装してくれて、私も作ってみたいと思ったことを思い出した。Copを実装する際にParserにも触れることができそう。冒頭の去年のRubyKaigiのイベントであるRubyMusicMixinのおかげで転職先が決まった話がこの1日目に聞けたのもよかった。

  • Implementing "++" operator, stepping into parse.y

    Rubyには(意外と)実装されていないincrement演算子を実装するという試み。実装してみる→実装できた→次の問題が見つかる→次のプランで試してみる を3,4パターンほど繰り返していて、構成として見ていて面白かったし、理想の実装のために(しかも至る所で難所だと噂を聞いたparser.yを読んで)突き詰めていくところが本当にすごい。

  • Fix SQL N+1 queries with RuboCop

    ISUCONを自分はやったことがないけど、想像していたものは「当日の限られた時間と参加者の知識」を活かしていく競技だと思っていたので、この発表を聞いて当日のために1年ほどの時間を使ってcopという道具を仕込む手もあることを知った。ISUCONという総合格闘技のために淡々と刀を研いでいる。かっこいい

  • Build Your Own SQLite3

    キーボードでSQLiteを動かす話。OSが載ってないマイコンにPicoRubyでSQLiteを動かすというもの。低レイヤーから高レイヤーまでRubyで実装できてしまうんだな。普段アプリケーション開発をしているとあまり低レイヤーに触れる機会がないのだけど、こういうマイコンだとコンパクトな分、低レイヤーの理解がしやすかったりするのかな?と気になった。キーボードでSQLiteが動くようになったので、キーボードの入力履歴を記録してよく入力しているキーからキーマップを作っていた(もちろん解析するのもPicoRuby)のが面白かった。

Rubyistとの交流

今年のRubyKaigiでは、去年のRubyKaigiぶりに会う人、オンライン上では以前から知っていたけどやっと対面で話せた人、知り合いの知り合いで初めて顔を知った人、などなどいろんな形で社外のRubyistと交流することができました!

会社の同僚と歩いていたら私のフィヨルドブートキャンプの知り合いの人とすれ違い、その同僚と知り合いが仲良くなったり、かたや私も同僚に RailsGirls で繋った知り合いを紹介してもらったりしました。そうした輪の広がりはオフラインだからこそ生まれやすい広がりだと実感しました。

休憩中すれ違った人とその場で話していたら、思いのほか深い話ができて30分以上経っていた……ということも楽しい思い出の一つです。

私は2021年にフィヨルドブートキャンプというプログラミングスクールを卒業したのですが、今年は特にフィヨルドブートキャンプの関係者たちと会うことができました。去年もかなり人が多いと思っていましたが、今回はさらに各所にフィヨルドブートキャンプの関係者がおり、自然にオフ会的なものが発生していて面白かったです。

3日間を通して「社外の人と沢山話せたな!」と思えたのは、フィヨルドブートキャンプのつながりがあったからこそです。(「別のコミュニティの私の知り合いの人」もフィヨルドブートキャンプの知り合い」)

これからはもっと会社やフィヨルドブートキャンプではないRubyKaigiの人たちとも交流できていけるようなムーブをしていきたい気持ちもあります!

著者から本を購入した

  • 研鑽Rubyプログラミングの著者であるJeremy Evansさんと翻訳者の角谷さん
  • RubyRailsの学習ガイドのigaigaさん
  • ユウと魔法のプログラミング・ノートの著者である鳥居雪さん

から本を直接購入し、その場でサインを頂きました!即売会的に技術書が著者から本が買えるの嬉しすぎる。 RubyKaigiから帰ってきてから研鑽Rubyプログラミングを毎日少しずつ読んでいます。

開催地である松本が好きになった

私は今まで松本に行ったことがなく、今回のRubyKaigiで初めて訪れました。

松本は山に囲まれており、川と綺麗な水、蕎麦や地酒、松本城や美術館、素敵な喫茶店や飲食店など、私が感じるたくさんの豊かさがある街だと知りました。RubyKaigi2023を過ごした土地であることも含め、今では松本という街が大好きになりました。(松本で食べたものや観光の話はそれだけで書きたいことが山ほどあるので別エントリーで書きたい)

1日目のアフターパーティーでチーフオーガナイザーである松田さんから、(意訳)「毎年別の土地・会場でやるということはオペレーションや会場の配置を1から考えないといけないので大変。それでも毎年別の場所でその土地を含めてRubyKaigiを楽しんでもらいたい」という旨の話をお聞きしました。

毎年開催地が変わることによる運営側の大変さが私には少しも想像できていなかったので、より改めてオーガナイザーやヘルパーの方たちのおかげでこのRubyKaigiを楽しむことができているのだとより実感しました。運営の皆さんには本当に感謝しています。

私は去年開催地である三重の津でも初めて訪れた津が好きになり、今回も松本が好きになったので、そのことを松田さんに会話の流れで直接伝えられてよかったです。

最後に

改めてこのような場を作っていただいたオーガナイザーやスタッフ、そして出張費用を出していただいた上に業務扱いとして行かせてくれた会社には感謝の気持ちでいっぱいです。

この3日間、RubyKaigiでたくさんのよい経験や刺激を受け取るばかりで、自分はどうしたらRubyRubyコミュニティに還元できるかを考えるようになりました。まずは自ら手を動かしてコードを書くこと・アウトプットしていくこと、そして自分以外の手を動かしている人たちに対して反応していくこと(いいねやstarをつけるなど)を地道にしていきたいと思います。

具体的な直近のやりたいこと・目標です。KaigiEffectにしていくぞ〜

  • RubyやGemの好きなコードをデバッグしながら追ってみる
  • 研鑽Rubyプログラミングを少しずつ読む
  • Kaigi on RailsのCFPを送る
  • 地域コミュニティ(特にin personなもの)に顔を出してみる
  • 松本にまた行く

中学生以来の電子工作をして meishi2 を組み立てた

これは🎅GMOペパボエンジニア Advent Calendar 2022 - Adventar の8日目の記事です。

昨日の記事は nacal くんの エンジニアとしてのキャリアのVSOP でした。

キャリアのVSOP という考え方について、エンジニアとして捉えた考え方がまとめられているいい記事でした!

🎄GMOペパボエンジニア Advent Calendar 2022 - Adventar もあります🎅🎄


meishi2 を組み立てた

中学生以来の電子工作をして meishi2 を組み立てました。

はんだ付けは中学校の技術の時間に触った以来でちゃんと動くか不安でしたが、meishi2 keyboard ビルドガイド を参考に2,3時間程度で組み立て・ビルドまでできました。右から2番目のキースイッチが若干傾いていたりしますが、それもひっくるめて愛着が湧いています。

ビルドはターミナルであれこれする必要もなく、REMAP というサイトを使いブラウザ上でビルド・キーマップの設定が完結しました。すごい。

自分で作ったものがPC上で動くのが面白く、組み立てた時間以上に押したりキーマップをいじったりして遊んでいます。

早速REMAP で マクロ機能を使って :sushi: という文字を入力することで🍣 などの絵文字が表示できるようにしてみました。

REMAP 上では日本語や絵文字入力ができない(はず)なので、今回はSlack上で :sushi: という文字を表示させる方法で絵文字の入力を実現しています。しかしどんなアプリケーションでも 🍣 や ✌️ を1Tapで入力させたいという欲望があるので、次はQMK Firmware に挑戦してみようと思います。

作った経緯

前々から自作キーボードを作ってみたいと思っているのですが、最初から普段使うようなキーボードを組み立てるのは気持ち的にハードルが高かったのでキーが少なくビルドガイドが充実しており、かつPro Micro が同封されている meishi2 を選びました。

また、ペパボ社内で shiorinが 自作キーボードを作る会 を発足してくれたり、その会の一環でyuchi に初心者向けの自作キーボードの説明をして貰ったことで自分の中の自作キーボードの機運が高まり作成にまで至りました。


以下では用意したものや苦戦したことを書きます。同じく(ほぼ)初めて電子工作を行う方の参考になれば!

用意したもの

meishi2 キット

meishi2 キット

フィヨルドブートキャンプ出身のトミーさんふーがさんと亀戸餃子に行った後につき合ってもらい 遊舎工房 に行った時に買いました。

キースイッチ 4つ

キースイッチ は 遊舎工房 さんにあるキースイッチのサンプルを心ゆくまで押しまくり、気に入ったものを4種類購入しました。1個から販売してくれるのすごい!

キーキャップ 4つ

キースイッチの色が見えるように透明なものを選びました。

はんだごてセット

白光(HAKKO) BLUE SET 電気器具/電気部品用はんだこてセット 40W はんだ/吸取線/簡易こて台付き FX511-01

meishi2 keyboard ビルドガイド にもおすすめの道具の紹介がされていたのですが、同じものを全て揃えると結構良い値段がして、自分のような試しに電子工作をしたい身としては気が引けたのでAmazonやヨドバシで 600円程度で購入できるこちらのはんだごて/はんだ/吸取線/簡易こて台のセットを買いました。

値段的には文句がないですが、あまりおすすめはしないです。

はんだごての温度が高いのか基盤が焦げそうになったり、ON/OFFのスイッチがないのでコンセントを入れた瞬間に熱くなるのも気を使います。はんだの長さも短く、最後の方は残り数センチのはんだではんだ付を行うというハードモードになりました。

初心者こそちゃんとした道具を使おうという学びでした。

ニッパー

タミヤ クラフトツールシリーズ No.93 モデラーズニッパー アルファ74093

ニッパーは以前プラモデル用に買ったもので事足りました。

余談ですが最近水星の魔女にはまっていて、初めてのガンプラを楽しく作ったりしています。エアリアルはどこの店頭にもなく購入できていません……。


これら全て含めて 5000円しないくらいで一式揃いました。meishi2 は スイッチ&キーキャップ付き を買ったりするともう少し安くなると思います。

調べたこと

meishi2 を作ったエントリー

meishi2 を作ったブログ記事を色々読みました。初めて電子工作やはんだ付けをする人の体験談が多く参考になりました。

はんだごての使い方

「はんだごて 使い方」で検索して複数記事を見ながらイメージトレーニングをしました。今思えばこういう時に動画を見るのがピッタリなのかもしれない……。

REMAP のキーの設定

こちらの記事が網羅的でわかりやすかったです。

(初心者編)Remapを使ってキーマップを書き換えよう - 自作キーボード温泉街の歩き方

苦戦したこと

はんだ付け

先にも書いたように、手頃なはんだ付けセットで済ませたため苦戦するところがありました。 はんだ付け自体は meishi2 をやっていくにつれ慣れてきたので、もっとやりたい気持ちです。

コンスルーとピンヘッダの違い

meishi2 のビルドガイドに

2022 年現在コンスルーの入手が非常に困難になっており、コンスルーは付属しなくなっています。

と記載があります。 meishi2 にPro Micro と一緒にコンスルーのようなものが2つ同封されており、「コンスルーのようなものがついてそう?Pro Micro の半田付けいらないのか!」と思っていたのですが、同封されていたのはコンスルーではなくピンヘッダでした。

画像で言うと左がピンヘッダで、右がコンスルーです。 画像 : wings42 v2 ビルドガイド | Daily Craft Keyboard より

そのような勘違いをしながら Pro Micro のはんだ付けをスルーし、キースイッチのはんだ付けをしてREMAP でビルドをしようとしたところ、うまくいきませんでした。はんだ付けしたら無事REMAPでビルドまで行うことができました。

このようにコンスルーが付属されない場合はピンヘッダを使って Pro Micro をはんだ付けする必要がありました。ビルドガイドにコンスルーが付属されていなかった場合のケースが書かれていなかったのでハマったのですが、電子工作慣れている人にとっては当たり前のような話かもしれません。キースイッチ付けてからの Pro Micro のはんだ付け大変だった……。

最後に

meishi2 を作った今、普段使いの自作キーボードを作る前にもう一個くらいなにか小さめのものを作ってみたい気持ちになっています。


🎅GMOペパボエンジニア Advent Calendar 2022 - Adventar の次の担当はにっしーさんです🚆

RubyKaigi 2022 に現地参加しました

RubyKaigi 2022 に会社の出張として行かせてもらいました。RubyKaigi自体は去年のオンライン開催に参加したことがあり今回2回目で、現地参加は今回が初めてです。

RubyKaigi の現地参加は 「Rubyの話を聞ける・Rubyistと話せる・現地のことを知れる」 と お得で有意義で楽しい3日間でした!!!

目次

Ruby の話を聞いた(印象に残った登壇)

特に印象に残った登壇の感想です。

rubykaigi.org

フィヨルドブートキャンプ卒業生のふーがさんによるgem_rbs_collectionへのコントリビューションを提案する話。

手順の説明が丁寧で、これなら自分もコントリビュートできるかも!と思えました。近いうちにPR立てるぞ!

rubykaigi.org

ポケモンカードのデッキを検索するエンジンを作った話。

内容自体の理解はあまりできていないのですが、それでも自分のために自分でアプリケーション作る話は聞いていて面白いし、私はこういう話が好きなんだな〜という気づきがありました。私も何か作りたくなりました!

rubykaigi.org

なぜRubyのビルドは難しいのか という話。

ソフトウェアは絶えず進化しているので、あらゆる環境であらゆるgemのあらゆるバージョン でビルドできることが逆にすごいことだと実感。

bundlerを実行したときにエラーが出るのがイレギュラーな状態なのではなく、エラーが出ずに通る方が奇跡だった。

https://twitter.com/yasulab/status/1568434261224755204?s=20&t=JW4RZkLYWrlWeOA9xnox3w

rubykaigi.org

Rubyを楽しむためのRuboCoppとの向き合い方の話 。

RuboCopの使い方を「強制・参考の2つのレベルに分ける」という提案はもちろん、快適にチームで開発するための提案にたどり着くまでここまで考え、時間をかけて試行錯誤していく様子が印象的でした。

Rubyistと話した

登壇の合間(お昼・休憩の時間など)では社内・社外たくさんの人とお話しする機会がありました。

フィヨルドブートキャンプでお世話になったメンターや卒業生・関係者の方とはオンライン上で長い付き合いがあったものの、お会いする方はほぼ全員初めて対面でお話しができて感慨深いものがありました。全国各地からこうやって同じ場所に集まることができたのもRubyKaigiのおかげです。

3日目には一緒に床でお昼を食べたり集合写真を撮ったりもしました!

そのほかにも Twitterで繋がっていた方、一方的に憧れていた方、オンラインの地域Rubyコミュニティで一緒になった方、企業の若手の方、企業ブースでお会いした方……と書き出してみると自分でも驚くほど本当にいろんなRubyistとお話しできました。

知り合いと廊下で登壇の感想を話したり、一方的に憧れていた方が廊下にいたので勇気を出して話しかけたり、赤いTシャツを着たRubyコミッターが普通に廊下を歩いていたり、この「廊下」も含めてRubyKaigiなのだなということを実感しました。

三重が好きになった

今回のRubyKaigi ではお昼にお弁当、休憩時間におやつを提供していただきました。また各ブースの企業さんからも三重の食べ物を提供していただいたり。夜も津駅周辺で美味しい海鮮やお肉、日本酒を飲んだりしました。

RubyKaigi後に伊勢神宮に寄ろうとしたのですが体力的に断念。三重はほかにも行きたいところがたくさんあるので今度は旅行として三重に行こうと思います。

自分は出不精でなかなか遠出しないので(今までの旅行も友人の企画かライブや舞台の遠征がほとんど)、RubyKaigiに自分の知らない土地へ連れて行って貰えて嬉しかったです。

自分もRubyコミュニティの一員

こうやってRubyの話を聞いたりRubyistと話を聞いたのはもちろん、Matzの話や松田さんのエンディングトークを聞いて改めて自分は「Rubyのコミュニティを作っている1人の人間」ということを再実感しました。

自分が属しているコミュニティが会社やフィヨルドブートキャンプのコミュニティだけではなくて、それらを覆い尽くす大きなRubyコミュニティがあるんですよね。

これからも自分ができる自分なりの手段でRubyコミュニティに貢献していこうという気持ちになりました。やっていくぞ〜

モチベーションあがった

ここまで書いたように、あらゆる人の話を聞いたり会話をしていくことでモチベーションがあがりました。

「壇上に立っているこの人みたいになりたい・近づきたい」「発表の話がもっとわかるようになりたい」「みんな頑張ってる!負けてらんね〜!」を3日間毎日感じていました。

来年の松本のRubyKaigiの日に今回と比べてちょっとでも成長を実感できるようにするために、RubyKaigiではない日々を過ごしていこうと思います。

オーガナイザー・スタッフへの謝意

今の情勢の中で現地・オンラインというハイブリットでの開催は自分が想像しきれないほどの苦労があったことだと思います。自分がこういった体験をできたのもオーガナイザー・スタッフの方々のおかげです。本当にありがとうございました!

画面上のDOM要素を画像に変換してサーバーに保存する 【Rails6】

f:id:yana_g:20211220205329p:plain

この記事はフィヨルドブートキャンプ Part 1 Advent Calendar 2021の記事です。

フィヨルドブートキャンプ Part 1 Advent Calendar 2021 - Adventar

フィヨルドブートキャンプ Part 2 Advent Calendar 2021 - Adventar

昨日の19日目は

でした。

はじめに

わたしは本日フィヨルドブートキャンプの課題として個人開発した TwiCode というサービスをリリースしました。

twicode.herokuapp.com

yana-g.hatenablog.com

サービスの概要や作った背景、苦労したことや工夫したことはリリースブログに書いたので、今回はサービスの肝となる実装について技術的な話をしたいと思います。

TwiCodeはテキストで入力したソースコードシンタックスハイライトを適用したものを画像に変換し、その画像をサーバー側で保存しています。その画像はURLをツイートすることでTwitterカードに画像を表示することができます。

画像にして画面上に表示するだけであればJavaScriptのみで実装できますが、OGPに表示するには画像にするだけでなくサーバーに保存する必要があります。

DOM要素を画像化してサーバーに保存する処理は他に参考にできる記事がなく苦労したので、簡単ではありますが紹介していきます。

処理のおおまかな流れです

  • JavaScript

    1. 保存ボタンを押したらフォーム送信の前に処理を走らせる
    2. 画面上のDOM要素をcanvas形式に変換する
    3. canvasデータをデータURLに変換する
    4. データURLをRailsに渡す
  • Rails

    1. パラメーターで受け取ったデータURLをActiveStorageに保存する

開発環境・使用ライブラリ

  • Rails 6.1.4
  • Ruby 3.0.2
  • ActiveStorage
  • html2canvas

今回はhtml2canvas というライブラリを使ってDOMの要素を画像(canvas)変換していきます。 html2canvasを使うと、下記のサンプルのボタンを押すとHello world!の要素が画像になって表示されるようなことができます。便利!

See the Pen Untitled by yana-gi (@yana-gi) on CodePen.

事前準備

今回はscaffoldで自動で作成されたformのtextarea部分を画像にして、サーバーに保存する処理を作ってみます。

rails new して scaffoldする

サンプル用のアプリを作ります。

rails new して text型のbody を持つモデルをscaffoldします。モデル名はなんでもいいですが、今回はcodeで作成していきます。

$ rails new
$ rails g scaffold Code body:text

html2canvasをインストール

$ yarn add html2canvas

Active Storage をインストール

$ rails active_storage:install
$ rails db:migrate

app/models/code.rb

class Code < ApplicationRecord
  has_one_attached :image # 追加
end

Railsでhtml2canvasを動かしてみる

いきなり保存する処理を作るのは難しいので、試しに要素の画像を画面上に表示するボタンを作ってみます。

app/views/codes/_form.html.erb formテンプレートにボタンを追加します。

<input type="button" value="button" class="my-button">

app/javascript/packs/application.js

/app/javascript/src/code.js を読み込めるようにします

require("../src/code");

/app/javascript/src/code.js

ボタンが押されたらhtml2canvasが#code_bodyの要素をcanvasに変換し、子ノードの最後に表示するようにします。

import html2canvas from "html2canvas";

document.addEventListener('DOMContentLoaded', () => {
    const myButton = document.querySelector('input.my-button');
    myButton.addEventListener('click', function () {
        html2canvas(document.querySelector("#code_body")).then(canvas => {
            document.body.appendChild(canvas)
        });
    });
})

これでボタンを押すとformのtextareaが画像として表示する処理できました✌️

Image from Gyazo

画面上のDOM要素をサーバーに保存する

事前準備が終わりhtml2canvasの動かし方がわかったところで、実装に入っていきます。

JavaScript側の処理

  1. 画面上のDOM要素を取得する
  2. submitボタンが押される
  3. submit後の処理をキャンセルする
  4. 要素をcanvas形式に変換する
  5. canvasデータをデータURLに変換する
  6. データURLを隠しフィールドにsetする
  7. submit処理を実行する

Rails側の処理

  1. データURLを受け取る
  2. データURLからActiveStorageにattachする

JavaScript

app/javascript/src/code.js

import html2canvas from "html2canvas";

document.addEventListener('DOMContentLoaded', () => {
    // [1] 画面上のDOM要素を取得する
    const form = document.querySelector("form");
    const code_body = document.querySelector("#code_body")
    const hiddenImageDataUrl = document.querySelector("#code_image_data_url");

    // [2] submitボタンが押される
    form.addEventListener("submit", function (event) {
        // [3] submit後の処理をキャンセルする
        event.preventDefault();
        // 要素をcanvas形式に変換する
        getImageDataUrl()
            .then((imageDataUrl) => {
                // [6] データURLを隠しフィールドにsetする
                hiddenImageDataUrl.setAttribute("value", imageDataUrl);
            })
            .then(() => {
                // [7] submit処理を実行する
                form.submit();
          });

    async function getImageDataUrl() {
    // [4] 要素をcanvas形式に変換する
        const canvas = await html2canvas(code_body);
    // [5] canvasデータをデータURLに変換する
        return canvas.toDataURL("image/jpeg", 1.0);
    }
  })
})

ビュー

app/views/codes/_form.html.erb

<div class="field">
    <%= form.hidden_field :image_data_url, value: "" %>
</div>

app/views/codes/show.html.erb

<p>
  <strong>Image:</strong>
</p>
<p>
  <%= image_tag(@code.image) %>
</p>

コントローラー

image_data_url をStrong Parameters で受け取り、画像をattachします。

dataURLをActiveStorageに保存する処理はこちらを参考にさせていただきました。

zenn.dev

処理の流れやデータURLなどについて書くと長くなってしまうのですが、以前フィヨルドブートキャンプの日報で雑に書いたことをScrapboxに雑に転記したので載せておきます。

scrapbox.io

app/controllers/code_controller.rb

# frozen_string_literal: true

class CodeController < ApplicationController
  before_action :set_code, only: %i[show destroy]

  def create
    @code = Code.new(code_params)
    @code.attach_blob(image_data_url)

    if @code.save
      redirect_to @code, notice: 'Code was successfully created.'
    else
      render :new, status: :unprocessable_entity
    end
  end

private

  def set_code
    @code = Code.find(params[:id])
  end

  def code_params
    params.require(:code).permit(:body)
  end

  def image_data_url
    params.require(:code).permit(:image_data_url)[:image_data_url]
  end
end

モデル

app/models/code.rb

# frozen_string_literal: true

class Code < ApplicationRecord
  has_one_attached :image

  def attach_blob(image_data_url)
    image_blob = ImageBlob.new(image_data_url)
    image.attach(
      io: image_blob.to_io,
      filename: Time.zone.now,
      content_type: image_blob.mime_type
    )
  end
end

app/models/image_blob.rb

class ImageBlob
  attr_reader :image_data_url

  def initialize(image_data_url)
    @image_data_url = image_data_url
  end

  def mime_type
    image_data_url[%r/(image\/[a-z]{3,4})/]
  end

  def to_io
    StringIO.new(decoded_content)
  end

  private

  def decoded_content
    Base64.decode64(content)
  end

  def content
    image_data_url.sub(%r/data:image\/.{3,},/, '')
  end
end

これで画像をサーバーに保存する処理ができました🎉

注意事項

turbolinksがオンになっているとJS側の処理がうまく動かないことがあります。その場合はturbolinksをオフにするか、addEventListenerで指定するイベントをDOMContentLoadedからturbolinks:loadに変えてみてください。

本番環境の画像の保存先をローカルにすると、herokuでデプロイした場合一定時間で画像データが消えてしまうので、S3などの画像サーバーに保管する必要があります。*1

画像毎にOGPの画像を設定するときに、相対パスurl_for指定だとTwitterカードの反映ができません。絶対パスpolymorphic_urlで指定する必要があるようです。*2

さいごに

今回はformのtextareaを画像化しましたが、自分が作成したアプリではtextareaに入力したコードをいい感じにした要素を画像化して使っていました。

f:id:yana_g:20211220183424p:plain

イデア次第では色々面白いことができそうなので、参考にしてもらえると嬉しいです!

参考

Vue.jsで画像を作成しRailsのActive Storageで保存する

base64でエンコードされた画像をActive Storageで保存する - Qiita

コードを画像でツイートできるサービスをリリースしました

f:id:yana_g:20211220113226p:plain

はじめに

フィヨルドブートキャンプの最終課題である自作サービス TwiCode をリリースしました!

twicode.herokuapp.com

github.com

この記事ではサービスの説明、また開発で苦労したことやよかったことなどを書きたいと思います。

目次

自己紹介

yana-gi(やなぎ)です。昨年の2021年からFJORD BOOT CAMP(フィヨルドブートキャンプ) でWebプログラマーになるためにRubyRuby on Railsなどを勉強していました。現在はフィヨルドブートキャンプを卒業し就職活動をしています。

TwiCodeの紹介

TwiCode(ついこーど) とは

TwiCodeとは、一言でいうとTwitterでちょっとしたソースコードを共有できるサービスです。

さらに詳しく説明すると、Twitterソースコードを共有するときにテキストそのままでもなく、画像でもなく、URLで共有すると画像として表示することができます。

ぜひサービスを使ってツイートしてみてください!

ツイートするネタがない人は、

  • 好きなメソッドの使用例
  • AtCoderのコンテストで提出したコード
  • 最近書いたコード

などをぜひツイートして教えてください!

使い方

サービスを使ってコードを共有するまでの大きな流れとしては、以下のようになります。

  • Twitterアカウントでログイン
  • 「新しくコードを投稿する」からコードを入力
  • 画像が作成され、コードの情報が書かれた画面に遷移する
  • その画面のURLをツイートで共有する

このサービスが解決できること

サービスの説明にも書いたように、TwiCodeはTwitterソースコードを共有するときにテキストそのままでもなく、画像でもなく、URLで共有すると画像として表示することが特徴です。

たとえば、AtCoderのコンテスト終了後に自分の回答をTwitterに共有したいとします。

そのままテキストでツイートすると、

f:id:yana_g:20211219150336p:plain

このように

  • シンタックスハイライトが適用されておらず読みにくい
  • メソッドがURLになってしまう
  • Rubyの場合、@hoge などインスタンス変数を書く場合メンションを送ってしまう可能性がある

といった不便さがあります。

また、この問題を解決しようとして画像として投稿してみると

f:id:yana_g:20211219150400p:plain

確かに読みやすくはなりましたが、ソースコードをコピーすることができません。また、画像を作成するのも少し面倒です。

TwiCodeを使うことで、この問題を解決することができます。

f:id:yana_g:20211219150420p:plain

TwiCodeが読みやすいコードとして画像を作成することで、読みやすい形で共有できること、またリンク先からコードを参照・コピーが可能になります。

こんな人に使って欲しい

コードを書く人なら誰でも使ってほしいと思っていますが、特にプログラミングを学んで日が浅い人に使って欲しいと思っています。今日学んだコードや、書いたコード、分からなかったコードなどを人に共有できれば、もっとプログラミングを学ぶことが楽しくなるんじゃないかと思っています。

TwiCodeがもっと気軽にコードの話をTwitterでできるきっかけになってくれたら嬉しいです!

サービスを作ろうと思ったきっかけ

自作したnpmを使って貰うことの面白さ

以前フィヨルドブートキャンプの課題で コマンドライン上でGitHubの草を生やす というnpm(JavaScriptのライブラリ)を作りました。

yana-g.hatenablog.com

f:id:yana_g:20211219150547p:plain

最初は「自分が使いたい・面白そう」と思って作ったものですが、実際に作って公開したところ、いろんな人に使ってもらいました。 純粋に自分が作ったものを利用して貰ったことがとても嬉しかったのですが、自分が想像しないような使い方をしている方もいたのが面白かったです。

f:id:yana_g:20211219150613p:plain

f:id:yana_g:20211219150633p:plain

自分が作ったものが、ユーザーによって自分が想像していたよりも面白いものにできた初めての体験でした。

この体験から、自作サービスでもこういった「ユーザーがサービスの面白さや価値を広げてくれるようなサービス」を作りたいと思っていました。

Twitter関連サービスへの興味

私はマシュマロfusetter(ふせったー)というサービスが以前から好きでした。こういったTwitterの機能を拡張させるような、Twitterでは痒いところに手が届かない機能を補完させるようなサービスは普段利用していて、自分でも作ってみたいと思っていました。

自分はすべてサービス内で完結するサービスより、普段よく使っているTwitterの機能を増やせるようなサービスの方が普段使いできそうと思い、Twitterで共有すること前提のサービスを作ることを考えました。

1番のきっかけ

1番のきっかけは、おなじフィヨルドブートキャンプの受講生であり、輪読会メンバーであるタマキさん(id:shirotamaki)が毎日コードをツイートしていたことです。

ツイートを毎日投稿(!)されていたので、自分は毎日「どうにか見やすくできないかな」と思っていたのがこのサービスのアイデアの始まりでした。

タマキさんがこうして毎日投稿していなければ、このサービスは生まれなかったかもしれません。

もっと気軽にコードをツイートするようになって欲しい

自分は今までDiscordでは結構コードを共有することはありましたが、Twitterではあまりコードをツイートしませんでした。その違いは前者がシンタックスハイライトで共有できることが大きな理由だと思っています。

自分もコードを見やすい形でツイートできるなら、ツイッターでもコードを共有するかも。さらには、このサービスがあったらコードを気軽にツイートする文化ができるかも。という淡い期待があります。

技術スタック

開発中に苦労したこと

やること・分からないことがとにかく多い

個人開発で1からサービスを作る中ではとにかく

  • やること
  • 決めること
  • 考えること
  • 分からないこと
  • 調べること

がこんなにも多いのか、と常に思っていました。

「やること」ひとつとっても、想像していたよりもやったことがないこと(= 分からないこと・調べること)がたくさんありました。*1

特に一番難しかったのは「やらないこと」を決めることです。サービスの構想を練っているとあれもこれもとやりたいことはたくさん出てくるのですが、すべてを実装していてはなかなか完成しません。本当に必要なことに絞って、リリースまでの最低限実装することを決めることにしました。

「考えること」が多いというのは、例えばボタン一つとっても

  • どんな文言にするのか
  • どこに配置するのか
  • どの色・サイズにするのか

と考えることがたくさんあります。

こうして1からサービスを作ってみると普段利用しているサービスでも、この仕様やUIは苦労して考えられたんだろうな〜と作った側の気持ちになるようになりました。

誰もやったことがないことをやる難しさ

TwiCode では新規作成画面から「画像を作成」ボタンを押した後、次の画面に遷移するまでに

  1. (JavaScript側) 画面のDOM要素を画像に変換
  2. (JavaScript側) その画像をデータURLとしてパラメーターでRails側に渡す
  3. (Rails側) パラメーターに渡されたデータURLをActive Storageに登録する

をしています。

別の記事で詳しく書いたのでこちらを参照してください。

yana-g.hatenablog.com

この一連の処理はそのまま参考にできそうな記事や資料がなく、ライブラリの選定から実装まで自分で考える必要がありました。

ライブラリを見つけるところから、そのライブラリをRailsに導入するまで一つ一つ手探りで進めていきました。 1人で解決できたわけではなく、メンターや受講生の方にはとても助けて頂いたおかげで実装までたどり着くことができました!

画面上で作成した画像をActive Storageに登録する必要があったのですが、canvas形式をRails側に保存する方法が分からず苦労しました。幸運にも同じ時期に自作サービスを作成していた@obregonia1 さんが同じような画像作成処理を実装しており、その処理を参考にさせてもらいました。本当にありがとうございます!

この実装を通して、誰もやったことがないことや不確定のことを実装として落とし込むことの難しさを実感しました。苦労をした分、このサービスの技術的な見どころにもなったと思っています。

開発中にやってよかったこと

自分1人で1からサービスを作ることは、前述したようにとにかくやることが多い上に、自分しか開発を進めてくれる人はいません。

そこで自分は以下のような工夫をしました。

進捗をこまめに共有した

自作サービスの進捗報告会で進捗を報告できるようにした

フィヨルドブートキャンプで毎週水曜日の夜行っている自作サービスの進捗報告会があります。そこで自分は少しでも何かしらの進捗を報告できるようにしていました。1週間の間に何も進捗がなかった場合は水曜の昼間に急いで進捗を出すこともありましたが、それでも報告できる内容ができるので自分の中ではよしとしていました。

自作サービスの課題は締め切りがなくモチベーションを保つのが大変だったのですが、進捗報告会は定期的なモチベーションの補給ポイントになっていました。

リポジトリの動きを共有できるようにした

前述したように週1の進捗報告会はありましたが、週1でしか自分の進捗を伝えられないこと・他の人の進捗が伝わってこないことはモチベーション的な辛さを感じていました。というのも、自作サービスの開発は各自のリポジトリで行うため、チーム開発と比べて自分の進捗が周囲に伝わりにくいうえに他の受講生の進捗も見えにくくなるためです。

そこでもっと頻繁に進捗を共有できるようにするために、komagataさんたちにお願いしてDiscordのWebhook機能を使ってフィヨルドブートキャンプのサーバーにGitHubリポジトリの通知を送るチャンネルを作って貰い、自分だけでなく自作サービスを作っている受講生にも通知を送れるようにしてもらいました。

設定したリポジトリがpushなどのイベントが発生すると以下のような通知がチャンネルに流れてきます。

f:id:yana_g:20211219150746p:plain

リアルタイムで自分の進捗が誰かの目に触れられること、また他の人の進捗が可視化されたことでモチベーションにおおいに繋がりました。

また、自分1人が作業するリポジトリでも「誰かに見られているかもしれない」とコミットメッセージやPRを適当に書かなくなったという思わぬメリットもありました!

分報チャンネルで開発の様子を実況した

フィヨルドブートキャンプが連絡手段として使っているDiscordのサーバーでは、各自で分報チャンネル(Timesチャンネル)が存在します。

私はそこで雑に進捗や分からないことを投稿していました。そこでスタンプなどのリアクションを貰えたり、分からないことに対して受講生やメンター、アドバイザーの方からコメントをもらうことも多々ありました。分報が自作サービス開発の大きな心の支えになっていました。

f:id:yana_g:20211219150808p:plain

f:id:yana_g:20211219150837p:plain

サービスや実装について質問や相談をした

自作サービスでは、たくさんの分からないこと・やったことがないことに直面しました。

フィヨルドブートキャンプの質問タイムでは、よく質問や相談をしてたくさんの手がかりやヒントをもらいました。自分1人で調べて考えることも重要ですが、1時間以上自分で調べても分からないことは人に聞いて解決するようにしました。時には1回の質問タイムで5個ほど質問することもありました。

メンターへの質問だけでなく、受講生の人にも相談するようにしていました。

どんなサービスを考えるかの段階でエレベーターピッチを見てもらったり、実装中の段階では実際のアプリを見てもらったりしました。サービスの新規投稿画面には最後に選んだ言語を自動で表示できるようにする機能があるのですが、これは受講生の方からもらった意見です。

また、相談する中で「楽しみ」「早く使いたい」と言って貰えることがユーザーのいない状況にとってとても励みになりました……!

不安な実装はこまめに確認してもらっていた

フィヨルドブートキャンプの自作サービスのカリキュラムは、一番最後にコードレビューとデザインレビューを提出すると完了扱いになります。

それまでコードレビューをして貰わなくても開発を進めることはカリキュラム上可能ですが、自分はDB設計やリソース設計を実装に入る前に見てもらったり、不安な実装(ログイン処理など)はマージ前のPullRequestをレビューして貰っていました。

そのおかげで全体的に手戻りの作業はほとんどなく、一番最後のコードレビューも少しの修正で済みました。

DB設計やリソース設計を実装前にレビューして貰うのは他の受講生にも参考にしてもらったり、後ほどプラクティスにも追加してもらったりもしたので嬉しかったです。

「いかに1人で進めないか」を意識した

こうしてみると、「いかに1人で進めないか」が自分にとって自作サービスをリリースするまでにたどり着く一番のポイントだったと思います。

技術的に詰まったこともたくさんありましたが、人に相談することで大体のことは解決できました。時にはあまりにやることが多くモチベーションが下がりそうな時もありましたが、進捗報告会や日報・分報で進捗を共有することを目標にすることでモチベーションを維持できました。

人に質問すること・分報を書くこと、分からないことを文章化するスキルなどは、自作サービスより前のプラクティスで続けてきたことで、自作サービスではそのスキルが十分に発揮できました。

「やることが多すぎて全然進んでいる気がしない」と途方に暮れながら開発していましたが、よく人から「安定して進捗が出ている」「順調に進んでいるように見える」と言って貰えることがありました。自分では進んでいる気がしていなくても、客観的に見るとちゃんと進んでいたということは、人前で作業していないと気づけないところでした。

これからやりたいこと

サービスというものはリリースして終わりではなく、リリースしてからが本番だと思っています。

今回デザインレビューをしていただいたken_c_loさんの言葉を借りると、盆栽のようにちょっとずついじりつづけてサービスをいいものにしていきたいです!

自作サービスはリリースして終わりではなく、自分で使ったり人に使ったりしてもらいつつ、日々盆栽みたいにちょっとずついじり続けることにも醍醐味があると思います

フィヨルドブートキャンプでデザインのメンターをはじめて1ヶ月経ちました #fjordbootcamp - 納豆には卵を入れる派です。

リリース前には後回しにして実装できなかった機能の追加や、リファクタリング、テストのガバレッジをあげること、またユーザーへのフィードバックの反映*2などをやっていきたいです。

さいごに

サービスを作るにあたって、サービスの構想から一緒に考えて頂いた@machidaさん、コードレビューや沢山の質問・相談に答えて頂いた @komagata さん、デザインレビューをしていただいた@ken_c_loさん、サービスを作るきっかけになった@tamaki460さん、色々教えて頂いたメンターアドバイザーの@cafedomancerさんやDJの@obregonia1 さん、YOU CAN DO ITしてくれた@eatplaynap329さん、日報に温かいコメントをくれたフィヨルドブートキャンプのメンターのみなさん、Discordの分報などでコメントやスタンプを押していただいたフィヨルドブートキャンプの皆さんにはとても感謝しています🙏

*1:今までやったタスク : https://github.com/yana-gi/twicode/projects/1#column-15988092

*2:使ってみた方は是非 #TwiCode@yana_gis までメンションで是非フィードバックをいただけると嬉しいです!