任意の人は質問箱を作るべき

この記事は CAMPHOR- Advent Calendar 2019 1日目の記事です.

こんにちは,あたらんです.

先日自分専用の質問箱を作って,(Web関連の技術を学びたい人や新しい技術を試してみたい)任意の人は質問箱クローンを作ると良いと思ったのでその知見を共有します.

質問箱クローンを作った

質問箱クローンを作りました.良かったら質問してみてください!

f:id:satoarata:20191129000129p:plain

geing.ataran.me

フロントはReact, バックエンドはGoで書いています.

機能

実装した機能は,

  • 質問を投稿
  • 質問をbasic認証でログインして回答
  • 質問一覧を表示
  • 質問
  • 回答個別ページ
  • 質問画像の生成
  • 質問画像をOGPに設定

です.

Twitterの自動投稿,新しい質問の通知も実装したかったですが,一旦モチベが燃え尽きたのでまだ実装してないです.

構成

構成はこんな感じです.

geing

作った経緯

主なモチベとしてはフロントやクラウドで完結するものばかり作っていてAPIサーバーなどを1から作ったことがなかったので,簡単なWebサービスを1から作ってみたいと思っていました.

そこで,機能要件的にシンプルでAPIサーバーの設計や実装,インフラまわり (Dockerやリバースプロキシ,VPSなど) に入門するのに丁度いいということで質問箱を作ってみることにしました.

GoとReactを選んだのは

  • フロントはVueしか触ったことがなくてReactも入門してみたかった
  • Goが周りで流行っているので触ってみたかった

というのが主な理由です.

また,CAMPHOR- のOBの @genya0407 さんが以前Rustで質問箱クローンを作っていて結構参考にさせていただきました.🙏

任意の人が質問箱を作るべき理由

タイトルにもある通り,任意の人が質問箱を作るべき理由を述べたいと思います.任意の人というのは少々大げさですが,僕みたいに新しい技術に入門してみたい任意の人に質問箱は色々と丁度良いです.

理由1: 機能要件がシンプルである

質問箱は機能がシンプルなので,作ることでWebサービス開発を無理なく網羅的に学べると思います.

新しい技術を試してみたいときに丁度良いです.

理由2: まあまあ使ってもらえる

本家質問箱でまあまあ質問が来る人は,自分で作ってもまあまあ質問が来ます.Webサービスを作っている途中で「これ本当に需要あるのか…?」とか考えてモチベが消える心配がありません.

実際に学べた技術

僕の作った質問箱で学べた技術を具体的に挙げます.

フロントのフレームワーク

Reactに入門できました.質問のリストを表示するトップページと,個別の質問と回答を表示するサブページという構成なので,コンポーネント,SPAなどの概念を学ぶのに丁度いいと思います.

APIサーバーの設計

APIサーバーの設計 (ディレクトリの分け方など) に気を使ってみました.具体的には,Goで書いているのでGoらしい(?)ボトムアップでの設計を意識してみました.ここで言うボトムアップというのはDDDやクリーンアーキテクチャのように現実をモデル化して設計するのではなく,システムを構成するコードの断片があって,それらを組み合わせてシステム全体を作っていくという意味です.

この話題に関してこれ以上深入りするとマサカリが飛んできそうなのでこの辺にしておきます.

この辺はCAMPHOR- の先輩に色々教えていただきました.

DBの設計,操作

このアプリのDBは設計するというほど複雑ではないですが,質問と回答のテーブルは分けたほうが良さそうだったという知見は得られました.(後述)

Goは高機能なORMがあまりなさそうなので,SQLを書く練習にもなります.

ページネーションを実装すると,SQLのOFFSET句はid1から順番に見ていくのでO(n)で重いという知見なども得られました.

インフラ

インフラ周りを全然触ったことがなかったので,クラウドに頼らずにVPSでホストしてみました.リバースプロキシやDockerに入門できました.Dockerまじで楽.

CI/CD

CircleCIに使ってみた.デプロイがすごく楽だった.

CORS

CORSめっちゃハマった.

その他の細かい学び

動的ルーティングの動的なOGPの対応

SPAで動的ルーティングの動的なOGPに対応させるのは地味にめんどくさいです.

どういうことかと言うと,何も考えずにSPAを静的にビルドすると個別回答ページなどのAPIサーバーに依存した動的なページは生成されません.Twitterなどは基本的にOGPイメージをクロールするときJavaScriptを実行してくれないので,ビルド時に静的なページを生成しておくか,SSRにする必要があります.

今回は新しい回答が追加されるタイミングでAPIサーバーでNetlifyのビルド用Webフックを叩いて,静的なページを生成しています.

ページネーション

ページネーションを実装するのも地味にめんどくさいです.

トップページには回答済みの質問一覧が表示されるのですが,質問は質問にauto incrementなidで管理しているので,ページをクエリとして10件ずつ取ってきたい場合に何も考えず

WHERE id < page * 10 
~
LIMIT 10

とかするとうまくいきません.

nページ目を取ってくるのを素直に実装しようと思うと質問id1から ページ*10 件分の回答済みの質問をいちいち確認していく必要があります.

しかし,「n件目を表示したい」という需要はあまりないと思ったので,今回は最新の質問から順に取ってくる形式にしました.(infinite scroll的な)

フロント側で現在持っている最も過去の質問idをオフセットとして保持しておき,それをクエリとして

WHERE id < offset
~
LIMIT 10

このようなSQLを叩きます.

この点に関しては,そもそも質問と回答を1つのテーブルで管理している時点でミスった感もあります.

まとめ

  • 質問箱はシンプルなので新しい技術を学ぶのに丁度良い.
  • 需要も一定数あるのでモチベが続きやすい

みなさんも新しい技術を学ぶきっかけに質問箱を作ってみてはいかがでしょうか.

チームラボのインターンに参加した

こんにちは.あたらんです.

9月の後半2週間でチームラボのインターンに参加してきました!この記事ではインターンの内容,雰囲気,学びなどを紹介します.

チームラボという会社

まず,チームラボがどんな会社なのかを紹介したいと思います.

チームラボはデジタルアートやメディアアートを作っている会社というイメージが強かったのですが,他にもWebアプリやモバイルアプリを作るチームもあったり結構なんでもやってます.インターンで選択できるコースも10以上あり,僕は今回フロントエンドチームで参加しました.

参加した経緯

今回チームラボのインターンに参加した経緯,理由について書きます.

僕は今学部2回生で同期にはインターンに行くという人はあまりいなかったのですが,CAMPHOR- というIT系学生コミュニティの先輩がインターンの話を度々していて,「インターンはいいぞ」 的なことを言っていたので申し込んでみました.CAMPHOR- はいいところです.

また,僕が将来就職企業に求めるものとして,遊び心とかクールなプロダクトを持っているということを重視しているので,それにチームラボは当てはまっていると思ったのも1つの理由です.

とか言いつつも参加した主な理由としては,単純に初めてインターンに申し込んでみたら受かったので嬉しかったというのも大きいです.笑

チームラボのインターン

チームラボは通年インターンとサマーインターンの2種類(5月〜9月末がサマーインターン,10月〜4月末が通年インターン)で募集しており,僕はサマーインターンの募集が始まる前に待ちきれずに通年インターンで申し込みました笑.期間は8, 9月の2ヶ月で申し込んだのですが,結果的にはサマーインターンでの参加という形になって悲しかったです(それはそう).

チームラボのサマーインターンは1~4ターム(8, 9月の前後半)に別れており,僕は第4タームで参加しました.選考はインタラクティブ,Webアプリケーション,フロントエンド,iOS, Androidなど,様々なチームごとに選考して,そのチームに参加する感じになります.

必ずメンターが付きます(2:1の場合もあります) .内容は実際の業務をする場合もあれば,用意された課題をこなす場合もあります.これはチーム, メンターごとに結構異なるみたいです.

業務内容

業務内容に関して書きます.

僕はフロントエンドチームで参加しました.フロントエンドチームでは実際の業務に参加させてもらえました.チームと言ってもフロントエンドチームのインターン生は僕しかいませんでした😂.

僕がやった内容は,実際のプロダクトで追加したい機能が実現可能かどうかを検証するというタスクでした.具体的には,「パスポートをフロントエンドだけで(サーバーと通信せずに)OCRして,パスポート情報の入力補助をする」という機能の検証をしました.検証タスクだったので書いたコードがボツになるかもしれないという緊張感がありました.

技術的な話をすると,MediaDevices.getUserMedia() メソッドでカメラの映像を撮ってきて,それをcanvasに一旦描画しつつクロップして,TesseractというOCRエンジンをラップしたTesseract.jsというライブラリを使ってオンデバイスOCRして結果を表示する,という感じで実装しました.

実装上のつらみ,ハマりポイントをいくつか挙げると,

  • カメラの縦横比,縦横の概念がデバイスによって違ったのでその対応
  • Tesseract.jsがデフォルトの設定だと精度がいまいちだし,結果が出るまで時間がかかる.(学習データをパスポートのフォントだけに特化したものに変更すると精度も速度も改善した.)

という感じで,大部分の時間を認識精度の向上に費やしたので,「フロントエンドとは…?」という感じになっていました笑.チームラボのフロントエンドチームは,Webの技術を応用してWeb以外の領域にも積極的に踏み込んでいくチームです.

技術とは関係ない話をすると,パスポートの仕様にめっちゃ詳しくなりました.パスポートにはMRZ(Machine Readable Zone)と呼ばれる機械でOCRして読み取る用のエリアがあり,その部分の仕様を調べたりしました.MRZのどの部分になんの情報が書いてあるという仕様だけでなく,読み取った文字列が正しいかどうかを検証するためにチェックサムで照合するという仕組みがあり,大学で履修していた情報符号理論の知識が役立ったりしました.意外なところで コンピューサイエンスが感じられて面白かったです.

また,そのタスクは1週間ちょっとで終わってしまったので,後半の2日(そもそも3連休が2週連続だったので,2週間とはいえ出勤は8日間でした😂)はプロダクトの画面をTS, Nuxt, Vuexで実装してました.

会社の雰囲気

次に会社の雰囲気について話します.

一番大きく感じた印象としては,社員同士の仲がとても良い,というのがあります.チームにもよるのかもしれませんが,フロントエンドチームはコミュニケーションなどが活発で,上下関係などはあまり感じられず,心理的安全性が高かった印象があります.毎日決まった時間にミーティングがあり,オフラインのコミュニケーションが活発でした.ミーティングをする会議室(?)的なフロアは隣のテーブルとの仕切りがなく,(それがどういうメリットがあるのかはわからないが)とてもオープンでした.(こんな感じ)

なので隣で代表の猪子さんが普通にミーティングしていたりして,面白かったです.猪子さんめっちゃ声でかかったです.また,会議室のテーブルが1つ1つ違って個性的で,人ダメソファみたいなのが天板になっているテーブルや,メモを書けたり,砂で遊べるテーブルがあったりしました.

メモを書けるテーブル

会議室に限らずオフィスの至るところにインタラクティブなアート作品があったりして,遊び心が感じられてよかったです.

オフィスの様子はこちらの記事にまとまっています! saiyo-ac.jp

インターンの環境

開発環境

僕の席はメンターさんの隣の席で,わかんないところがあったら質問し放題な環境でした.(これはメンターによるらしい)

マシンはメモリ16GBの15インチのMBPを支給してもらいました.15インチのMBPは初めて使いましたが,快適すぎて自分のマシンも買い替えたくなりました.

あと,24インチぐらいのモニターを1つ使えました.

生活

ホテルはオフィスから徒歩10分のところにあるビジネスホテルでした.ホテルって毎日掃除されるし,最高ですね.(インターンの感想ではない)

給与は時給1000円でした.

とある日のランチ↓

個人的推しポイント

チームラボの個人的推しポイントを紹介したいと思います.

部活が盛んでインターン生も参加できるものもいくつかありました.僕は,ボードゲーム部とシェーダ部に参加したのですが,どちらもオフィス内の会議室のテーブルで活動していました.バリバリ会議やっている隣でボドゲとかできるのは,チームラボらしいなと思いました笑.

ボドゲをした緑の丘↓

まとめ

最後にインターンで得られた学びなどを共有しようと思います.怠くなってきたので箇条書きで.

  • Webでデバイスのカメラから映像を取得したり, OCRなどの触ったことのない技術に触れることができた.
  • 様々な技術を持った人が周りで多様なことをやっているので,刺激が多い,モチベーションになる.
  • パスポートにめっちゃ詳しくなった
  • 長期で自分の家を離れるときは爪切りは持っていったほうが良い

以上です.ありがとうございました.

「Webサービスを作りたい!」と思ってから実際に作るまで5年かかった

この記事は CAMPHOR- Advent Calendar 2018 10日目の記事です.

初めまして.京大工学部情報学科1回のあたらんです.プログラミングは初心者ですが,初心者なりに感じていることを綴ろうと思います.

最高にクールなWebサービスを作りたい

中学2年生の時,映画「ソーシャルネットワーク」を見ました.マークザッカーバーグハーバード大学在学中にFacebookを作り上げる過程を描いた映画ですが,とても感動したのを覚えています.どこに感動したかというと,Facebookをローンチした瞬間にサーバーのログが大量のアクセスによって流れていくシーン.一人の人間が作り上げたものが大量の人間に影響を与えているのが最高にかっこよくて,「やばい,Webサービス作りたい!」という気持ちになりました.しかし,実際にWebサービスを作るまで(今初めてWebサービスと呼べるものを作っている)にはそれから5年もかかってしまいました.

そこから学んだプログラミングの習得(やそのほかの学習なんでも)に重要だと思っていることを書こうと思います.

順番って大事

初手Railsチュートリアルはだめ

高校生になった僕は,入学祝いに念願のMacBook Proを買ってもらい,夏休みに中高生向けプログラミングキャンプWebサービス開発コースに参加しました.プログラミングキャンプとは言っても5日間しかないし,HTMLとCSSをdotinstallでかじった程度の知識でRailsを理解するのは不可能でした.

その後Railsチュートリアルで勉強しようと試みましたが,Rubyをはじめその他のプログラミング言語を何一つ触ったこともない状態で理解できるはずもありませんでした.Webフレームワークを理解するにはそのフレームワークプログラミング言語をまず習得する必要があります.

というかそもそも,動的なWebサービスを作る為には世の中のWebサイトを閲覧できる仕組み(インターネットの仕組みとかhttpプロトコルとか)を学び,プログラミングとは何かを知り,Webフレームワークの仕様を学ぶ,というプロセスが必要だと僕は思っています.Railsチュートリアルに案の定挫折させられた(RailsチュートリアルはあたかもRubyが分からない人にも理解できるかのように書かれている)僕からプログラミングをするモチベは消え去りました.

Webフレームワークの勉強をする前に,そのフレームワークを記述しているプログラミング言語の基本的な文法は最低限学ぶようにしましょう.

コミュニティって大事

オフラインで人と会うことの重要性

大学入学前よりも,大学に入学してCAMPHOR-に通い始めてからの方が成長のスピードは多分数倍速いです.当時はプログラミングができる人にもほとんど会ったことがなかったので学習方法もよくわからず,本で勉強するなんてナンセンスだと思っていて,全てググってどうにかしようと思っていました.実際ググって出てくる情報はググっただけでどうにかなるていで書かれていますが,ググっただけではどうにもならないこともあるということを実際に人に会って初めてわかりました.

ググったらなんでもわかる時代とはいえ,やはり人に会ってみないとわからないことも多々あります.

ちょっとズレるような気もするけど,こんな研究もあります.

切磋琢磨できる仲間を探す

大学入学以前は周りに「プログラミングやりたい!」って言っている人は多分ほとんどいなかったので,自分がプログラミングをやっていてもその話題を共有できる人がいませんでした.自分のやっていることが共有できる仲間がいない場合,モチベは続きません(少なくとも僕の場合).

僕は高校時代数学にハマっていました.高1の冬休み,塾の友達と数学の問題集の1つの章を1週間で1周できなければ500円払うという賭けみたいなことをしたことがあります.それを3,4週間した時には「数学おもしれー」ってなってたし,美しい解法を誰かが見つけた時にはそのメンツで共有したりしました.

同じように,大学に入学して競プロというものの存在をCAMPHOR-で知り,学科の友達とその話題を共有することでプログラミングにハマっていきました.おそらくアルゴリズムを考えること自体も面白いことではあるのですが,自分で思いついた美しいアルゴリズムを人と共有して盛り上がることでモチベが保たれるんだと思います.一人で黙々とやってモチベを保てている人がいるとすれば,尊敬します.

Webサービスを開発したい人が辿るべき道

結局,「Webサービスを作りたい!」と思った人がまずやるべきは,パソコンを買って,同じような意志を持った集団に属し(なるべくオフラインがいい),焦らずに必要なことから習得していくことです.そのような環境を提供してくれるのでCAMPHOR-はいいところです.

今開発しているWebサービス

それはそうと,今どんなWebサービスを開発しているかちょっと紹介します.

RoC京大(Rate our Coursesの略)という,自分の取っている授業にレビューや資料をを投稿して共有できる,京大に排他的なサイトを作っています.授業を選ぶ時に先輩たちのレビューを参考にできたり,同じ授業を取っている人とノートを共有できたり(,過去問をもらえたり)してみんなハッピーになる気がしています.

伝えたかったこと

  1. 物事を学習しようと思ったら,焦らず必要なことから順番に学習する.

  2. 学習のモチベを維持する為に同じ目的を持った集団に属す.

  3. それにハマる.

以上です.

なんか精神論みたいな話が多くなってしまいましたが,最後まで読んでいただいてありがとうございました.来年はバリバリに技術的な話ができるようにレベル上げしていきたいと思います.

Raspberry PiをIRリモコンにする

はじめに

LIRCを使ってRaspberry Piで赤外線の送受信するとこまで。

計画

スマートホーム化①

Google HomeRaspberry Piで家電を操作する f:id:satoarata:20180522175108p:plain

目次

用意するもの

必要ならば

ハードを整える

ハード面はこのサイトを参考にしました。(回路は全く同じ) make.bcde.jp

実際に使った電子部品など :

lircで赤外線受送信部分を作る

lircとは

LIRC is a package that allows you to decode and send infra-red signals of many (but not all) commonly used remote controls. (http://www.lirc.org/)

要はRaspberry Piを赤外線リモコンにするやつってこと。たぶん。

Raspberry Piにインストール

$ sudo apt install lirc

バージョンの確認

$ lircd -v lircd 0.9.4c

lircの設定を変更(/etc/lirc/lirc_options.confを編集する)

$ sudo emacs /etc/lirc/lirc_options.conf

[lircd]のところをこんな感じにする

[lircd] 
nodaemon = False 
driver = default 
device = /dev/lirc0 
output = /var/run/lirc/lircd 
pidfile = /var/run/lirc/lircd.pid 
plugindir = /usr/lib/arm-linux-gnueabihf/lirc/plugins 
permission = 666 
allow-simulate = No 
repeat-max = 600 
#effective-user = 
#listen = [address:]port 
#connect = host[:port] 
#loglevel = 6 
#uinput = ... 
#release = ... 
#logfile = ... 

変えたのは

driver = default 
device = /dev/lirc0 

使うピンの設定 /boot/config.txtを編集

$ sudo emacs /boot/config.txt 

最後にこれを追加(ピンのところは自分で決めたピン)

#RemoteController 
dtoverlay=lirc-rpi 
dtparam=gpio_in_pin=22 
dtparam=gpio_out_pin=23 

再起動

$ sudo reboot 

動作確認

$ sudo mode2 -d /dev/lirc0 

受信モードになるので受信機にテレビのリモコンとか向けて赤外線を浴びせてみる

Using driver default on device /dev/lirc0
Trying device: /dev/lirc0
Using device: /dev/lirc0
Running as regular user pi
space 16777215
pulse 3766
space 1921
pulse 441
space 482
pulse 465
space 1436
pulse 446
space 432
pulse 508
space 1443
pulse 489
space 466
pulse 431
... 

って感じで出てきたらOK

ちなみにlircの起動は $ sudo /etc/init.d/lircd start 終了は $ sudo /etc/init.d/lircd stop リモコンの学習はirrecordでやってる記事も多いがうまくいかなかったので、さっきの受信モードで受信したデータを加工して設定ファイルを記述した。

このサイトを参考にした。

takuborn.hatenablog.jp

補足:irrecord で作成した定義ファイルではうまくいかないとき

のところを参考にしてファイルを作る。

部屋の照明を登録した。

lircを再起動して ちゃんと登録されたか見てみる

$ irsend list "" "" 
light tv

信号を送ってみる

$ irsend send_once light full

電気がついた!