急須で入れたようななにか

記事サムネイル

Media Do Tech Internship 2022(ハッカソンコース)を終えました。

2022年9月14日

15 分くらいで読めます!

概要

前半2日でビジネス企画、後半3日でプロダクト開発を行う5日間のハッカソン型インターンシップ「【ハッカソンコース】Media Do Tech Internship 2022」に参加しました。
ハッカソンで行ったことや得たものについて書き記します。
ここからは敬体でなく、常体でいきます。

株式会社メディアドゥ

インターン先企業は株式会社メディアドゥと呼ばれる出版業界最大のIT企業。
電子書籍の流通事業を始めとするコンテンツ業界を支える会社。電子書籍の流通総額は世界2位を誇る。

個人的な参加の目的

登場人物

ABCDの4チームに分かれて行うハッカソンで私はAチームだった。
Aチームのメンバーは5人+メンターさん。

個人情報保護のため、Aチームのメンバーは絵文字で表す。

🦆👒🌂🐧🍁

私は🌂である。

1日目

ハッカソン概要

ハッカソンのテーマは
「アニメ・マンガ・小説のファンがもっと楽しみたいという気持ちに応えるデジタル時代のサービス」

oViceを中心に使いつつ、MiroやSlackを用いて会議などを進めた。

ハッカソンって放置されるものじゃないの?

これまでインターンシップでない普通のハッカソンに参加したことがあった。
そこでは最終の成果発表以外は放置!って感じだったので、まさか主催者側から何かを提供してもらえるとは思わず衝撃だった……
デスゲームで主催者が攻略法を教えるレベルの驚きである……

体型立ったアイデア出し

チームビルディング

まず自己紹介したり、チームのリーダー決めたり、チーム名決めたりするチームビルディングの時間になった。もちろん全員が初対面のメンバーである。
チームのリーダーは👒さんになった。

その後チームルールを考える時間。
ルールもリーダーも居ないチームが理想的だ!みたいなことが思われがちだが、そんなことはなくて、やっぱりリーダもルールも大事だと思った。

miroで全員で付箋にルール候補を出していく形であり、最終的に私のチームでは

がチームルールとなった。

このルールが行動指針のような形となり、5日間という短い期間でも効果があった。
厩戸王が604年に憲法十七条を作った理由も分かる気がする。

昔サークルで共同開発したとき、ビジネス企画全部ふっとばして「これ作ります!」って開発部分から始めたことをとても後悔した……

マンダラート

次に行ったのが、日本史の授業などで習う曼荼羅を模したマンダラート。
テーマから連想されれるもの、さらにそのテーマから連想されるものを書いていくことでアイデアを出す仕組み。

私は下記のような形のマンダラートを作った。
中心にあるテーマはハッカソンのテーマを指す。

チーム5人分それぞれのマンダラートがあり、軽く考えただけでは出て来ないようなことが幾つもでてきた。

アイデアスケッチ

次にマンダラートのアイデアを組み合わせてアイデアを考えていく。
1人最低3つアイデアを出す時間。
結構難しいと思いつつも、マンダラートのおかげで意外にも出てきた。

私は下記3つをアイデアスケッチとして出した。

他の方のアイデアスケッチの掲載は控えるが、たくさんのアイデアが出た。
私一人では思いつかないアイデアも多く、やはり1人と共同開発は全然違うと感じた。

ハイライト

上記で出たアイデアスケッチから良いアイデアを1人3つ印つけていく。いわば投票スタイル。

こんな感じで。

私の班では🌂のアイデアと🍁のアイデアが同率1位になり、議論の結果「すきつりー」を実装する方向になった。(後ほど変わるため、このアイデアの詳細の説明は省く)

中間報告

VPoEの川田さんが途中経過を見てくださる中間報告タイム。

ファーストマイル戦略大事だよとおっしゃられていた。
世界で3000人に刺さらせる自信があるものがよいということ。ニッチなサービスのほうがあたるらしい。paypalとeBayを例に過去事例が紹介されており、説得力があった。

また他のチームの中間報告に対して、そのサービス実は既にありますみたいなツッコミを入れた上で、LINEとSkypeの話を例に、類似のサービスがあってもアイデアを断念しなくてもよいことをおっしゃっていて、なかなかに興味深い時間であった。

アイデアのブラッシュアップ

アイデアのブラッシュアップをする段階で、中間報告の内容やハッカソンのテーマである「アニメ・マンガ・小説のファンがもっと楽しみたいという気持ちに応えるデジタル時代のサービス」、またメディアドゥのハッカソンであることを鑑みて、「すきつりー」は適切でないのではないかということになりアイデアを白紙に戻した。

議論をしていく中で、マンダラートに上がっていた「考察」良いんじゃないか?となり、さらにメディアドゥという立場を活かせそうな部分を踏まえて、権利問題を解消する考察プラットフォームを作る方針に転換した。

レトロスペクティブ・KPTワーク

1日目最後はレトロスペクティブ。いわば振り返りタイム。
レトロスペクティブの特徴は開発物そのものではなくチームの関係性やプロセスに着目すること。

まずKeep(今回良かったこと)を挙げ、その後Problem(今回問題だった所)を挙げ、それをもとにTry(改善すること)を挙げていく。

KPT自体はこれまで取り組んだことあったが、個人的に良いなと思ったのは、下記フォーマット。

このような形でTryに縦軸と横軸が用意されており、KeepとProblemを見ながらTryの位置を緊急性と重要度に応じて可視化しながら配置できる。

レトロスペクティブだけでなく、日報をSlackで提出する時間も設けられていた。
振り返りは大事。

分断するチーム

1日目はアイデアを深めていく中で話が噛み合わなく怪訝な雰囲気になることが多々あった。

一番の原因はドメイン知識が統一されていないことだったと考えられる。
考察プラットフォームでの「考察者」は誰を指すのかという前提(誰かにとっては専門の考察者であり、誰かにとっては一般ユーザーであるなど)が違って話が噛み合わなかったり……
ドメイン駆動設計とかそういったものが持て囃される意味が痛いほど分かった。

他にも役割分担がきちんとできていない(誰が議事録?誰がMiroで図示する?)点も課題であった。

正直、初対面のメンバーで1日目からスムーズに進行するほうが難しい気もするが、この件についてはきちんとレトロスペクティブの時間に挙げることで、次回の改善点とすることができた。

併せて、口で話すだけでは伝わりにくいと思い、図にまとめるなどした……

やはり音声コミュニケーションには限界あって、Miroで図示できる環境は偉大だった……

2日目

体型立ったアイデア出し

2日目もビジネス企画である。2日目は1日目で決めたアイデアを深めていく時間だった。

ペルソナシート

ペルソナというのはゲームの方ではなく、ユングの定義するpersonaの方。
ペルソナシートでは忠実に架空の人物を再現することで(文脈的に正しい意味での)顧客が本当に必要だったものを考える。

また私の書いたもので恐縮だが、下記のように「考察プラットフォーム」の閲覧者と投稿者に分けてペルソナを作った。

このような形で作成した。

🦆さんが架空の人物の住む地域、年収、住んでいる家のサイズまで考えていて、私ももっと緻密にペルソナを考えればよかったと思った……具体的なペルソナだとConcernsやSolutionsも的確になりがち……

チーム全体でペルソナをすり合わせていき、考察プラットフォームのためのペルソナは最終的に下記のようになった。

価値仮説

エレベータピッチというものがあるらしく、これはエレベータでの移動時間みたいな短い時間でプレゼンする手法。

それをフォーマットにしたものが価値仮説。

ペルソナシートで決めたペルソナを元に私は下記のように価値仮説を作成した。

チーム5人で価値仮説をすり合わせていき、考察プラットフォームのための価値仮説は最終的に下記のようになった。

競合製品や類似製品調べ

考察プラットフォームの競合を調べた所、かなりのサービスが候補に上がった。

先で述べたように既に存在するアイデアの価値が無いわけでは全く無く、いかにして現状の課題をペルソナと価値仮説に沿って解決していくかが大事である。

この過程も機能の方向性などを決めていく中で大変役に立った。

プロダクトのスコープ決め

ここで出てくるのがMVP (Minimum Viable Product)。
残り3日で何を最低限実装するかを考える。

この最低限何を実装するかがハッカソンにおいては結構大事になる。

最低限必要となるユーザー体験を考え、そのフローに併せて実装する開発チケットを作っていく形で進んでいった。

技術選定

2日目最後は技術選定タイム。

私達のチームではフロントエンドにNuxt.js、バックエンドにFlaskを用いる方向で決まった。

またインフラ部分としてはGoogleCloudとHerokuを用いることとなった。

技術選定、特にバックエンドに関しては一筋縄に決まった訳ではない。
👒リーダーが私のTwitterを見ててくれて、ちょっとPHPが得意という点を知ってくれていた。
そんなこともあり当初はLaravel(PHP製フレームワーク)でバックエンドを固めることを検討していた。
しかし、PHPを使える人数がほんとど私しか居ない一方でPythonであれば複数人が使えることが分かり、最終的にはFlask(Python製フレームワーク)の利用で落ち着いた。

一部の人が秀でているPHPを使うか、全体が少しだけど使えるPythonを使うかという点が問題だった。
結果的にどちらが良かったのかは分からないが、私としてはFlaskという触ったことのないフレームワークの技術を習得できてよかった。

この日に環境構築まで行った。
ローカル開発はDockerを採用。PostgresDBをHerokuで使う都合、ローカルもそれに併せたく、docker-composeで全部済ませちゃえって形になった。

レトロスペクティブ

良きメンバーに恵まれ、またリーダーの主導もあり、1日目のような認識の齟齬による怪訝な空気は減った。
もちろん新たな問題は度々生じたが、毎日レトロスペクティブの時間で振り返り改善できた点がハッカソン成功に大きく貢献したと考えられる。

VPoEトーク

お昼にVPoEトークの時間があった。

株式会社メディアドゥのVPoEはHTML5とか勉強会やサブカル業界Developers 勉強会にも登場する川田さん。インターネットではふろしきさんと呼ばれておりピクシブ株式会社の退職エントリーは必見である。
正直このインターンに参加した目的はこの方に憧れてって感じではあった……

VPoEトークではこれまでの日本のコンテンツの歴史に始まり、今日本のコンテンツに起きていること、電子書籍の市場規模、そのなかでのメディアドゥの立ち位置などをお話されていた。

3日目

プロダクト開発

開発開始

開発からは完全にチーム独自でやっていく形になる。

私達の班ではAPIのエンドポイントとその内容を全体で定義した後、バックエンド班🌂🦆🍁とフロントエンド班👒🐧に分かれて作業開始。

2日目から3日目までは休日を挟んでいた。
その期間に🐧さんが開発方向についての認識ズレを修正してくださったり、👒リーダーがサイトデザインを作ってくださったりしていた。
バックエンド班の🌂🦆🍁はFlaskの学習などをした。
私はFlaskが初めてであり、正直他のフレームワークの知識があれば気合でなんとかなると思っていたが、いざチュートリアルを始めて見ると苦戦した。
ただ、公式チュートリアルをやるだけでも相当理解を深めることができた。

私が所属していたバックエンド班は🌂🦆🍁の3人。
3日目は私🌂が本番のインフラ部分を整備し、その間に🦆さんと🍁さんでAPI作りをする形になった。

インフラ部分といってもHerokuとつなぐだけなのだが、されどHerokuであり、かなり苦戦を強いられた。インフラ部分を整えたあと私は画像検索ロジックの実装などをした。

1日目でとりあえずAPIが本番環境で動くところまで達成した。
複数人だと速度が早い。

レトロスペクティブ

この日からはずっと開発日であり、特筆すべき点は少ない。

MVPをもとに比較的順調に開発ができた一方で、ありきたりな機能しかなくないか……?という問題が生じつつあった。

また私としてはバックエンドのファイルがapp.pyとmodels.pyの2ファイル構成であり開発速度が低下していることが過大であると考えていた。

そしてリファクタリングへ

バックエンド班として採用していたFlaskというフレームワークはLaravelやDjangoみたくファイル構造も提供してくれる訳ではなくGinのような形で自分で構造を用意しなければならない。

少ないファイル構成は最初の一歩自体は簡単に実装できる反面、規模が大きくなるに連れて課題が増えていく。
今回は開発期間2.5日程度だったのだが、それでも1日目(残り1.5日)を残した段階で、コンフリクトの問題が生じるようになってきていた。

結局私のエゴであり、逆に迷惑をかけえないが、リファクタリングを任せてもらえることになったので、3日目から4日目にかけてリファクタリングを行うことにした。

開発期間残り1.5日のハッカソンでリファクタリングをする必要があるのかは甚だ疑問にしか見えない気もするが、今後の開発速度向上に貢献できた。

メンターさんとの1on1

3,4日目はチームを担当するメンターさんとの1on1の時間が設けられていた。
1on1といっても堅苦しいものでなく、会社の内部の事情やリーダー職についての業務、メンタ-さんの過去の企業経験を踏まえての就活相談など幅広くお話でき、大変有意義な時間であった。

4日目

終わらないリファクタリング

リファクタリングを3日目の夜に始めたものの、かなり苦戦をした。
何とかファイル構成を決めた後も慣れないフレームワークのエラーが止まらず絶望を感じた。
10時始業なのだが、9:30くらいまでずっとエラーに悩まされていた。
本当にギリギリの段階で何とか治った……

個人開発だと絶対諦めていたと思う。正直9:00くらいまでは絶望だった。
チーム開発だと責任が伴うので、簡単には諦められなかったのが大きい。

最終的には下記のような構造にした。MVCライクな感じ。
特徴としてはFlaskではあまり見られないルーティングをファイル分けした点。
またエントリーポイントとなるapp.pyでの処理をほとんど他のファイルに移動し、ルーティングの登録や初期設定のみにとどめた点。(これは過去のインターンの経験が活かされていたりする。)

ハッカソンでコードの保守性まで考えるのは過多ではある反面、やはりエンドポイントがまとまって1つのファイルで定義できつつ、処理がコントローラーに置かれているのは大変見やすくて良かったと自負している。(が、これまで私が触れてきたフレームワークの影響を受けすぎている感も否めない)

.
├── __pycache__
│   ├── __init__.cpython-310.pyc
│   ├── app.cpython-310.pyc
│   ├── db_init.cpython-310.pyc
│   └── models.cpython-310.pyc
├── app.py
├── command
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   └── init_db.cpython-310.pyc
│   └── init_db.py
├── controllers
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   ├── add_favorite.cpython-310.pyc
│   │   ├── create_articles.cpython-310.pyc
│   │   ├── create_comments.cpython-310.pyc
│   │   ├── get_article.cpython-310.pyc
│   │   ├── get_articles.cpython-310.pyc
│   │   ├── get_articles_by_theme.cpython-310.pyc
│   │   ├── get_comments.cpython-310.pyc
│   │   ├── get_domannaka.cpython-310.pyc
│   │   └── search_by_dialogue.cpython-310.pyc
│   ├── add_favorite.py
│   ├── create_articles.py
│   ├── create_comments.py
│   ├── get_article.py
│   ├── get_articles.py
│   ├── get_articles_by_theme.py
│   ├── get_comments.py
│   ├── get_domannaka.py
│   └── search_by_dialogue.py
├── databases
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   ├── db.cpython-310.pyc
│   │   ├── reset.cpython-310.pyc
│   │   ├── seeder.cpython-310.pyc
│   │   └── setup.cpython-310.pyc
│   ├── db.py
│   ├── reset.py
│   ├── seed
│   │   ├── articles.json
│   │   ├── comments.json
│   │   └── images.json
│   ├── seeder.py
│   └── setup.py
├── middleware
│   ├── __init__.py
│   └── __pycache__
│       ├── __init__.cpython-310.pyc
│       └── cors.cpython-310.pyc
├── models
│   ├── Articles.py
│   ├── Comments.py
│   ├── Images.py
│   ├── __init__.py
│   └── __pycache__
│       ├── Articles.cpython-310.pyc
│       ├── Comments.cpython-310.pyc
│       ├── Images.cpython-310.pyc
│       └── __init__.cpython-310.pyc
├── resources
│   └── gcp
│       └── gcp.json
├── routes
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   └── api.cpython-310.pyc
│   └── api.py
└── usecase
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-310.pyc
    │   └── get_image_url_from_path.cpython-310.pyc
    └── get_image_url_from_path.py

18 directories, 62 files

これによりコンフリクトの解消に貢献できた。
一方でapp.pyとmodels.pyの2ファイル構成を何十ファイルかの構成に1人で行った点は、バックエンド班のメンバーに可読性の低下という迷惑をかけてしまったのではないかと思われ、反省している……

プロダクト開発

絶望の午前

4日目からは👒リーダーがその日の流れを用意してくれた。

1日目からの課題であった役割分担ができていなかったチームとは別のチームかと思うほどの改善だった。

リファクタリングも終わって一段落したと自分の中では思っていた午前であるが、CORS周りの対策、ダミーデータを作るロジックの用意、キラーコンテンツ(新機能)も作らなきゃって形に。

3日目で開発を始めて概ね形となり、3日目から4日目にかけてリファクタリングを行い、4日目に新機能追加という怒号の開発スピード。
私としては、まだMVPの実装もリファクタリングしたばかりでちゃんと動くか微妙な段階なのに、新機能も追加するのまじで……?って正直思っていた。

そこに拍車をかけるようにフロントエンドとの結合準備の段階でAPIを叩くとCORS関連のエラーが出る問題の雲行きが怪しくなっていた。
CORSのエラーは毎度のように直面する問題で、今回もAccess-Control-Allow-Originヘッダを付けてくれるライブラリを導入してぱっぱと済ましちゃえって感じの方針だったのだが、それがどうもうまくいかない。

POST関連のAPIを他ツールからで叩くと明らかにAccess-Control-Allow-Originヘッダがついているのだが、フロントエンドであるNuxt.jsから叩くとCORSのエラーが出てくる。
この問題に数時間悩みあぐね、一旦はCORSエラーをブラウザ側から出させないようにする拡張機能でその場を凌ぐ方針になった。

希望の午後

新機能の実装やダミーデータ登録機能の実装は比較的素早く終わった。
手前味噌ではあるが、3日目から4日目にかけて行ったリファクタリングが功を奏して、複数人での開発速度向上に貢献できたと考えられる。

CORSのエラーに関しては、その後🐧さんが解消方法を見つけてあっさり解決。
結局のところ原因はバックエンド側でのバリデーション不足で、意図しない形式でPOSTが来ると500エラーになってしまうことであった。
500エラーでCORSのエラーが出るのは一見不思議ではあるが、処理の途中でエラーが生じた結果Access-Control-Allow-Originヘッダを付ける処理が走る前の段階でレスポンスが返される結果、CORS関連のエラーが表向きは出てくることが原因であった。
気づけば納得の理由……

バリデーションに関しては必要ではあるものの、ハッカソンではフロントエンドもバックエンドも正しい値が来る前提で設計しており、MVPの実装ではとりあえず見送る方針であった。
結局のところ根本的な原因はMiroで書いていたAPIの仕様とバックエンドで実装していたAPIの仕様が異なっていたことが原因であった……

レトロスペクティブ

4日目になるとレトロスペクティブも洗礼されてきた。
最後の1日頑張ろうという雰囲気になった。

トークセッション

4日目のお昼ごろ、トークセッションの時間が設けられた。
ここではVPoEの方とエンジニアの方が各お題に沿ってお話をする時間であり、メディアドゥを選んだ理由であったり、コンテンツ業界についてであったりをお聴きできた。

5日目

最後の調整

5日目も👒リーダーがその日の予定を事前に用意してくれた。

私🌂と🐧さんは拡張班に任命され、フロントエンド担当の🐧とバックエンド担当の私🌂で最終調整を行った。
フロントエンドの部分を少し手伝ったり、バックエンド部分のバグを潰したり……

その後は想定されうる技術的な質問に対応できるようQ&A集を用意した。

15:10にコードフリーズ。

デモ展示

発表の前にデモ展示の時間があり、oVice上で運営の人が来て作ったサービスを紹介する形に。

私達のチームは本番デプロイを済ませており、誰でも体験できるという強みを活かして、実際に触って貰う形を取った。

発表

ついに作ったサービスをプレゼンする時間が来た。

私のチームの発表は👒リーダー、🦆さん、🍁さんの3人で行われた。
落ち着いた分かりやすい発表であり、特筆したい点としては質疑応答で🦆さんが率先して対応してくださり、ゴタゴタになりがちの質問タイムがスムーズに進んだ。

どのチームもレベルが高かった。

特にBチームの発表はあまりのレベルの高さに笑ってしまった……
1,2点がすごいとかじゃなくて、プロダクトのアイデア、クオリティ、技術、スライド技術、遊び心全部持ってた。

講評と結果発表

結果はBチームの優勝。悔しいけどBチームが優勝することは納得の結果ではあった……

講評ではそれぞれのチームの内容に関して1つずつ褒めてくださって、ちゃんと見てもらえていると感じた。

私の所属していたAチームのメンターさんがAチームが一番すごかったって何度も褒めてくださってとても嬉しかった。

懇親会

最後に懇親会の時間があった。前半後半の2回。
前半はAチームでの懇親会で、VPoEの川田さんが私達のチームに来てお話してくれた。Goについての現場の話が大変興味深く、一瞬で時間が過ぎ去った……
後半はチームの垣根を超えたシャッフル懇親会で、Dチームのメンターさんのお話を聞くことができた。過去のソシャゲ開発現場の修羅場話を聞けて大変勉強になった。

所感

大変充実した5日間だった。

就業型のインターンでは実際のサービスに触れることができる点や現場の雰囲気を知れる点に魅力がある。一方でハッカソン型は0からの開発や、チームでの開発という点が大きな魅力である。

やはりハッカソン型インターンは就業型と比べると現場の雰囲気を知れるかという点では敵わない部分があるが、その企業が重視するものやその企業で働く人がどんな人なのかといった概要をつかむ事はできた。

とりわけ今回のハッカソンでは3つポイントがあると思う。

1つはメディアドゥがバックについていた点である。
テーマがメディアドゥの事業に沿った形であったり、ハッカソン期間中にCEOやVPoE、エンジニアのトークタイム、1on1があるなど、インターンでないタイプのハッカソンとはまた異なる形式であった。
結果としてメディアドゥについて知るということができた。
企業説明会では聞けないマイナスな点やエンジニアの開発指針などより深い部分について知れることができた点が大きい。

2つ目はエンジニアを目指す就活生に不足しがちなビジネス企画部分の思考方法を提供してもらえた点である。
個人開発では意識しにくい部分をペルソナやMVPの考え方など知ることで、今後の個人開発でも役立てるハードスキルを習得できた。

最後に3つ目はバックグランドも技術力も違う面識のないメンバーで協力して開発を行えたという点である。
サークルでのチーム開発などとは一線を画すものがあり、ドメインの認識を揃えることの重要性など、いわゆるソフト面のスキル向上に繋がった。

サブカル業界で言われがちな言葉を使うと、「このインターンからしか得られない成分があった」と感じたインターンであった。