概要
今まで,自分はバックエンド系のエンジニアですが,ハッカソンを7,8回ぐらい参加してきました.その中で,色々な技術やプロダクトを使ってきて有用だったモノを紹介したいと思います.
私が実際にハッカソンで開発するうえで重要だと思うのが
- 実際にプロダクトが動くこと
- 最速でプロダクトが作れること
- 多人数開発できること
という点で,これらを実現できるプロダクトを中心に紹介したいと思います.あと最後にハッカソンで参加するうえで,小さいですが重要なTipsも紹介したいと思います.
気を付けていただきたいのが,これはハッカソンに参加し,プロダクトを最速で作ることを目指しており,セキュリティ的にまずい部分もあります.
ハッカソンってなに?
ハッカソン(英語: hackathon 、別名:hack day ,hackfest ,codefest )とはソフトウェア開発分野のプログラマやグラフィックデザイナー、ユーザインタフェース設計者、プロジェクトマネージャらが集中的に作業をするソフトウェア関連プロジェクトのイベントである。個人ごとに作業する場合、班ごとに作業する場合、全体で一つの目標に作業する場合などがある。
参考:ハッカソン
大体のハッカソンは,チームを作り,8時間~24時間ぐらいの短期間でスマホアプリやウェブサービスを作るイベントです.私が出たことがあるものだと,Hack Day, teamLab Hack-Day, SPAJAM,魚ッカソンなどがあります.
チャット(slack)
言わずとしれたチャットツールです.普通は会社内で使ったり,遠隔にいる人とチームで使うイメージがあると思います.対面で行うハッカソンでメリットがあるか?というと,
- ハッカソンの事前準備をする際の進捗確認・共有になる
- 素材の受け渡しが楽になる
例えばどういうケースで有用か?というと,開発サーバーへのログインに必要な情報を共有したり,技術的にハマった時に,手分けして調べたときのリンクを共有するために有用だったりします.また,アプリの開発をしていると画像の差し替えや,サイト用の素材も軽いものであれば十分に渡せます.また,プレゼンを作る際の実際のデータを受け渡しする際にも有用です.
一方で,「slackでないといけないか?」というとそうでもないです.ほかにもチャットワークやFacebook Messenger等があるので,特にこだわる必要はないです.
重要なのはコミュニケーションコストや素材の受け渡しコストを最小限に落とすことです.
共用サーバー(Docker)
言わずと知れたDockerです.共用サーバーはあったほうが便利な場合もあるので作っておくことが多いです.
最近,メンバーで共用環境で使ったDockerfileがあるので,それを貼ります.
FROM ubuntu:16.04
RUN apt-get update && apt-get -y upgrade && apt-get install -y build-essential libssl-dev libreadline-dev zlib1g-dev language-pack-ja
RUN apt-get -y install openssh-server ufw curl
RUN mkdir /var/run/sshd
# 1人分のユーザーの設定 --ここから--
# ユーザーの登録(kotauchisunsun,password)
RUN useradd -m kotauchisunsun && echo "kotauchisunsun:password" | chpasswd && gpasswd -a kotauchisunsun sudo
RUN mkdir -p /home/kotauchisunsun/.ssh; chown kotauchisunsun /home/kotauchisunsun/.ssh; chmod 700 /home/kotauchisunsun/.ssh
# ユーザーのSSH鍵の登録
ADD ./authorized_keys /home/kotauchisunsun/.ssh/authorized_keys
RUN chown kotauchisunsun /home/kotauchisunsun/.ssh/authorized_keys; chmod 600 /home/kotauchisunsun/.ssh/authorized_keys
# 1人分のユーザーの設定 --ここまで--
CMD /usr/sbin/sshd -D && tail -f /dev/null
参考:sshできるdockerコンテナをつくるために最低限必要なこと
このDockerfileとssh用のauthorized_keys,private_keyを作ると動きます.
上のDockerfileでは,kotauchisunsunというユーザーを追加し,パスワードをpasswordとして登録し,sudoの権限を与えています.「#1人分のユーザーの設定」の部分を,ハッカソンに参加するメンバー分だけコピペして名前を変えて増やせば全員sshできるようになります.「ハッカソンにだけ使う」ということを割り切れば,秘密鍵をslackなどに張り付けて共有(実際のプロダクトでやったら完全にアウトですが)し,ログインとsudoが動くことを確認しておけば安心です.終わればサーバーごと落とせば母艦のサーバーに影響がありません.万が一,秘密鍵が漏れても,ハッカソンの短期間で攻撃されにくいですし,攻撃の踏台になっても,サービスをストップさせるのが簡単です.
あまりDockerfile自身が作りこまれていないのは,ハッカソン毎で作るプロダクトの種類やライブラリがかなり異なるので,ベーシックなコンテナだけ用意して,あとはチームメンバーに任せるスタイルにしています.
$ docker build -t sshd_image .
$ docker run --privileged -d -p 2222:22 sshd_image
これでDockerを起動し,2222ポートでsshを稼働します.
キモになる点があって,ポートフォワーディングするポートはssh用の22だけです.
こうすると前の話と矛盾が出来ます.それは,「マイクロサービスで組んだほうが良い」と言っているのに,Docker上のサーバーがグローバルのIPからリクエストを受ける方法がありません.そのため,ハッカソンのように何台サーバーが立つかわからない状態で運用するのは,不確定要素が多いことがあります.では,dockerであとからポートフォワーディングを追加する方法があるか?というとあります(参考).しかし,この方法はdockerの動いている母艦のサーバーをいじる方法で,出来ればやりたくない方法です.次節では,この**「dockerで運用したいけど,コンテナ起動後に公開するポートを増やしたい問題」**を解決する方法を紹介します.
あと,わざわざこの内容のsshdをDockerでサービスする必要があるか?といわれると,あります.ハッカソンにおいて時間が一番貴重です.そのため,「あ,sshエラーしたわ.Permission Deniedね.あ,わかるわかる.authorized_keysの権限ミスったのね.よくやるやつ.chmod 600ね.」とかやってる時間は無いです.そんなつまらないところに時間かけるのであれば,安定なモノを使ったほうが便利です.
ポートフォワーディング(ngrok)
一言で説明すると,ポートをグローバルに公開してくれるサービスです.
例えば,Docker内のlocalhostのポート80を公開したいとき,上の公式サイトのバイナリをダウンロードして,以下のコマンドを打つだけで,ポートをhttps付きで公開してくれます.
$ ./ngrok http 80
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Version 2.2.8
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://2c8b91ae.ngrok.io -> localhost:80
Forwarding https://2c8b91ae.ngrok.io -> localhost:80
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
これだけです!これで https://2c8b91ae.ngrok.io にアクセスすると,Docker内のlocalhostのポート80にアクセスが飛んでくるようにすることが出来ます.これでいくらでもDocker内のポートをグローバルに引き回せます!ユーザー登録もいりません!
ngrok自体,無料プランでは色々制限がありますがハッカソンで使う分にはそれほど問題にはなりません.ただ,1点だけ注意が必要で,無料プランは起動するたびにランダムにドメインが変わります.そのため,クライアントのドメインを変えられる機能を実装するか,もしくはサーバー側で一度起動したngrokはドメインが変わらないようにプロセスを立ち上げ続ける努力が必要になります.
静的サーバー(python)
作りたいものがWebアプリの場合,画像やjsを置くために静的なサーバーが必須になってきます.作りたいものが,Webアプリでなくても,デザイナーさんがスマホでUIを確認したいときのために,スマホのブラウザで簡単に現在のUIの具合が見れるサーバーがあったほうが便利な場合もあります.
一般に,静的なファイルをサービスすると,安定で速いのはnginxですが,個人的には導入がめんどくさいです.そこで私は,
$ python3 -m http.server
で立ててしまいます.これは実行したディレクトリが,そのまま8000ポートで公開されます.したがって同じディレクトリにhtmlやcss,jsを置けば即座に見ることが出来ます.これも先ほどのngrokでポート転送してやれば,見る分には問題はないです.
ファイル転送(Cyberduck)
MacとWindowsの両方で動くGUIのscpのクライアントです.実は先ほど共用環境でsshを動かしていたのはこのためでもあって,CyberduckでGUIの操作でファイル転送出来るのは,デザイナーさんにとって便利だと思います.これには開発側にもメリットがあって,わざわざデータを本番化するのにエンジニアがデプロイすると,それだけで時間がかかりますし,デザイナーさんも"待ち"が出てしまいます.これではプロダクトの開発効率が落ちてしまいます.そのため,デザイナーさんも自分たちでデプロイが出来るようにしておくと両方にとって得だったりします.
ハッカソンのBEアーキテクト
1人1サーバーのマイクロサービスをおススメ
します.理由は3つで,
1. コードの結合にコストがかかる
2. 個人の力と環境を最大限生かすことが出来る
3. 開発が困難になった時,機能のデグレがしやすい
個人的な経験として,コードの結合部分が一番時間がかかることが多いです.私は,ハッカソンでは「動くコードを書くこと」を重視しており,クラスの分割や,プログラムの構成が中途半端で,仕事で書くような綺麗なコードにならない場合が多いです.そのため,同じソースコードを複数人が触ったり,機能が足りなくて勝手に関数のインターフェースを変えたり,頻繁にコンフリクトが起こります.ハッカソンを行っている間に,誰かがコードを触るたびにコンフリクトと修正が起こったりすると,開発速度が落ちてしまいます.また,コードをgithubからプルしたせいで動かなくなって,そのリカバーに時間を取られると,プロダクトが全く動かない状態が長期化し,精神的に追い詰められることもあります.そのため,「コードのマージは出来れば避ける」「コードのマージをするにしてもクラスのインターフェース設計,機能分割の粒度に注意を払い,同じソースコードを触らないようにする」というのが,個人的な戦略です.
先ほど話した「コードのマージはできれば避ける」というアプローチだと,どのように多人数開発状態で機能的に結合するか?となります.個人的な解はマイクロサービスとして結合するのがベターです.いわゆるREST APIで組むのが一番楽だと思います.本当のプロダクトレベルでREST APIを作るのは結構大変です.変数のバリデーションだったり,きちんとしたエラーハンドリングからの復旧.ステートフルなAPIを作るための工夫等々色々考える点は多いです.しかし,ハッカソンの場合,動くことが大前提なので,その辺を一切無視できます.個人的に**一番楽だと思うのは,基本はPOST,URLのエントリポイントを分け,ボディはjsonにしてしまう.**という案です.大体のプログラミング言語で,httpのリクエストはできますし,jsonも作ることが出来ます.サーバーサイドだとhttpは普通に受けられますし,言語標準でjsonのパースも大体あるので,考えることが少なくて済みます.
ハッカソンの特性上,「技術的にチャレンジ」することが多いです.例えば,新しいガジェットであったり,機械学習のライブラリであったり,こういうチャレンジは面白いですが,環境周りで詰まることも多々あります.この環境周りで詰まると本当に大変で,プロダクトが一切動かなくなる場合もあります.それが多人数が共有の開発環境を使い,個々が好き勝手にライブラリをインストールし始めると,動いていたものが動かなくなることもあります.そのため,1人につき1サーバー,1機能のように組むと,プロダクトとして動くものが作りやすいです.これには色々なメリットがあり,個人個人でサーバーを立てるので,個人のやりやすい開発環境で作成し,プロダクトを動かすので,開発速度がでやすいです.また,マイクロサービス化して,モジュール同士を疎結合しておくと,何かの機能が動かなくてどうしようもなくなったとき,そのモジュールをサーバーレベルで切り離して,デグレをしてプロダクトを作ることができるので,「プロダクトが動かない」ということを避けることが出来ます.
ただこれらは本当にサーバーサイドだけの話をしています.iOSとAndroidの開発だと,コードの共有は必須になると思います.実はこれは個人的な課題でもあって,**ハッカソンで多人数でスマホアプリを作ると地獄を見ることがかなりあります(特にGUI周り).**そのためスマホアプリの場合は,最終的な機能連結する開発者の1人がすごくパワーを必要としている節が個人的にはあります.
小さいが重要なハッカソンTips
開発環境,ライブラリの導入とチュートリアルの実行は必ず事前に
ハッカソン中に開発環境の構築やライブラリの導入をやっていると,いくら時間があっても足りません.先にやっときましょう.それと一度サンプルコードをビルドして確実に動くことを確認しておくと,作りこみに集中できます.
ガジェット系ハードは複数人が同一のものを動かせるように
最近のスタートアップ系のハードは面白くて,そういうハードを使ったプロダクトは"ハッカソン映え"します.しかし,ハッカソンのプロダクトとして,そのようなハードを採用すると,うまく動かなかった場合,プロダクトが瀕死状態になります.そのため,1人だけが動かせる状態にするのではなく,2,3人が動かせる状態にしておきましょう.
電子工作は必ず予備部品を3,4個用意する
僕自身はハッカソンで電子工作はやったことがありませんが,部品は壊れるもの.として複数個用意しておくと良い(らしい)です.
機械学習の"学習"は諦める
ハッカソンは長くても1日,短いと5時間程度です.そんな中で機械学習の学習と,パラメーターチューニングは絶望的です.できるだけ既存のものを使いましょう.
電源タップとポータブルWifiを持って行く
ハッカソンは浸透はしてきていますが,あまり多いとは言えません.それは参加する側だけでなく,運営する側もです.そのため,運営側もノウハウが少なく,ハッカソンの会場の電源の数が足りない.Wifiがダウンして開発が進まない.ということも割とあります.そのため,円滑に開発をするためには,最低でも電源タップが欲しいところです.ポータブルWifiもあるとフェイルセーフになります.
スモールスタートし,ピボットはするものと考える
ハッカソンでプロダクトを作るとき,どうしてもすごいものを作りたいと思いますが,かなり難しいです.そのため,コンセプトを絞り,シンプルに機能を一点突破を狙うほうがやりやすいと思います.しかし,その機能も上手く動かないことも多いです.そのため,第2,第3案もある程度考えて置き,フェールオーバーできるようにしておくとよいです.
当日チームビルドするハッカソンは避ける
**これは個人的な意見ですが,当日にチームビルドするハッカソンは,運要素が強く,ハッカソンに慣れていたとしても難しいと思います.**特に初心者や初参加の場合は,おすすめしないです.自分が相手にタスクを振る場合でも,自分が相手からタスクを受ける場合でも,お互いの実力がはっきりしていないと最終的なプロダクトのクオリティの落としどころを見定めることができません.そのため,急造のチームだとメンバー同士が遠慮してしまって,あまり機能のないプロダクトになってしまったり,お互いの意見が対立してプロダクトの着手が一向に始まらない場合もあります.個人的には,仲が良く,忌憚なく意見が出しあえる3,4人程度のコアメンバーが必要で,アプリエンジニア,バックエンドエンジニア,デザイナーあたりを抑えておくと,安心してハッカソンを楽しむことが出来ます.
動かないプロダクトを見ても心に響かない
「〇〇しようとしましたが完成しませんでした.」「〇〇する予定でした」は避けましょう.ハッカソンの形態にもよりますが,コンテスト終了後,プロダクトを展示して,一般のお客さんに楽しんでもらうものもあります.そういうイベントに来る一般のお客さんは何を期待して,来場するのでしょう?おそらく「短期間でこんなものが作れるんだ!すごい!」「こんなサービス見たことない!」「技術っておもしろい!」ということを体感したいと思って来られる方が多いと思います.そういうときにプロダクトが動かないとなると非常に残念な思いを与えてしまうことになります.それは,おそらくハッカソンを運営する側や審査員もそうだと思います.**最低でもデモができるぐらいには動かしましょう.**というのが個人的な見解です.
まとめ
- ハッカソンで動くプロダクトを作りましょう
- ハッカソンで動くプロダクトを作るために事前に準備をしましょう
- ハッカソンでの突然の仕様変更に耐えられるようにアーキテクトを考えましょう
この記事では技術的な話もしましたが,その他にもある程度知っておいたほうが良いハッカソンのノウハウというものもあります.絶対にこれを守らないといけないわけではないですが,知っていると,楽しんでハッカソンに参加することができます.一番最高の学習はハッカソンに参加することです.ハッカソンを楽しみましょう!Let's Hack Time!!