GitHub Webhook → Discord 通知を飛ばす時に忘れがちなこと(末尾に/githubを付ける)

個人でアプリ開発をしている際、GitHubのIssue・PR作成やコメントなどを自分のDiscordサーバに通知するようにしておくととても便利です。

その手順と、GitHub側で何度かミスった部分をメモしておきます✍️

結論

GitHub WebhookでDiscordに通知する場合は、Webhook URLの末尾に /github を付ける必要があるので注意!

手順

Discord側

  1. 通知を飛ばしたいチャンネルの設定を開く
  2. 「連携サービス」から「ウェブフック」へ
  3. ウェブフックURLをコピー

お名前はご自由に💁

GitHub側

  1. 該当リポジトリのSettingへ 2.サイドバーの「Webhooks」から「Add webhook」へ
  2. 以下の必要項目を入力・設定して下部の「Add webhook」ボタンクリック
    • Payload URL
      • 上でコピーしたウェブフックURLをペーストし、末尾に「/github」を追加
    • Content type
      • 「application/json」に変更する
    • Which events would you like to trigger this webhook?
      • どこまでの範囲で通知した以下の設定。今回は全部通知してほしかったので「Send me everything.」にしました
    • 上記以外はそのままでOK

注意事項

始め、Discord側に通知が来ず、色々調べていたらGitHubのWebhook URLに /github を付けていなかったことが原因でした。

# ⚠️Discord側からコピーしたこのままだとNG
https://discord.com/api/webhooks/{id}/{token}

# ✅末尾に/githubをつければOK
https://discord.com/api/webhooks/{id}/{token}/github

これでちゃんとDiscordに通知されるようになりました🎉

終わりに

これまでも何度か同じことをやっていて、今回も「うーん通知が飛ばないなー」としばらく設定を彷徨っていました😅
将来の自分はまた確実に忘れるので、メモでした📝

Ruby Silverに合格したのでメモなど

先日、「Ruby Silver」こと「Ruby Association Certified Ruby Programmer Silver version 3」を受検し、めでたく合格することができました🙌

www.ruby.or.jp

記録のためにブログを書いていきます📝

受検のきっかけ

Ruby Silverは以前から取りたいと思っていたのですが、なかなか受検することができていませんでした。

昨年11月にフィヨルドブートキャンプを卒業し、年始に「今年こそRuby Silver取らなきゃな〜」と呑気に思っていた矢先、Rubyの基礎力不足を感じる出来事がありました。

やりたいことは多々ありましたがまずこれはRuby Silverを取る機運だろうと思い、勢いで2月7日(土)の受検予約をしたのが1月21日(水)のことでした。

やったこと

予約をしてからは以下の試験対策を中心に行いつつ、気になる部分は公式ドキュメントを確認したり生成AIに類似問題を出してもらうなどして復習していきました。

どれも基本的には「50問やる→採点する→間違えたところを中心にチェック→同じ50問をやり直す」という流れで、1セットで2周解いていました。

あと、特に間違えた問題は必ずirbで実際にコードを実行するようにしました。「ここをこう書き換えたらどうなるかな?」みたいな試行錯誤は楽しかったし、学びも大きかったなと思います。

  • 書籍『最短突破 Ruby技術者認定試験(Silver/Gold対応) 公式テキスト
    • テキスト部分はだいぶ前にひと通り読了済みで、適宜見直していました
    • 基礎力確認問題(30問)と模擬試験(50問)を4セットほどやりました
    • 連続でやり過ぎると回答自体を覚えてしまうので、最後は1週間ほど空けて、前日に最後の1回を解くように逆算して実施しました
  • GitHubに上がっている公式の模擬試験『Ruby技術者認定試験Silver模擬問題
    • 2セットほどやりました
  • Ruby技術者認定試験の対策サイト『REx
    • 7セットほどやりました
    • 一番回数が多いのは、一番手軽にできたからです

受検当日

試験会場は池袋のテストセンターでした。家族も一緒に出かけて、サンシャイン水族館に行ってもらっている間に受検してきました。(僕もサンシャイン水族館行きたかった😇)

試験時間は90分。時間は充分に余裕がありましたが、自信のない問題が10問ほどありました。何度も見直しをして、「よほどの勘違いがない限り自信のないやつが全部不正解でも80点は取れてるはず」という状態で試験を終了、結果は84点でした。
できれば90点以上取りたかったところですが、引き続き精進していきたいと思います。

「合格」の部分、ちょい要素が下にズレているのを修正したい

受検を終えて

試験勉強として繰り返し問題を解いたことで、Rubyの基本的な内容について復習できて良かったです。

時は大AI時代、資格試験の勉強がどこまで役に立つのか?という考え方もあるかもしれませんが、基本的なところから毎回AIに聞いていてはキリが無いですし、AIを使いこなすためにも自分自身の知識をちゃんと定着させていきたいと思っています。なので個人的には受検して良かったですし、勉強の楽しさや達成感を改めて感じることができたなーとも思います。

おわりに

無事合格できて、ホッと胸を撫で下ろしました。
次は基本情報技術者試験を取ろうと思います🚀

www.ipa.go.jp

おまけ1:公式模擬試験にPRを出した

GitHubの模試をやっている途中に問題文の並びに違和感がある箇所があったので、修正のPRを出しました。マージされるといいな✨

github.com

おまけ2(長文):Ruby Silver対策メモ

今回、勉強中に何度も間違えてしまったところやうっかりミスしそうになったことを適宜メモしていました。
せっかくなのでおまけとして載せておきます!

(もしおかしいところがありましたら、そっとご指摘ください🙏)

その他

「その他」から紹介するのも変ですが、カテゴライズしにくかったやつ

  • Stringクラスにto_hメソッドは無い(Arrayクラスにはある)
"hoge".to_h # => エラー
[[:price, 100], [:amount, 5]].to_h # => {price: 100, amount: 5}
  • Stringクラスにbinaryメソッドは無い
"7".binary # => エラー
  • 式展開の省略記法(以下のようにそれぞれ{}を省略可能)
    • "#{$hoge}""#$hoge"
    • "#{@hoge}""#@hoge"
  • メソッド内では定数を定義できない
def hoge
  x = 10
  Y = x < 10 ? "C" : "D"
  puts Y
end
hoge
# => SyntaxErrorが出る

strip, chomp, chop

chomp はAtCoderでよく使っていて無意識に覚えていたので助かりました。

  • strip:文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除く
  • chomp:末尾から改行コード("\r\n", "\r", "\n")を取り除く
  • chop:末尾の文字を取り除く。ただし、文字列の末尾が"\r\n"であれば2文字とも取り除く
  • 上記それぞれ、strip! chomp! chop! の破壊的メソッドもある
s = "hello\n\n"

s.chomp  # => "hello\n"
s.chomp  # => "hello\n" # 非破壊的メソッドのため1行上の結果は無かったことになる
s.length # => 7

s.chomp! # => "hello\n"
s.chomp! # => "hello" # 破壊的メソッドのため1行上の結果が保持される
s.length # => 5

pop, push, unshift, shift

⚠️! が無いけど、全部破壊的メソッド

  • popは、末尾の1要素を破壊的に取り出す。引数nがある場合は末尾からn個の要素を取り出して配列で返す
  • pushは、末尾に引数の値を破壊的に追加する
  • shiftは、先頭の1要素を破壊的に取り出す。引数nがある場合は先頭からn個の要素を取り出して配列で返す
  • unshiftは、先頭に引数の値を破壊的に追加する
a = [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5]
a.pop # => 5
a # => [1, 2, 3, 4]
a.pop(2) # => [3, 4]
a # => [1, 2]
a.push(9) # => [1, 2, 9]
a # => [1, 2, 9]

b = [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5]
b.shift # => 1
b # => [2, 3, 4, 5]
b.shift(2) # => [2, 3]
b # => [4, 5]
b.unshift(9) # => [9, 4, 5]
b # => [9, 4, 5]

concat, append

  • self.concat(other)self(文字列)にotherを繋げる
  • self.append(other)self(配列)の末尾にotherを追加する
a = "hello"
a.concat(" world") # => "hello world"
a # => "hello world"

b = "hello"
b.concat(" world", "!") # => "hello world!" # 引数は複数渡せる
b # => "hello world!"

c = [1, 2]
c.append(3) # => [1, 2, 3]
c # => [1, 2, 3]

d = [1, 2]
d.append(3, 4) # => [1, 2, 3, 4] # 引数は複数渡せる
d # => [1, 2, 3, 4]

find, detect, select, filter, find_all

  • find, detect:ブロックの値が真になる最初の要素を返す
  • select, filter, find_all:ブロックの値が真になる全ての要素を返す
a = [1, 2, 3, 4, 5, 6]

# 最初の1つだけ返す
a.find { |x| x > 3 }       # => 4
a.detect { |x| x > 3 }     # => 4(findのエイリアス)

# 条件に合う全部を返す
a.select { |x| x > 3 }     # => [4, 5, 6]
a.filter { |x| x > 3 }     # => [4, 5, 6](selectのエイリアス)
a.find_all { |x| x > 3 }   # => [4, 5, 6](selectのエイリアス)

ファイルオープンのモード(r, r+,w, w+, a, a+

これ、覚えるのに苦労しました😇

  • r(readの略):読み込み専用(ファイルが無い場合はエラー)
  • r+:読み書き両方(ファイルが無い場合はエラー)
  • w(writeの略):書き込み専用(新規作成 or 開いた時に中身を消して先頭から書き込む)
  • w+:読み書き両方(新規作成 or 開いた時に中身を消して先頭から書き込む)
  • a(appendの略):追記専用(中身を残して末尾に追記される or 新規作成)
  • a+:読み書き両方(中身を残して末尾に追記される or 新規作成)
  • +は全て「読み書き両方」になる
    • r+は、読む+書く
    • w+は、書く+読む
    • a+は、書く(追記)+読む
    • 特にr+w+は同じ意味に見えるが、 r+は「読む」が起点なので、ファイルがない場合にエラー
  • オープンモードを省略したら、デフォルトのrになる
  • rewindは、「先頭に戻る」(ただし a, a+ では読み込み位置は戻るが、書き込みは常に末尾)
# `test.txt` の中身は `"ABC"`とする
File.open("test.txt", "a+") do |f|
  f.rewind # 読み込み位置が先頭へ
  f.write("Z") # a+モードは、書き込みは常に末尾
  f.rewind # 読み込み位置が先頭へ
  puts f.read
end
# => "ABCZ"

product, zip, push, transpose, combination, permutation

combinationpermutation は問題ではほぼ見かけなかったけど、セットで覚えました。

  • product:全組み合わせ(直積)を作る
  • zip:同じインデックス同士をペアにする(要素数はレシーバに合わせる)
  • push:配列の末尾に引数をそのまま1要素として追加する(展開されない)
  • transpose:配列の行と列を入れ替える(要素数が揃っていないとIndexError)
  • combination:順序を区別しない組み合わせ
  • permutation:順序を区別する順列
# productとzipの基本
[1, 2].product([3, 4]) # [[1, 3], [1, 4], [2, 3], [2, 4]]
[1, 2].zip([3, 4]) # [[1, 3], [2, 4]]

# レシーバと引数の要素数が異なる場合
[1, 2].product([3, 4, 5]) # => [[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]
[1, 2, 3].product([4, 5]) # => [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]
[1, 2, 3].zip([4, 5]) # => [[1, 4], [2, 5], [3, nil]]
[1, 2].zip([3, 4, 5]) # => [[1, 3], [2, 4]]

[[1, 2]].push([3, 4]) # => [[1, 2], [3, 4]]
[[1, 2]].push([3, 4, 5]) # => [[1, 2], [3, 4, 5]]
[[1, 2, 3]].push([4, 5]) # => [[1, 2, 3], [4, 5]]

[[1, 2], [3, 4]].transpose # => [[1, 3], [2, 4]]
[1, 2].product([3, 4]).transpose # => [[1, 1, 2, 2], [3, 4, 3, 4]]
[[1, 2], [3, 4, 5]].transpose # element size differs (3 should be 2) (IndexError)

[1, 2, 3].combination(2).to_a  # => [[1, 2], [1, 3], [2, 3]]
[1, 2, 3].permutation(2).to_a  # => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

sub, gsub, slice, scan

⚠️ sub! gsub! slice! の破壊的メソッドがあるが、scanだけは無い

  • sub:マッチした最初の箇所のみ置換
  • gsub:マッチした全ての箇所を置換
  • slice:最初にマッチした文字列を返す
  • scan:マッチした文字列を配列で返す
"hello world".sub(/o/, "0")  # => "hell0 world"
"hello world".gsub(/o/, "0") # => "hell0 w0rld"
"hello world".slice(/o/)     # => "o"
"hello world".scan(/o/)      # => ["o", "o"]

IOクラスのクラスメソッド(抜粋)

⚠️ IOFileの親クラス(superclass)なので、IOにあるクラスメソッドはFileでも使える

  • IO.open # ファイルを開く
  • IO.read # ファイルを読む
  • IO.write # ファイルに書く
  • IO.readlines # 全行を配列で読む
  • IO.foreach # 1行ずつ処理
  • IO.select # IO監視

Fileクラスのクラスメソッド(抜粋)

クラスメソッド系はなかなか覚えられなかった…

  • ファイル操作

    • File.open # 開く
    • File.read # 読む
    • File.write # 書く
    • File.delete # 削除 ⚠️Dirクラスにもある
    • File.rename # 名前変更(⚠️Dirクラスメソッドじゃないけどディレクトリにも使える)
    • File.chmod # パーミッション変更
    • File.chown # オーナー変更
    • File.exist? # 存在するか ⚠️Dirクラスにもある
    • File.size # サイズ
    • File.mtime # 更新日時
  • パス文字列の操作

    • File.basename # パスからファイル名を取り出す
    • File.dirname # パスからディレクトリ名を取り出す ⚠️Dirクラスっぽいけど違う
    • File.extname # パスから拡張子を取り出す
    • File.join # パスを結合
    • File.split # パスを分割

Dirクラスのクラスメソッド(抜粋)

覚え方:Linuxコマンドっぽい名前(pwd, cd, mkdir, rmdir)
Linuxコマンドを覚えていないのでこの覚え方はあまり活用できなかった😇)

  • Dir.pwd # 今いるディレクトリ
  • Dir.chdir # ディレクトリを移動
  • Dir.mkdir # ディレクトリを作る
  • Dir.delete # ディレクトリを削除 ⚠️Fileクラスにもある
  • Dir.rmdir # 同上(エイリアス)
  • Dir.unlink # 同上(エイリアス)
  • Dir.entries # 中身の一覧を取得
  • Dir.glob # パターンで検索
  • Dir.exist? # 存在するか ⚠️Fileクラスにもある
  • Dir.home # ホームディレクトリ

%記法

  • %!...!: ダブルクォート文字列(式展開:あり、%Qの省略形)
  • %Q(...): ダブルクォート文字列(式展開:あり、由来:Quote)
  • %q(...): シングルクォート文字列(式展開:なし、由来:quote)
  • %W(...): 文字列の配列(式展開:あり、由来:Words)
  • %w(...): 文字列の配列(式展開:なし、由来:words)
  • %I(...): シンボルの配列(式展開:あり、由来:Identifiers)
  • %i(...): シンボルの配列(式展開:なし、由来:identifiers)
  • %s(...): シンボル1つ(式展開:なし、由来:Symbol)
  • %r(...): 正規表現(式展開:あり、由来:Regexp
  • %x(...): コマンド実行(式展開:あり、由来:eXecute)
lang = "Ruby"
%w(#{lang} Python Java) # => ["\#{lang}", "Python", "Java"] # 式展開されない
%W(#{lang} Python Java) # => ["Ruby", "Python", "Java"]     # 式展開される

%i(foo bar baz).class # => Array
%i(foo bar baz).first.class # => Symbol

正規表現

語源から覚えるの大切だなと思いました。

  • 小文字は、マッチするもの
    • \d(digitの略):数字(0-9)にマッチ
    • \w(wordの略):単語構成文字(a-z, A-Z, 0-9, _)にマッチ
    • \s(spaceの略):空白(スペース、タブ、改行)にマッチ
  • 大文字にすると「否定」
    • \D:数字以外
    • \W:単語構成文字以外
    • \S:空白以外
  • 位置を示すもの
    • ^:行の先頭(複数行で各行にマッチ)
    • $:行の末尾(複数行で各行にマッチ)
    • \A:文字列の先頭(文字列全体の最初だけ)
    • \z:文字列の末尾(文字列全体の最後だけ)
  • 量を示すもの
    • *:0回以上(a* → "", "a", "aaa")
    • +:1回以上(a+ → "a", "aaa"(""は×))
    • ?:0回か1回(a? → "", "a")
    • {n}:ちょうどn回(a{3} → "aaa")
    • {n,m}:n回以上m回以下(a{2,4} → "aa", "aaa", "aaaa")
  • その他
    • .:任意の1文字(改行以外)
    • []:文字クラス(どれか1つ)
    • [^]:否定の文字クラス
    • ():グループ化
    • =~:マッチした位置(インデックス)を返す。マッチしなければnilを返す
s = "abc\ndef\nghi"
s.scan(/^\w+/) # => ["abc", "def", "ghi"]
s.scan(/\A\w+/) # => ["abc"]

"Ruby123" =~ /\d+/ # => 4
"Ruby123"[/\d+/] # => "123"

"hello" =~ /x/ # => nil
"hello" =~ /l/ # => 2
"hello".match?(/x/) # => false # match? はtrue/falseを返す

進数

  • 2進数 0b、使える数字:0, 1
    • 0b0001(1)、0b0110(6)、0b1010(10)
  • 8進数 0o または 0、使える数字:0-7
    • 0o10(8)、010(8)、0o25(21)、025(21)
  • 10進数 プレフィックスなし、使える数字:0-9
    • 10(10)、010025は8進数になるので注意
  • 16進数 0x、使える数字:0-9, a-f(A-Fも可)
    • 0x10(16)、0x1F(31)、0x90(144)
  • 関連メソッド
  • to_i(基数) 文字列を指定した基数で整数に変換
    • "10".to_i(2)(2)、"FF".to_i(16)(255)
  • to_i(0) プレフィックスから基数を自動判定
    • "0x10".to_i(0)(16)、"0b10".to_i(0)(2)
  • .hex 16進数文字列を整数に変換
    • "0x90".hex(144)、"FF".hex(255)
  • .oct 8進数文字列を整数に変換
    • "10".oct(8)、"77".oct(63)
0x10 # => 16 # 16進数の10は16
010  # => 8  # 8進数の10は8
0b10 # => 2  # 2進数の10は2

"0xFF".to_i     # => 0   # 引数無しなので10進数として解釈、xの時点で変換が止まり0になる
"0xFF".to_i(16) # => 255 # 16進数として解釈。`0x` プレフィックスも認識 → 255
"0xFF".to_i(0)  # => 255 # プレフィックスから自動判定。`0x` → 16進数 → 255
"0xFF".hex      # => 255 # 16進数文字列として変換 → 255

ヒアドキュメントの開始ラベル

  • "識別子"(ダブルクオート):式展開が有効
  • 識別子(クオート無し):ダブルクオートと同じ
  • '識別子'(シングルクオート):式展開できない
  • `識別子`(バッククオート):コマンド出力
name = "Ruby"

# 基本形:終端ラベルは行頭に置く必要がある
a = <<EOS
Hello #{name}
EOS

# <<- :終端ラベルをインデントできる
b = <<-EOS
  Hello #{name}
  EOS

# <<~ :終端ラベルをインデント可能 + 中身の共通インデントを自動除去
c = <<~EOS
  Hello #{name}
  EOS

# シングルクォート:式展開なし
d = <<'EOS'
Hello #{name}
EOS

# <<- と ' の組み合わせも可能
e = <<-'EOS'
  Hello #{name}
  EOS

p a  # => "Hello Ruby\n"
p b  # => "  Hello Ruby\n"(インデントがそのまま残る)
p c  # => "Hello Ruby\n"(インデントが自動除去される)
p d  # => "Hello #{name}\n"(式展開されない)
p e  # => "  Hello #{name}\n"(式展開されない)

【Ruby】sortメソッドのブロックの役割

調べたことのメモです📝

sortメソッド

ary = [2,4,8,1]

# デフォルトでsortメソッドを使う
p ary.sort # => [1, 2, 4, 8]

# こういう書き方もできる
p ary.sort{ |i,j| i <=> j } # => [1, 2, 4, 8]

# 降順もサッと書ける(以下どちらでも同じ)
p ary.sort{ |i,j| j <=> i } # => [8, 4, 2, 1]
p ary.sort{ |i,j| -i <=> -j } # => [8, 4, 2, 1]

# reverseで降順にもできるけど、sortとreverseで2回処理するので非効率
p ary.sort.reverse # => [8, 4, 2, 1]

ブロックなしの書き方は無意識に使っていたのですが、ブロックありで宇宙船演算子 <=> を使う時に何が起こっているのかイマイチわかっていなかったので確認しました。

公式リファレンス

docs.ruby-lang.org

全ての要素を昇順にソートします。要素同士の比較は <=> 演算子を使って行います。

(中略)

ブロックとともに呼び出された時には、要素同士の比較をブロックを用いて行います。ブロックに2つの要素を引数として与えて評価し、その結果で比較します。ブロックは <=> 演算子と同様に整数を返すことが期待されています。つまり、ブロックは第1引数が大きいなら正の整数、両者が等しいなら0、そして第1引数の方が小さいなら負の整数を返さなければいけません。両者を比較できない時は nil を返します。

うーん、これだけではよくワカラナイ😇

宇宙船演算子 <=> のおさらい

宇宙船演算子 <=> は、左辺と右辺を比較して、以下のように結果を返す。

1 <=> 10  # => -1(左辺が小さい)
10 <=> 10 # => 0(等しい)
10 <=> 1  # => 1(左辺が大きい)

sortのブロックは「比較のルール」を定義している

要は、 sort にブロックを渡すと、「2つの要素を比較してどちらを前にするか」というルールを指定できる、という感じで受け取りました。

ary.sort { |i, j| i <=> j }

ブロックの戻り値(-1, 0, 1)によって、sortが並び順を決めてくれる。

戻り値 意味
-1 i を前に i=2 , j=4 の場合、 i を前にしたまま、
つまり順番はそのまま
0 何もしない i=2, j=2 の場合、
何もしないので順番はそのまま
1 j を前に i=4, j=2 の場合、 j を前にする、
つまり ij を入れ替える

sort は内部でこのブロックを片っ端から何度も呼び出し、全体をどんどん並び替えていってくれる、というイメージ。

※実際のアルゴリズムとしてクイックソートアルゴリズムバブルソートアルゴリズムといった仕組みがある(そして sortクイックソートアルゴリズムが適用されているらしい)ことも知りましたが、難しかったのでここでは割愛します🙏

ただ、Wikipediaに載っているそれぞれのGIFアニメーションがわかりやすかったので、そのリンクは貼っておきます!

ja.wikipedia.org

ja.wikipedia.org

降順にするには

i <=> jj <=> i にするだけで、大小関係が逆転して降順になる。

# 昇順
ary.sort { |i, j| i <=> j } # => [1, 2, 4, 8]

# 降順(i と j を入れ替える)
ary.sort { |i, j| j <=> i } # => [8, 4, 2, 1]

# ちなみにこう書いても降順になる
ary.sort { |i, j| -i <=> -j } # => [8, 4, 2, 1]

おわりに

ary.sort{ |i,j| i <=> j }という1行に隠された動きの片鱗を知ることができて、良かったです。

2025年の雑な振り返り

今年も書きます、毎年恒例年末の雑な振り返り。

法人化して6年が経った

  • 今年も1年間色々なお仕事をさせてもらい感謝です🙏
  • 今年は、後述するフィヨルドブートキャンプ卒業のためにお仕事を少しセーブしていた。

フィヨルドブートキャンプ(FBC)卒業

  • 今年イチのトピックはこれ
  • 2021年秋に入会してずっとお世話になっているプログラミングスクール、フィヨルドブートキャンプ。入会から4年1ヶ月を経て、ようやく卒業できた🎉
  • 夏頃の卒業を目指してたけど結局11月になってしまった。時間はかかったけど楽しかったなぁ。4年だもんなぁ、大学と一緒の期間かかっている。

Webアプリ開発

  • 今年は主に3つのWebアプリ開発に関わっていた。どれも楽しかったな〜

rururu

rururu.app

  • 去年の振り返りでも書いていた、プロジェクトFHのこと。
  • 今年は具体的な開発に全然コミットできていなかったので、来年はもっとやっていきたい🚀

CAMPUS

campus.bz

  • フィヨルドブートキャンプの卒業制作、通常「自作サービス」で作ったアプリ。
  • まだ開発予定の機能が色々あるので、引き続きやっていく🚀

Typnix

typnix.com

  • フィヨルドブートキャンプを卒業したらAgentic Cordingで何か作りたいと思ってて、分割キーボード用のタイピング練習アプリを自作した
  • Agentic Cordingでガッツリ作れて楽しかったし、かなり勉強になった。
  • こっちもコツコツ便利にしていきたい🚀
  • まだリリースしたばかりだけど、Cornix人気の波もありお知らせの投稿は想像以上に見てもらえた。

登壇やカンファレンス参加

登壇

Kaigi on Rails 2025

  • 今年もデザインスタッフとして参加させてもらい楽しかった。3年目。
  • 今年は看板持って入り口で案内したり発表者の目の前で「残り3分」みたいなカンペを出す役とかもやって面白かった
  • 当方RubyRailsの学習をここ数年続けていて年々話の内容が面白くなってきて、今年はそういう意味でも楽しかった

生活

  • 引き続き、早寝早起き生活
  • 早朝もくもく会を始めた
  • ルーティン
    • 体重計測→ラジオ体操は完璧、99%できてたはず
    • スクワットは達成率3割くらい?
    • 筋トレ、全然できなかった😇
      • 筋トレに関しては諦めるという判断をしていたのだけど、2026はやっていきたい
  • 趣味の1人語りポッドキャストも毎週欠かさず配信できて良かった
  • Cosenseで書いている公開日記も毎日継続。丸3年が過ぎていよいよ楽しくなってきた
  • 冬に京都、夏に大阪に行った。楽しかった
    • 太陽の塔を初めて拝めた、めっちゃ良かったな〜
  • ドラム
    • 去年ちょろっと書いてたけど、今年はかつてのバンド仲間とスタジオに入れた。年の前半は月イチくらいで入れてたけど後半は止まってしまった、来年もうちょっとやっていきたいな〜
  • 1番の買い物は分割キーボードかなぁ、まだ全然タイピングができないんだけど涙、おかげでアプリ作れたので。
  • 読書
    • あんまり読めなかった。2026年は、「ちゃんと読まなきゃ」とか「記録しなきゃ」みたいなことは気にせず、雑に乱読したい。
  • 映像作品

2025年の総括

1年前に書いた「2025年やりたいこと」も眺めつつ…

  • 2025年は4年間続いたスクールを卒業した、区切りの1年になったと思う。本当は今年のうちにもう一つ新しい取り組みを始めたかったけどそれは来年に持ち越し、改めて報告できるよう頑張る💪
  • スクールの学習に加えて、登壇や開発もたくさんできてとても充実していたと思う
  • 一方、1年前に書いていたやりたいことのRuby Silver取得や英語の技術書を読むことは未達成
  • ポッドキャストにゲストを呼ぶのは達成できた! junebokuさんとhacktkさん。楽しかったな〜

2026年やりたいこと

  • これまで通り、生活リズムを保って家族で仲良く楽しく過ごしたい
    • 去年と一言一句同じやつ。油断すると崩れていくので、常に一番に意識しておきたい
    • そのために、健康面の基盤を整えたい。2025年はかなり学習に軸足を置いて活動していたので、2026年は適度な運動・筋トレを習慣化したい
  • 上述した「新たな取り組み」をやって報告したい
  • 資格を取る
  • アプリ開発
    • rururu、CAMPUS、Typnix、どれもコツコツやっていきたい
  • 分割キーボードでタイピングできるようになる
    • 毎日Typnixやって投稿する

おまけ:Claude作の2025年まとめページ

毎日書いている日記を全部食わせてSpotify風のまとめページを作ってもらったので紹介します。 なかなか面白いページが一瞬でできた。 来年も作ろうと思うので、Claudeが読み込みやすい形式で日記を書いていこうと思った。

https://claude.ai/public/artifacts/59ebd9cc-7065-4f2c-8406-5732fe64a3c2

TokyuRuby会議16で初めての外部LT登壇しました

この記事は フィヨルドブートキャンプアドベントカレンダー2025 の1日目の記事です。

今年から、卒業生の hagi さんが開発されたフィヨルドブートキャンプ専用のアドベントカレンダーアプリでの開催です🎉

hagi0121.hatenablog.com

そして僕は昨年に続いて初日を担当しています、よろしくお願いします🚀

🔖 目次

👨🏻 自己紹介

@sugiwe (すぎえ)と申します。
先日11月21日、CAMPUSというアプリをリリースしてプログラミングスクールの フィヨルドブートキャンプ (以下、FBC)を卒業しました!よろしければアプリのリリースブログもご覧ください🙏

sugiwe.hatenablog.jp

さて、この記事では先日11/29(土)に参加してきたTokyuRuby会議16の話を書きます。
今回はフィヨルドブートキャンプアドカレンダーなので、FBCに関することを多めに書いていきたいなと思います。

ちなみに僕はポッドキャストもやっておりまして、TokyuRuby会議の帰り道に感想などを収録したエピソードも本日同時公開しましたので、よろしければ併せてお聴きいただけると幸いです👂

listen.style

🍶 TokyuRuby会議とは

TokyuRuby会議は、プログラミング言語RubyにまつわるLT大会で、参加者一人ひとりが食べ物・飲み物を持ち寄り、休憩を挟みつつ4〜5時間ずっとLTが続くという会です。

以下、公式ページ からの引用です。

  • TokyuRuby会議は、東京で開催される Regional RubyKaigi です。
  • Ruby に興味を持つエンジニアが集う Tokyu.rb 主催の LT 大会です。
  • 飲み食いしつつ、みんなでLTをして盛り上がろうというイベントです。
  • 抽選LTを実施予定です! 抽選LT発表者の指名は抽選により、当日会場にて行います!当たるかもしれません!
  • 今回も参加者のみなさんの投票により飯王、酒王、LT王を決定します!

僕は今回のTokyuRuby会議が初の地域Ruby会議参加でした。
何名かの方に「これは一般的な地域Ruby会議とちょっと違うからね」と言われて面白かったです笑。

会場は GMO Yours・フクラス さん。めちゃくちゃ綺麗で広くて良い場所だった…!

🐦 FBC関係者が多い

Rubyコミュニティに顔を出せばほとんどの場合にFBC関係者がいる、という感じかと思いますが、今回のTokyuRuby会議では特にその割合が多いような気がして、僕のように初めてでも知っている人がたくさんいてとても参加しやすかったなと思います。

💁スタッフ

まず今回の実行委員長さんがFBCの現役受講生です。(受講生なのに実行委員長、めちゃくちゃすごい!!!)
また、それ以外のスタッフさんもFBCのメンター・卒業生・受講生が揃っており、安心して参加することができました。スタッフ業お疲れ様でした、ありがとうございました✨

🙋登壇者

登壇者もFBCの卒業生・現役生が多くいらっしゃいました。(そして自分も末席に加えていただきました)

  • 登壇者の中のFBC関係者(sugiwe調べ。違ってたらすみません🙏)
    • 通常LT登壇:6名
    • 抽選LT登壇:1名
    • 飛び込みLT登壇:3名

重複もあるので正味9人です。LTが全体で30くらいだったと思うので、なんと登壇者の3割くらいがFBC関係者でした。

自分が特に感動したのは、「こういった場で喋ったことがないので慣れるために喋ります」と飛び込み登壇されていた方がいたことです。その行動力を真似したいと思ったし、そう思って行動した瞬間を見られてかなりグッと来てしまいました。

🙎参加者

参加者の中にもFBC関係者さんがたくさんいらっしゃいました!
(参加者に限らずスタッフ・登壇者まとめての話になりますが)オフラインでお話できる貴重な機会だったので、色々な方にご挨拶できて良かったです😄

💬 LT登壇しました

TokyuRuby会議はエントリーのハードルが低めのLT会ということで、FBC内のDiscordでも「はじめてのLT会(FBC内で不定期開催されるオンラインLTイベント)の次にLTデビューに適している」と紹介されていたので、エイヤー の気持ちで登壇を希望しました。

先日リリースした自作サービスCAMPUSの開発時にやっていたことと絡めて、以下の内容で登壇させていただきました。

speakerdeck.com

緊張しましたが楽しかったです!

LT王には全然届きませんでしたが、なんと自分の発表に1票入っていました!!!コメント欄には一言、「いい」のお言葉。めちゃ嬉しいです、どなたか存じませんがありがとうございます🙏🙏🙏

額縁に飾っておきたい、この画面

とはいえ内容的には色々反省があるので、今回発表した考え方をさらに実践してもっと深めてみたいなと思っています。

✨ LT・ご飯の感想

飲み食いしてたり発表前に緊張していたりでちゃんと聞けなかったものもあるのですが、どれも素敵な発表でした。 ほとんどメモできてなかったので、撮っていた写真などから思い出したものを挙げていきます。

  • Linuxディストリビューションの良さをまだ何も知らないので知りたい
  • H×Hの念能力系統になぞらえてバックエンド系・インフラ系とか分けた系統図、面白かった
  • O'Reilly Learning Platformで前書きの多読してみたい(いいお値段するんだよなぁ涙)
  • 暦に技術負債が溜まっている話、面白かった
  • 「毎日Rubyで開発してるのにgemを作ったことがない」からgemをリリースしたの凄い
  • 息子に勝つために素因数分解ゲーム作ったの凄い(というか息子さんも凄すぎる)
  • 抽選LTで突然ブルパップ銃の話が始まるの凄い
  • minitestの結果で魚を泳がせるの超面白かった

ご飯も、どれも美味しくて最高でした!

  • 牛すじ煮めちゃくちゃ美味しかった
  • 豚の角煮もめちゃくちゃ美味しかった
  • チキン春巻き、梅大葉のやつ美味しかった
  • 酢豚ならぬ酢鶏、美味しかった
  • チーズケーキ美味しかった
  • コーヒー美味しかった
  • ポンデリング.split、食べやすくて良かった
  • 納豆チップス、意外にもとても美味しかった
  • 海苔が巻かれた団子、とても美味しかった
  • ねこねこレモンケーキ、可愛くて美味しかった
  • 柿甘味という和菓子、感動的に美味しかった
  • 転職ドラフトさんのビール 、美味しかった!DAYDREAMをいただきました🍺

ご飯の感想のほうが多くなってしまった…🍖🍡🍗

反省

皆さんのLTを振り返ってみると自分の発表は何かちょっと真面目すぎたというか、中身もさることながらですが構成も発表のお作法に沿いすぎていたというか、もっとこう「自分の興味あること一点突破」みたいな発表をしてみたいなーと思いました。

「時間が決まっているからにはその時間内に収まるようにしなきゃ」と思って準備後半は内容というより発表のことに気持ちが向いていたんですが、なんかそんなお行儀の良いものではなく、「とにかく言いたいことを詰め込む、そして銅鑼がなるまで喋り続ける」みたいなLTはとてもカッコいいなと思いました。

🚀 紹介されていたgemを確認・試してみました

LTで紹介されていた以下のgemを確認・試してみました!
ちなみにこの2つのgemをリリースされたのもFBCの卒業生・現役生です👏
自分もgemをリリースしたい気持ちになりました🔥

inline_partial

rubygems.org

パーシャルに別ファイルに分けずに同一ファイル内に置いておくためのgemのようです。 上でも紹介したCAMPUSで言うと、まさに発表内で紹介したマイページの「参加イベント」「主催イベント」のところは別ファイルのパーシャルに分けていますが、これを単一ファイル内に置いておける、ということになります。

inline_partialの特徴を伝えるために実際のCAMPUSのコードをすごく省略化した上で書いてみました。

# 本当は以下の部分をパーシャルで別ファイルに分けるけど、同一ファイル内に置いておける
<% inline_partial(:event_item) do |event| %>
  <div>
    <h4><%= event.title %></h4>
    <p><%= event.start_date %></p>
    <!-- その他、各種イベント情報 -->
  </div>
<% end %>

<div>
  <h3>参加イベント</h3>
  <%= render_inline_partial :event_item, collection: participated_events %>
</div>

<div>
  <h3>主催イベント</h3>
  <%= render_inline_partial :event_item, collection: created_events %>
</div>

今回は既にパーシャルで別ファイルに分割済みなのとコード量の関係から実際にinline_partialの導入はできていませんが、紹介されていたように「パーシャル化したいけど別ファイルに分けるほどでもない」ときにとても重宝しそうです。

というか、「1つのerb内にまとめて書く」という方針が自分の発表した「Viewファーストな開発」とめちゃくちゃ相性が良いのではということに気が付きました。チャンスがあればぜひ試してみたいです!

METs-advisor

rubygems.org

METsとは、身体活動の強さを表す単位で、安静に座っている状態を1メッツというそうです。知らなかった!

# まずインストール
% gem install mets_advisor

# 実行、あとは質問に答えていくだけ
% mets_advisor

Please select your language / 言語を選択してください: 日本語

1週間の歩数を1日平均で教えてください: 7000
1週間に何日間運動をしていますか?: 5

運動の強度を選んでください: 軽度(徒歩・ピラティスなど)

以下から該当する活動を選んでください: 少し速めに歩く
その運動は1日合計で何分ほどですか?: 20

🎉あなたの身体活動量は理想値を上回っています!🎉
---------------------------------------------------
あなたの身体活動量は【24 METs】です。
素晴らしいですね!これからもこの身体活動量を続け、健康を維持してください!

意外と悪くない結果が出ました🙌
とはいえ自覚としてはちょっと運動不足気味なので、健康に気をつけてもう少し運動しなきゃと思っています🏃

🙏 終わりに

初めてのTokyuRuby会議参加、そして初めてのLT登壇でしたが、とても楽しかったです。
運営チームの皆さま、スポンサーの皆さま、そして参加者の皆さま、どうもありがとうございました!!!

📅 明日のアドカレ

ここまでお読みいただき、ありがとうございました😄

明日のフィヨルドブートキャンプアドベントカレンダー2025は、 kyokucho1989 さんの予定です。

フィヨルドブートキャンプアドベントカレンダー2025 は始まったばかりです、25日までぜひお楽しみください〜✨

組織やコミュニティでクローズドに使えるイベント管理アプリ『CAMPUS』をリリースしました🚀

こんにちは、フィヨルドブートキャンプ(以下、FBC)で学ぶsugiweと申します。

この度、組織やコミュニティでクローズドに使えるイベント管理アプリ『CAMPUS』をリリースしました🎉

チーム内だけで使えるイベント管理アプリ、『CAMPUS』

この記事ではCAMPUSの開発背景や今後の展開、開発の振り返りなどについて書いていきます。

🌟CAMPUSについて

🌍 サービスURL

https://campus.bz/

campus.bz

🎨 サービス概要

CAMPUSは、会社やコミュニティのメンバーだけで使えるクローズドなイベント管理プラットフォームです。

一般的なイベント管理プラットフォームでは、登録イベントは基本的にすべてオープンです。登録ユーザーであれば、どのイベントにも自由に参加申し込みできる仕組みになっています。
それに対してCAMPUSは、会社やコミュニティなど特定のメンバーだけで使えるクローズドな環境を提供しているのが特徴です。

👯 こんな人たちに使ってほしい

CAMPUSは「イベントを通じて組織・チーム内の交流を促進したいけど、うまく運用できていない…」という人たちに使ってほしいサービスです。

  • 社内で勉強会やランチ会、交流イベントを実施しているものの、告知がチャットで流れていってしまい困っているチーム
    • Slackで告知したのに気づかれない
    • 参加者の取りまとめが毎回手作業
  • リモートワークでメンバーが全国に分散しており、オンラインランチや雑談会など、ゆるい交流の場をつくりたいチーム
    • チームの一体感を作りにくい
    • 新メンバーの交流機会が少なく馴染みづらい
  • コミュニティ運営で、イベント管理をもっと手軽にしたい人たち
    • SlackやDiscord上だとイベントが埋もれてしまう
    • Googleフォームでは堅すぎるし、継続運用が面倒
  • 学習コミュニティ・学生団体など、クローズドなメンバーだけでイベントを共有したいグループ
    • 毎月の企画をLINEやメールで案内していて、管理に困っている
    • 気軽な交流の場をもっと増やしたい

📜 開発の背景

CAMPUSには元ネタがあります。今回の開発をするにあたって欠かせない話なので、よろしければお付き合いください🙏

🐣 CAMPUSが生まれたきっかけ

時は2019年に遡ります。

当時、僕の前職であり今でも業務委託で関わらせてもらっている企業で、新規事業立ち上げのお手伝いをしていました。そこでいろいろなアイデアを出しては議論する中で生まれた案の1つがCAMPUSです。

前職企業では「自分で社員旅行の企画を立ち上げて参加者を募ることができる」というユニークな社員旅行制度があります。
それまでは、企画をメールやチャットで集めてエクセル管理して社員アンケートを取って参加したい企画を決めて…というようなやり方をしていましたが、これをWebアプリで実現できるようにしよう、というのがCAMPUSの原型です。

新規事業開発チームではアプリ開発のノウハウもなく、かといってアイデアをすぐに外部の開発会社に発注する予算もありません。そこで、某CMSを使ってさまざまなプラグインを駆使し、最低限必要な機能を持つプロトタイプを作成しました。
まずこのプロトタイプを社内で使ってもらい、その手応え如何によっては新規事業の本流として開発を進めていく可能性もありました。

🔥 解散、そして6年越しの再挑戦

ところがそれからほどなくし、諸々の事情で新規事業開発チーム自体が解散となってしまいました。他のアイデアも進めたりしていたのでとても残念でしたし、開発のためには別の開発会社への依頼も必要だったりしたので、「もし自分に開発する力があれば、もっとスピーディに開発を進められて解散にはならなかったかもしれないのに…」と悔しく思ったことも覚えています。
(CAMPUSプロトタイプ版はその後も社内で使われ続けていましたが、新しい機能追加や改善活動については止まっている状態でした)

そこで今回、FBCの最終課題であり集大成である自作サービスとして、改めて前職で使ってもらえるようCAMPUSをRuby on Railsで開発することにしました。

もっと言うと、僕はCAMPUSを自分の手でゼロから開発できる技術を身につけるためにFBCの門を叩いたと言っても過言ではありません。

6年越しに目標を実現することができ、とても嬉しいです。

🧑‍💻 CAMPUSの使い方

🚀 今後の展開について

CAMPUSは現在ベータ版として無料で提供していますが、将来的に有料プランを導入したいと思っています。

今後のロードマップとして以下のような追加機能を検討しており、その中のいくつかは有料プランの機能として解放できればと考えております。

  • 各種通知機能
    • より便利にCAMPUSを活用するための、メールやチャットツールなどへの通知機能
  • 管理者用ダッシュボード機能
    • メンバーごとのイベント参加状況やイベント作成数ランキングなど、管理者に便利な情報の集約
  • 開催報告機能
    • イベント開催後には当日の写真や振り返り文章などを追加掲載できる機能
  • サブドメイン方式
    • チームごとに teamname.campus.bz のようなシンプルなURLを持てる仕組み
  • イベント画像の自動生成
    • 生成AIを用いてイベント用画像を簡単に作成できる機能




ここからは、CAMPUSの開発で使用した技術や、開発を通じて学んだことについて紹介します。技術的な内容が含まれますので、スキップされたい方は おわりに へジャンプしていただいても大丈夫です!

🛠️ 技術スタック

技術スタックは以下のようになっています。

💡 開発で工夫したこと・学んだこと

ここではCAMPUSを開発するにあたって工夫したことや学んだことを紹介します。

🏢 マルチテナント方式にした

経緯で書いたように、CAMPUSはまず前職の企業で使ってもらうことを念頭に置いたアプリです。一社で使うだけであればマルチテナント方式にすることは必須ではありませんでした。

ただ、せっかくこのサービスをゼロから開発するのであれば、他の企業やコミュニティなど、いろいろな方に使ってほしいと思い、CAMPUSは開発初期時点からマルチテナント方式を採用しました。

ここでいうマルチテナント方式とは、Slack・Notion・esaのように、利用する団体ごとに独立したグループ(スペース)を作成し、その内部でメンバー同士がやり取りしたり情報を共有したりできる仕組みのことを指します。

🎯 オブジェクト指向ベースなコードの書き方

条件判定をする際にはビュー側であれこれ条件分岐をするのではなく、モデル側でメソッドを作って呼び出すだけ、という書き方にするとコードの見通しが良くなります。頭ではわかっていたつもりなのですが実際にはビュー側の条件分岐が多発しており、メンターさんにたくさんの指摘をいただきました。

# 修正前(ビューで条件分岐)
<% if membership.role == 'admin' || membership == target %>

# 修正後
# モデルでメソッド化
def can_edit?(target)
  self == target || admin?
end

# ビューでは呼び出すだけ
<% if membership.can_edit?(target) %>

特にメンターさんに言われて印象的だったのは、「『あれ持った?これ持った?じゃあお出かけするよ』と子ども扱いするかのようにあれこれ尋ねるのではなく、シンプルに『出かける準備できてる?』とオブジェクトに問いかけるだけで済むようにしよう」という言葉です。

🎨 ビューファーストな開発

部分的にではありますが、先にビューを作ってからモデル・コントローラーを実装するという順番の開発をしてみました。

一般的なRailsアプリ開発では、まずモデルを定義して rails console で動作を確認しながら進める、というような流れが多いのではと思います。
それに対して今回は、先にビューファイルを作るというアプローチを試してみました。

これは自分がWordPressで独自テーマを作ってサイトを作成するときによく行う方法をベースにしています。(まず先に静的ページを作ってしまい、その後で必要な箇所でHTMLをPHPに書き換えてWordPressテーマにしていく、という手法)

先にビューファイルだけでそのページを全部作ると、ブラウザで完成版に近い形のページを見ることができて、作っていてテンションが上がります😄 また、完成イメージが明確になるので、必要なデータ構造やロジックが自然と見えてくるという効果もあったように思います。

先にデザインを入れる必要がありますので、デザイン作成を先にやっても良いというケースに限られるかもしれませんが、個人的には結構おすすめの手法です。
(今回はTailwind CSSを導入したので1ページずつビューを先に作るのもやりやすかったなと感じていますし、生成AIの力を借りるともっとラクに実現できそうな気がしています)

💻 その他

その他にも以下などの工夫・苦労・学びがありました。印象に残っているものをいくつかご紹介します。

  • Rails Wayに則ったリソース設計
    • 当初は「招待への参加」をカスタムアクション(new_membership, create_membership)で実装する想定をしていましたが「招待の受諾」を独立したリソース(Acceptances)として捉え直すことで、よりRESTfulな設計に改善することができました。
  • 公開エリアとメンバー専用エリアの完全分離
    • これも当初の想定から改善したものですが、招待リンクは公開エリア(/invitations/*)、チーム管理はメンバー専用エリア(/teams/:slug/*)として、ルーティング構造で完全に分離しました。公開・非公開ページを構造で解決することでコードがシンプルになり、セキュリティ上のリスクも軽減できたと思います。
  • Active Storageの画像アップロード機能
    • Railsでの画像アップはActive Storageが定番ですが、デフォルトのままでは使い勝手に課題を感じました。CSSでアップロードボタンを別途用意したりStimulusを活用してプレビュー機能をつけるなど、少しでも使いやすくなるように工夫しました。
  • enumはinteger型にするかstring型にするか?
    • DB軽量化や将来的な変更柔軟性を考えるとinteger型も良かったのですが、直接DBを見た時の可視性などを考えて今回はstring型を選択しました。何日も悩んだり人に相談したりもして、トレードオフを考えて決めました。enumで扱う型について検討できたのは勉強になったし面白かったです。
  • ユーザーフレンドリーな@付きURL
    • これは自分の好みで実装した面もありますが、メンバープロフィールのURLを/teams/:slug/@:usernameの形式にすることで、直感的なURLを実現しました。(あと、URLに自分のアカウント名が入っていると嬉しい✨)
  • インフラはHerokuを選択
    • リージョンや費用面のデメリットはあるものの、デプロイの容易性や過去の知見を活用しやすいという観点から、インフラはHerokuにお任せしてアプリケーション開発に専念するという作戦を選択しました。
  • Hotwire導入のトライ
    • 全体でTurbo Driveを適用しページ全体の再読み込みを減らしたり、カテゴリー作成・更新の箇所ではTurbo Streamsを活用することで、部分的にではありますが最低限のJavaScriptでシームレスな画面遷移を実現できました。Hotwire導入は必須ではなかったのですが、今後使っていく技術として今回触れられたのは良かったです。

🎊 おわりに

開発にあたって相談に乗ってくださったりレビューをしてくださったFBCのメンターの皆さま、そして輪読会やもくもく会、その他オンライン・オフラインの場で話を聞いてくれたFBCの在校生・卒業生の皆さまに心から感謝しています。これからもよろしくお願いします。

また、僕がCAMPUS開発に改めて挑戦することを快諾していただき、そして現在進行形で協力してださっている前職の皆さまにも感謝を申し上げます。
まだまだ発展途上のサービスですが、ぜひ触ってみて、感想を聞かせてもらえたら嬉しいです。




同じFBC生のシモカワさんも最近、自作サービス『Rubree』をリリースされました!
リリースブログはこちら → Rubular の進化版「Rubree」リリース – Ruby × Rails × Wasm で正規表現をワンストップ管理 - aim2bpgのブログ

Ruby正規表現を学習・テスト・可視化・置換・コード生成まで、ブラウザだけで一度に扱えるワンストップ型ツール

めちゃくちゃ便利かつ完成度の高いサービスで、本当にすごいです✨
これから正規表現を扱う際にはガンガンRubreeのお世話になると思います、素敵なアプリ開発をありがとうございます&リリースおめでとうございます🎉

ソーシャルフィードリーダー「rururu」Closed Beta版の紹介

友人であり尊敬するソフトウェアエンジニアである juneboku さん(旧 june29 さん)と一緒に開発しているWebアプリケーション「rururu」が、この度めでたくClosed Beta版として広く使えるようになったのでこのブログでもお知らせします📣

rururuをざっくり説明

rururuを一言でいうと「ソーシャルフィードリーダー」です。

各種ブログ(noteやしずかなインターネットなどのブログサービスを含む)・各種ポッドキャストYouTubeなど、RSSフィードを吐き出しているウェブメディアであれば、RSSフィードを登録・購読することで、それらの最新情報をキャッチすることができます。

視聴した記事・動画・音声については既読チェック(Pawprint=足あと)を付けられて、さらにPawprintごとに簡単なメモを残すことができます。

また、「ソーシャル」と銘打っている通り、自分の購読しているチャンネルや既読チェックのPawprint・感想メモは他の人からも見られるようになっていて、他のユーザーのPawprintや感想メモから新しいブログ・ポッドキャストYouTubeなど新しいコンテンツに出会うこともできます。

こんな人に使ってみてほしい

  • 「インプットしたいけどSNSでずっと情報収集をしていると疲れちゃうな」
  • 「いろんな人のブログ更新情報をチェックしたいな」
  • ポッドキャストやブログの感想やメモを気軽に残したいな」

といったお悩みをお持ちの方などいらっしゃったら、ぜひ使ってみていただけると嬉しいです!

アプリ・紹介音声

  • アプリはこちら💁
    • https://rururu.app
    • ページ右上の「Login」から「rururuを使ってみたい方」のほうのGoogleログインで進んでいただき、コメントを添えてリクエストをお送りください
  • juneboku さんのポッドキャストに呼んでもらって一緒にrururuについて喋っているエピソード💁
    • listen.style
  • 上記エピソードを受けて僕のポッドキャストでもrururuに触れているエピソード💁
    • listen.style

今回は取り急ぎ告知だけになりますが、追って詳しい話なども書けたらと思っています🚀