フィヨルドブートキャンプの「自分で考えたWebサービスを作る」のカリキュラムでいつも言ってることまとめ。

「作ってみました」と「リリースしました」は違う

「作ってみました」と言うつもりで作ったWebサービスと「リリースしました」と言うつもりで作ったWebサービスは大きく違います。

「作ってみました」はお試し・実験のような意味合いで、自分の実力イコールではないことになります。下記のようないろいろな言い訳のできる余地がある言い方です。

  • 技術の実験なのでデザインは本気ではない。
  • 自分以外の誰かに使ってもらおうとは思ってない。
  • ターゲットは考えてない。
  • マネタイズは考えてない。
  • 本気で作ってない。

それに対して「リリースしました」は下記のように色々と突っ込まれることが予想されるので、それに対して「現時点での全力である」と言えるように作ることになります。

  • 「使いづらいんじゃない?」
  • 「デザインがダサいんじゃない?」
  • 「コンセプトが悪いんじゃない?」
  • 「名前(サービス名)がダサいんじゃない?」
  • 「誰が使うの?」
  • 「これがあなたの作品?」

Webサービスはネットにアクセスできる誰もが1タップで見れるので、業界人だけが見るわけじゃありません。かなりの確率でSNS経由で学生時代の友達や家族も見ます。そう言った視線を想定して全力で作ったモノと「作ってみた」モノはとてつもなく違います。

マンガでいえば「大学ノートに鉛筆で書いたマンガ」と「漫画原稿用紙にペン入れしてトーンを貼った18ページのマンガ」ぐらい違います。

逆に言えば「リリースした」人はそれだけやりきった人なのですごいです。

業界人の見方

Webサービスを作ったことがある人の目も「作ってみた」ことがある人と「リリースした」ことがある人では違います。経験者はその二つがどれだけ違うか分かっているので、「作ってみました」ではなく「リリースしました」と言い切っている人に対する態度は非常に優しいです。

「リリースした」だけで内容よりまず先に「すごい」「おめでとう」です。内容に対する意見はその後です。

就職面接での面接官の見方も違います。「リリースした」人は作り上げる技術だけでなく、サービスのコンセプトやデザイン、UIなどとことん考えたことがある人であると期待できます。

実際に業務でWebサービスを作る時にはそれぞれの専門職の人と協力しながら作りますが、その時にも自分なりに考えて、大変さを分かっていることは生きるはずです。

mentionable gemで簡単にmentionが実装できます。(こういうやつ → @komagata)

komagata/mentionable

インストール

gem 'mentionable'
$ bundle install

使い方

app/models/comment.rb:

class Comment
  mentionable_as :body

  def after_save_mention(new_mentions)
    p new_mentions # => ["@komagata", "@machida"]
  end
end

Commentモデルのbodyにmentionが含まれる文章が保存される場合、mentionable_asでそのカラムを指定したらデフォルトでafter_save_mentionメソッドが呼ばれるので実装して置けばOK。

そのカラムにメンションが含まれていた場合、そのメソッドがコールバックされます。

class Comment
  mentionable_as :body, on_mention: :on_mentioned, regexp: /:\w+:/

  def on_mentioned(new_mentions)
    p new_mentions # => [":komagata:", ":machida:"]
  end
end

コールバックメソッドの名前とメンションを抽出するための正規表現は独自のものが指定できる。

便利メソッド

comment = Comment.create(body: '@nobunaga @hideyosi Hi guys.')
comment.mentions # => ["@nobunaga", "@hideyosi"]
comment.new_mentions? # => true

comment.update(body: '@nobunaga @hideyosi @ieyasu Hi guys.')
comment.mentions # => ["@nobunaga", "@hideyosi", "@ieyasu"]
comment.mentions_were # => ["@nobunaga", "@hideyosi"]
comment.new_mentions # => ["@ieyasu"]
comment.new_mentions? # => true

#mentionsでメンションが取れる。

メンションを自分で実装するときの面倒な仕様として、

「メンションを含むテキストがupdateされた場合に増えた分のメンションだけ欲しい。(updateされるたびに通知が行くとうざい)」

というのがありますが、mentionable gemでは最初から新しく増えた分のメンションだけがコールバックメソッドに渡ってくるので楽です。

それらを自分で取る各種メソッドもあります。

  • #mentions: メンション全部
  • #mentions?: メンションある?
  • #new_mentions: 新しいメンション
  • #new_mentions: 新しいメンションある?
  • #mentions_were: 古いメンション

実際のサービスではコールバックメソッドの中でサイト内通知や通知メールを送ったりすればOK。

BasecampHEYがリリースされましたね。

見れば見るほどBasecamp社のWebアプリの作り方をまとめた本であるGetting Realの内容に従って作られてるアプリだなとGetting RealをバイブルにしてWebアプリ作成を仕事にしてきた我々としては嬉しくなってしまいます。(2007年の本なのに!)

ただ、業界内で「Getting Real良いですよね、私もすごく好きです。」という人は多いですが「え?あんたの作ってるアプリ全然Getting Real的じゃなくない?」ということがしばしばあります。

フィヨルドブートキャンプの最終課題の「自分で考えたWebサービスを作る」ではGetting Realを読んでからどういうサービスなのかを表現するエレベーターピッチを作ることになっています。

しかし「これってGetting Realに書いてあることと真逆じゃない?ホントに読んだ?」ということが頻繁にあります。

そこでわかりやすいようにWebアプリ作成に絞って(組織論などは除外)Getting Realの中から「Getting Real的なもの」と「Getting Real的でないもの」を僕の理解で抜き出してみました。

Getting Real的でないもの VS Getting Real的なもの

シンプルさ

  • 「競合より多い機能」VS「競合より少ない機能」
  • 「多くのコード」VS「より少ないコード」
  • 「様々なケースに対応できるように作る」VS「一般的なケースにのみ対応したものを作る」

オープンさ

  • 「失敗の許されない厳格な雰囲気」VS「失敗を認めやすいオープンな雰囲気」
  • 「クローズドなソフトウェア」VS「オープンなソフトウェア」

機能の選択

  • 「ユーザーの機能提案をなるべく採用する」VS「ユーザーの機能提案にまずNOという」
  • 「ユーザーに何が必要か尋ねる」VS「ユーザーに何が要らないか尋ねる」
  • 「ユーザーが柔軟に設定できるようにする」VS「サービス側で考えた一番良い設定を提供する」

段階的な開発

  • 「長いリリーススケジュール」VS「短いリリーススケジュール」
  • 「最初から大規模なシステムを作る」VS「システムを段階的に大きくしていく」
  • 「ユーザー拡大に備えてあらかじめ人員を揃える」VS「ユーザーが増えてから人員を増やす」
  • 「新たな機能を完璧にしてからリリースする」VS「新たな機能はベータ版として使ってもらって改良する」

ユーザーの声

  • 「自分以外が製品のターゲット・ユーザー」VS「自分自身が製品のターゲット・ユーザー」
  • 「ユーザーサポート専門のスタッフ」VS「開発者自身でやるユーザーサポート」

インターフェースデザイン

  • 「何でもできるインターフェース」VS「切り詰めたインターフェース」
  • 「システムを作ってからデザインを入れる」VS「インターフェースをデザインしてからシステムを入れる」
  • 「アウトラインができる前にディティールに固執する」VS「動くものを自分で使ってみてから必要な部分のディティールを調整する」
  • 「一貫性のあるデザイン」VS「一貫性よりもコンテクストに合わせたデザイン」
  • 「デザインにダミーテキストを使う」VS「デザインに本物の言葉を使う」
  • 「文言はインターフェースとは別」VS「文言はインターフェースの一部」
  • 「ユーザーが使う画面と管理画面を分ける」VS「ユーザーの画面に管理機能を組み込む」

その他

  • 「精巧な仕様書を書く」VS「仕様書を書かない」
  • 「初期費用・長期割引・解約料金を設定する」VS「初期費用・長期割引・解約費用を設定しない」
  • 「最初のアイデアを守り抜く」VS「最初のアイデアが悪ければ方向転換する」 

Getting Realの良さ

Getting Realが衝撃的だったのは多くの点でそれまで良いとされていたことと逆のことを言ったからです。毒にも薬にもならない耳触りの良いあるべき論ではなく「え、そんなこと言い切っちゃって良いの?」というような割り切りと実際にそれを実行してる点に当時の僕らはシビれたわけです。

と僕らが勝手に思ってるので話が食い違うことがあるんでしょうね…。

自分の会社で作ってるサービスや使ってるサービスに対して「ここがGetting Real的」「ここがGetting Real的じゃない」など考えてみるのも楽しいかもしれません。

macデフォルトは古いのでbrewで入れる。

% brew install ctags

vim-tagsを入れる。

.vimrc:

Plug 'szw/vim-tags'

let g:vim_tags_project_tags_command = "/usr/local/bin/ctags -R {OPTIONS} {DIRECTORY} 2>/dev/null"
let g:vim_tags_gems_tags_command = "/usr/local/bin/ctags -R {OPTIONS} `bundle list --paths` 2>/dev/null"

:TagsGenerateする。(.gitがあると.git/tagsに作られるみたい便利)

  • C-]: 定義にとぶ
  • C-o: 前のバッファに戻る
  • C-i: C-oの逆

2020年07月06日修正:bundle showはDEPRECATEDなのでbundle listに修正。(これが原因でtagが読めなくなってた)

Lily58 Proの家用の2台目ができました。(1台目は会社)

Image from Gyazo

今回は遊舎工房さんの組み立てサービスを使いました。

Image from Gyazo

「自作キーボードの 概念が 乱れる!」

ケーブル自作キットはまだ届いてないので仮のケーブルです。

やっぱり馴染んだキーボードはめっちゃ使い易い・・・天国のような使い心地です。

プログラミングスクールのフィヨルドブートキャンプの提出物のレビューでよく指摘するシリーズ。

独自の構造や単語を考える前に、組み込みライブラリ標準添付ライブラリでよく使われている構造や単語(クラス名・メソッド名)で表現できないか考えよう。

独自の構造・単語は作っている人にとってはわかりやすいかもしれないが、それを使う他人にとってはわかりづらい。rubyプログラマーにおなじみの構造・単語でなるべく作ろう。

Bad:

class Status
  def self.make_stat(file)
    {
      username: self.username(file),
      size: self.size(file),
      basename: File.basename(file)
    }
  end

  def self.username(file)
    # ...
  end

  def self.size(file)
    # ...
  end
end

puts Status.make_stat(file) # => {username => 'komagata', :size => 1234, basename: 'ls.rb'}

Good:

class Status
  def initialize(file)
    @file = file
  end

  def to_h
    {
      username: username, 
      size: size, 
      basename: File.basename(@file)
    }
  end

  def username
    # ...
  end

  def size
    # ...
  end
end

puts Status.new(file).to_h # => {username => 'komagata', :size => 1234, basename: 'ls.rb'}

プログラミングスクールのフィヨルドブートキャンプでは毎月オフラインでミートアップという名の飲み会イベントをやっていたんですが、コロナの影響でオンライでのミートアップに移行しました。そのオンラインミートアップにリモートカンファレンスサービスのRemoを使ってみました。

Image from Gyazo

(イベント中の座席画像は撮り忘れたのでイベント終わった後の画像です)

Image from Gyazo

どんなツール?

Remoの特徴はテーブル毎に別れたビデオチャットルームがあり、Wクリックすることで自由にテーブルを移動するように他のルームに移動できるところです。

「あの人と話したいからあっちのテーブルに移ろう」

とか

「他の話題で話したいから別のテーブルに移ろう」

などができるってことですね。

1つの共通の大きなルームだけだと1つの話題しか話せないので全員参加の雑談はしづらいです。要は立食パーティーみたいなフリートークができます。

これが今まで立食で飲み食いするオフラインミートアップをやっていた僕らにはぴったりハマりました。

また、主催者は強制的に全員に見せるプレゼンテーションを開始することができます。立食パーティーで言えば、主催者が「皆さんご注目ください」と言って話すみたいなシュチュエーションです。

そのプレゼンテーションでは、みている人はアイコンをクリックすると挙手することができます。主催者は挙手しているユーザーを選んで壇上にあげることができます。(全員が見ている場に登場することができる)

この辺りはカンファレンスの質疑応答のためにあるイメージですね。

どんな流れでやったか

今回は下記のような流れでミートアップを行いました。(合計2時間30分)

  1. 開始の挨拶・乾杯
  2. 自己紹介タイム
  3. フィヨルドトーーク!によるテーマトーク
  4. 卒業式
  5. フリートトーク

今回の主催・司会進行は私 @komagata と @machida の二名で行いました。

まず全員強制参加のプレゼンテーションを使って、Keynoteを画面共有しての趣旨説明と乾杯。それから一人づつ壇上に呼んでの自己紹介タイム。司会進行の僕らも同じく映っているので、リアクションを取ったり拍手したりできるので進めやすいです。

フィヨルドトーーク!については別のエントリーで紹介したいと思いますが、事前に募集した質問事項を「卒業生の方」とか「メンターの方」などを対象にした質問がくるので読み上げて、対象の人を壇上に読んで聞いていく形です。

フィヨルドトーーク! - komagataのブログ

卒業式は今月卒業された方への卒業証書授与です。壇上に一人づつ読んで僕が証書を読み上げる形です。(実物と卒業記念Tシャツを後ほど郵送します。)

残った時間は本来の各テーブルに分かれてのフリートークを行いました。テーブルを見ているだけでもいくつかのテーブルに有機的に集まっていく姿が面白いです。

主催者・メンターはなるべく各テーブルに分散して、特に初めて参加した方が一人ぼっちにならないようにサポートしていく感じでした。

契約している月150ドルのプランだとイベントは2時間30分までなのでそれを過ぎると強制的に終了します。これはだらだらせずできるのでよかったですが、10分前通知などがあるとよかったですね。今回は手動でアナウンスしました。(全員に強制的にメッセージダイアログを表示させられる)

イマイチな点

非常に満足しているんですが、いくつかいまいちに感じた点も。

全体的にWebアプリとして急いで作った感

他のサービスと比べて動作の怪しい部分やUIのわかりづらさなど最低限のMVP感があります。

プランの縛り

50ドルのプランだと1時間15分までのイベントしかできません。僕らはオフラインのイベントでは軽食・飲み物などを用意してたので150ドルのプランでも全然こっちの方が安いですが、100ドルを超えるとちょっと敷居の高さを感じますね。

録画ファイルがでかい

普段はWherebyを使っていて、Wherebyではwebp形式でものすごく小さく圧縮して保存しておいてくれるので、ダウンロードしてからYoutubeやVimeoにアップするのは早いのですが、数GBとかになるのでちょっとしんどい。

感想

ぴったりくるユースケースは限られるとは思いますが、僕らの用途にはぴったりでした。参加者の皆さんの評判も良く、来月もこれでやってほしいという方が多かったです。今までオフラインでやっていたミートアップは実際に行ける人にとってはいいですが、リモート参加の仕組みを用意してもやはりかなり非対称なコミュニケーションになっていて、特にお酒を飲んでの飲み会でローカルとリモートが混在するのはなかなかうまくできませんでした。

リモートの方が人数が多いですし、ローカルとの不公平感をなくすためにも今後全部これでいいんじゃないかと感じましたね。

先日のフィヨルドブートキャンプのオンラインミートアップにフィヨルドトーーク!を初めて使ってみました。

フィヨルドトーーク!は以前フィヨルドブートキャンプにエンジニア研修で来られたGMOペパボの@akhtさんが卒業制作で作ったペパトーーク!(旧Super Cool Web App)を@akht_ikdさんの許可を得てforkして@komagata@machidaがミートアップ用に改造したサービスです。(「誰に」という項目を追加してデザインを変えただけ)

フィヨルドトーーク!はイベントの時のトークテーマを募集してランダムで表示するアプリです。

Image from Gyazo

Image from Gyazo

匿名で質問やトークテーマを応募できます。この画面を見ればなんとなくわかると思います。

Image from Gyazo

事前に募集しておいたものからランダムで一つづつ表示されます。矢印キーの←→で前と次に話題を移れます。

以前オフラインでミートアップを開いていた時はfork元のペパトーーク!を使わせていただいていました。アプリとしての機能は少ないですが、初対面の人やシャイボーイ・シャイガールが多い場ではフリートーク前のアイスブレイクとしてとても便利でした。

オンラインミートアップでも大活躍でした。スクールという性質上、テーマは質問が中心となりますので、「誰に聞きたい」という項目が増えたことで、聞く相手も明確になって進めやすくなりました。1日ぐらいしかないのに@machida さんがデザインや派手なアニメーションも入れてくれました😍

元のペパトーーク!からオープンソースなのでもちろんこちらもオープンソースです。

サービス自体の方もどなたでも使えますので、オンラインイベントなどでぜひ使ってみてください〜。

プログラミングスクールのフィヨルドブートキャンプの提出物のレビューでよく指摘するシリーズ。

原則、クラス名は名詞、メソッド名は動詞です。例外は下記。

[RubyTips] 変数のように見えるメソッド - komagataのブログ

単純に英語の文章としておかしいメソッド名も多いので注意です。

プログラミングスクールのフィヨルドブートキャンプの提出物のレビューでよく指摘するシリーズ。

メソッド名に同じ名詞が頻出する場合、その名詞をクラス名として抜き出すとスッキリすることが多い。特にそれらのメソッドが同じインスタンス変数を使ってる場合は尚更。

Bad:

class File
  attr_accessor :permission

  def open
    # ...
  end

  def check_permission
    # ...
  end

  def fetch_permission
    # ...
  end

  def permission_characters
    # ...
  end
end

Good:

class File
  def open(path)
    # ...
    @permission = Permission.new(file)
  end
end

class Permission
  def initialize(file)
    @file = file
  end

  def check
    # ...
  end

  def fetch
    # ...
  end

  def characters
    # ...
  end
end