世界の開発者と一緒にプロダクト開発してみたい！「Comakers Match」を作りました


これまで、プロダクト開発はほぼ一人で取り組んできました。

正直なところ、チームでやるより一人は気楽だし、許可なしにガツガツ進められます。まさに、マイペースかつ、独断でローンチに踏み切ることもできる。フロントエンド、バックエンド、運用に至るまで、すべてを自分一人で手がけます。やり甲斐もあるし、勉強にもなる。

一人でやってきて思うのは、単にプロダクトをリリースするまでの実作業をこなすに関しては、一人でやった方が効率が良い、ということです。チームが欲しいと思うのは、作業量が多くて困るよりも、悩む時にあります。何を作るか悩む、成長に伸び悩む、ここら辺を第三者として相談乗ってもらえるのと、当事者として取り組んでもらうのではアウトプットがまるで違うわけです。

だからこそ、チーム開発って素晴らしい。今、アメリカにいて、日々ローンチされてるプロダクトを[Product Hunt](https://www.producthunt.com/)で眺めている身としては、こんな人たちと一緒に組んでプロダクト作ってみたいー！勉強になりそー！みたいなことは、よく思ったりします。

![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/fd94be61-3fce-08c8-4c1a-c3e76eb3160e.png)

## 問題

じゃあ、「誰か、一緒にプロダクト作ろうぜ！」と思い立った時に宣言できるツールや、コミュニティって見つかりません。もし、やるとするのであれば、[Indie Hackers](https://indiehackers.com)、[Hacker News](https://news.ycombinator.com)、[Reddit](https://reddit.com)あたりで、こんなアイデアあるんだけど、こんなサービス作ってるんだけど、といった具合にスレッドを立ててみるのが良いかもしれません。

ですが、もちろん、それらのサービスはチーム探し用のプラットフォームではないため、ただ一緒にプロダクトを作る人を探すという目的に関しては最適化されていないように思います。チームを募っている側としては、スレッドだけでは機能が不十分だし、入りたい側としても、仲間探しのスレッドをその他スレッドと区別で探すのは困難だったりします。

## 解決方法

アイデアや、作りかけのプロダクトを持っている人が、サイト内でピッチできるサイトを作ってみました。ピッチをする人は、「自分は一体、どういう人間なのか（Who you are）」、「作りたいと思っているアイデア（What you make）」、そして、「どういう人と一緒に組みたいのか（Whom you need）」をそれぞれテキストで入力して、投稿します。

![preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/68af9da7-f96e-075c-dc3f-907d91d378b4.png)

ピッチは、サイト内の一覧に表示されます。また、ピッチのページをSNSで共有する際には、アイデア部分のテキストが自動で生成されたカードが目立ちます。最近、流行っているTwitterカード型をここで取り入れてみました！

この[Comakers Match](https://comakersmatch.com)があれば、思いついたアイデアをすぐに周りや、メイカー界隈に投げかけられるし、応募の管理もサイト内で簡単にできてしまう。サービスは無料で使えるので、投げた分だけ損するようなこともありません。

## Comakers Matchのサイト構築に使った技術

* Ruby on Rails
* Heroku
* AWS S3
* AWS SES
* CloudFlare

## チュートリアル

### OG画像の生成

必要なGemをインストールします

```ruby:Gemfile
gem 'carrierwave', '~> 1.3.1'
gem 'fog'
gem 'mini_magick', '~> 4.8'
gem 'meta-tags'
gem 'config'
```

Pitchモデルにimageカラムを追加します

```terminal
$ rails g migration AddImageToPitches image:string
```

Uploaderを作成して、書き換えます

```terminal
$ rails g uploader PitchImage
```

```ruby:app/uploaders/pitch_image_uploader.rb
class PitchImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  if Rails.env.development? || Rails.env.test?
    storage :file
  else
    storage :fog
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  process resize_to_fill: [1024, 512]
  process convert: 'png'

  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  def filename
    super.chomp(File.extname(super)) + '.jpg' if original_filename
  end
end
```

CarrierWaveをinitializers配下に設置します

```ruby:config/initializers/carrierwave.rb
CarrierWave.configure do |config|
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
      provider: 'AWS',
      region: 'us-east-1',
      aws_access_key_id: Rails.application.credentials.aws[:access_key_id],
      aws_secret_access_key: Rails.application.credentials.aws[:secret_access_key],
    }
    config.fog_directory = Rails.application.credentials.aws[:bucket_name]
    config.fog_public = false
    config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" }
  end
  
  CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/  
```

Pitchモデルにcarrierwaveをマウントします

```ruby:app/models/pitch.rb
class Pitch < ApplicationRecord
  belongs_to :user

  mount_uploader :image, PitchImageUploader
end
```

Configをインストールします

```terminal
$ rails g config:install
```

OGBのデフォルト画像を`app/assets/images`配下に設置して、OGB情報を設定します

```config/settings.yml
ogb:
  base_image_path: ./app/assets/images/og.png
  gravity: center
  text_position: "0,30"
  font_path: ./app/assets/fonts/Heebo-Regular.ttf
  font_size: 32
  color: "#000"
  indention_count: 60
  row_limit: 10
```

OGB画像の作成モジュールを追加します

```ruby:app/controllers/concerns/setup_ogb_image.rb
module SetupOgbImage
  def build(text)
    text = prepare_text(text)
    img = MiniMagick::Image.open(Settings.ogb.base_image_path)
    img.combine_options do |config|
      config.font Settings.ogb.font_path
      config.gravity Settings.ogb.gravity
      config.pointsize Settings.ogb.font_size
      config.draw "text #{Settings.ogb.text_position} '#{text}'"
    end
    img
  end

  def prepare_text(text)
    text.scan(/.{1,#{Settings.ogb.indention_count}}/)[0...Settings.ogb.row_limit].join("\n")
  end
end
```

Pitch作成時にDescriptionの入った画像を生成する

```ruby:app/controllers/pitches_controller.rb
class PitchesController < ApplicationController
  include SetupOgbImage

  def create
    @pitch = current_user.pitches.create(create_params)
    @pitch.image = build(@pitch.description)
    if @pitch.save
      flash[:success] = "Successfully added a pitch!"
      redirect_to pitch_path(slug: @pitch.slug)
    else
      flash[:alert] = "Failed to add a pitch."
      redirect_to new_pitch_path
    end
  end
end
```

## チーム開発のレシピ

### 相手に期待し過ぎない

プロジェクトに対する想いが強くなっていくと、「早く出したい！」、「もっと良いプロダクトにしたい！」となります。例え自分がテンション上がってきても、必ずしも相手はそうでない場合があります。副業として、ちょっと稼ぎになれば良いくらいの温度感で、あくまで空いている時間でのコミットでやりたいといった感じで。

こうして、マインドセットにズレが生じると、「自分はこんなにやってるのに、全然やってくれないな。」、逆に「本業があるのに連絡しつこいな。」とお互いにストレスが溜まってしまう場合があります。勿論、マインドセットにズレがあるよりは、ない方が良いのは決まっているのですが、これを完全に合わせるというのも厳しいです。

なので、チームで開発しながらも、あくまで個人でやるべきことに取り組み、相手に期待し過ぎないのが良いと思われます。期待をしないにしても、お互いが進めなければ進まない問題もあるので、結託する前にルールを設定しておくのがオススメです。週にどれくらいコミットして、いつ頃までにリリースするかなど、お互いの状況を考慮してスケジュール設定をするのが好ましいでしょう。

### 定期的な打ち合わせ

やり始めても結局、連絡が疎通になってしまい、気が付いたらプロジェクトが流れていたなんてこともよくあると思います。かと言って、毎日のように連絡を取り合うことを強いてしまうと、サイドプロジェクトとして続けるにしては重荷になってしまいます。

こうしたコミュニケーションを避ける為に、毎週、もしくは隔週の頻度で良いと思うので、Web通話などお互いが時間を合わせて話せる機会を提供すると良いでしょう。時間を合わせることで、プロジェクトのことだけでなく、本業の話や、雑談もできて、お互いの仲を深めるようなキッカケにもなります。

### レベニューシェア

序盤で決めておいた方がいいのは、利益を出した時にどういう配分にするかどうかです。また、売却が決まった時の権利も決めておいた方が良いです。共同開発のブログを読んでいるとだいたいのケースが等分の持分に設定して取り組んでいる気がします。

一方で、会社化した場合は、株式比率が等分というのはあまり好ましくないと聞くので、スタートアップとして取り組む予定がある場合は、これを最初から決めるのは危険なのかもしれません。

### 経費精算

サーバー代、ドメイン代をはじめ、プロダクト開発する際に負担になってしまうコストは少なからずあるものです。これは必ずチェックしておき、一つのスプレッドシートなどを用意して、月に一回清算するなどして、相手とフェアな関係を築くようにしましょう。

それから、この経費精算で相手が延滞したり、いい加減な対応をしていく場合は今後プロジェクトを一緒にやっていくのも考え直した方が良いでしょう。お金に対する考え方が合わない人とは後々、揉めてしまう可能性が大きいからです。

## さいごに

最近、同じようなサービスを作ってリリースしてるんですが、基盤となるレポジトリ 作って置いておくと楽チンですね。最初からそうしておけば良かった。スタイルちょっといじって、機能を一部追加しただけだったので、すぐ出来上がりました！

それから、Comakers Matchは、本日付（2019年9月25日）でProduct Huntに参戦中ですので、投票・応援のほど、何卒よろしくお願いしますー！

<a href="https://www.producthunt.com/posts/comakers-match?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-comakers-match" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=169032&theme=light" alt="Comakers Match - Collaborate with makers who build a future product together | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>

## 関連リンク

* [Comakers Match](https://comakersmatch.coom)
* [Product Hunt](https://www.producthunt.com/posts/comakers-match)