はてブクライアントを作った

Rails, React/Redux構成で習作として何かWebアプリケーションを作ろうと思い、GW終わりから3日ぐらいでWebアプリケーションを作った。

f:id:tic40:20180510174108p:plain

こちら: https://tic40-emperor.herokuapp.com

*HerokuのFreeプランなので、サーバがsleep中だと表示にかなり時間がかかります

やりたいこと

  • Rails, React/Redux構成でWebアプリケーションを作る
  • できれば無料で

アプリケーション内容

特にアイデアが浮かばなかったので、普段よく使ってるサービスで何か作れないかなと思い、はてなブックマークの閲覧用クライアントを作ることにした。

  • はてなが提供しているAPI*1RSSからエントリー情報を取得する
  • はてなブックマークのホットエントリー一覧表示
  • エントリーの詳細情報(ブクマ数、コメント数、投稿日など)の表示
  • エントリーのコメント表示

技術構成

技術構成は以下

  • インフラ: Heroku(Free Dyno plan)
  • DB: Postge
  • キャッシュサーバ: Redis
  • CI/CD: CircleCI
  • 開発環境: Docker
  • Back-end FW: Rails v5.2.0, Node.js v9.5.0
  • Front-end FW: React v16 / Redux
  • CSS FW: Bulma

開発環境構築

Dockerで構築した

https://github.com/tic40/emperor/blob/master/Dockerfile https://github.com/tic40/emperor/blob/master/docker-compose.yml

DB設計

ログインもユーザ管理もしないので、ぱぱっと書いておわり

f:id:tic40:20180510180457j:plain

  • feeds: rssフィード情報を保持する
  • entries: エントリー情報を保持する
  • comments: エントリーに紐づくコメントを保持する

API設計

ReactからAPI経由でデータを取得する必要があるため、APIを設計する。

基本的にREST準拠で、レスポンスはjsonで返却する。

  • GET /api/v1/entries
    • エントリー情報全取得
  • GET /api/v1/entries/:feed_id
    • エントリー情報をfeed_id指定で取得

クローリング設計

はてブRSS*2から最新のホットエントリ一覧を取ってくる。 例えば総合カテゴリなら以下のURIから取得できる。

RSSのフィードはこちらから定期的に取りに行く必要があるので、スケジューラーでクローリングタスクを回すことにした。 Herokuアドオンのスケジューラー(無料)を使い、1時間おきに以下のクローリングタスクを走らせている。

https://github.com/tic40/emperor/blob/master/lib/tasks/task_crawl.rake

エントリー詳細情報の取得

RSSからホッテントリ一覧は取得できるが、エントリーに対するコメントなどの詳細情報は取得できない。 はてなが提供している はてなブックマークエントリー情報取得API*3 から取得することにした。

デプロイ

GitHubのmasterブランチ更新時に自動デプロイが走るようにCircleCIのデプロイレシピを記述した。

https://github.com/tic40/emperor/blob/master/.circleci/config.yml

実装

  • RailsAPIモード、かつv5.1から追加されたwebpackerオプションを指定して作成した
Rails new . --webpack=react --api
  • APIのレスポンスはHerokuのRedisアドオン(無料)を使い、キャッシュすることで高速した
  • フロントエンドの構成はReduxを使うため、以下のような構造にした。
# directories
app/javascript/packs/
   |-actions
   |-components
   |-containers
   |-reducers
   |-utils

感想とか

  • はてぶのAPIは user-agent ヘッダーをつけてリクエストする必要がある
  • Heroku無料プランだとDBレコードが10000までという制限がある。エントリーに対するコメントもDBにインサートしているため、あっという間に10000行を越えてしまった。特にデータを溜める意味はなかったので、DBにデータをためないようにRSS更新の際にレコード削除して直近のRSSに含まれているエントリー情報だけDBに保持することにした。
  • 1時間に一度しかクローリングしてないので、リアルタイム性は全然ない。
  • Herokuは楽
  • やっぱり個人で開発するならReactよりVueの方がいいかな。

GitHub

ソースはこちら

github.com

CircleCI 2.0からHerokuにRailsアプリを自動デプロイする

Herokuのアカウント作成

Heroku

適当なRailsアプリケーションをGitHubに作成

GitHubに適当なリポジトリを作成してclone

$ git clone git@github.com:{account}/{repository}.git

railsアプリケーションを作成する

$ cd {repository}
$ rails new .
$ vi app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def hello
    render html: 'hello, world'
  end
end
$ vi config/routes.rb
Rails.application.routes.draw do
   root 'application#hello'
end

Heroku用セットアップ

Gemfileに以下を追記

group :development, :test do
+  gem 'rspec-core'
+  gem 'rspec_junit_formatter'
+  gem 'sqlite3'
  gem 'byebug',  '9.0.6', platform: :mri
end

+ group :production do
+  gem 'pg'
+ end

localhost:3000 でrailsアプリケーションがちゃんと動いているか確認。

$ bundle install
$ rails s

Heroku CLIのインストール

ここから、それぞれの環境に合わせてインストール

Heroku CLI | Heroku Dev Center

Heroku CLIがインストール済みかどうか確認する。

$ heroku -v
heroku/7.0.22 darwin-x64 node-v10.0.0

Heroku コマンドで、ログインし、createコマンドでアプリケーションを作成する

$ heroku login
$ heroku create {heroku上のapp name(指定なしの場合はランダムな名前になる)}

f:id:tic40:20180503205922p:plain

CircleCIアカウントを作成

ここから Continuous Integration and Delivery - CircleCI

GitHubと連携し、Add Project から対象のリポジトリを選択する

f:id:tic40:20180503210137p:plain

CircleCI用のconfigファイルを作成する

Create a folder named .circleci and add a fileconfig.yml (so that the filepath be in .circleci/config.yml).

指示どおりに.circleci/config.yml を作成し、

$ cd {repository dir}
$ mkdir .circleci && vi .circleci/config.yml

画面に表示されているサンプルをコピーペーストする

f:id:tic40:20180503210447p:plain

schema.rbがないとCircleCIのビルドにこけるので、db:migrateを実行しておく

$ rails db:migrate

GitHubへここまでの作業をpushする

$ git add -A
$ git commit -m 'init'
$ git push origin master

上記push後にCircleCI上でビルドが走ればOK。

f:id:tic40:20180504013530p:plain

CircleCIからHerokuへの自動デプロイ設定を行う

以下を.circleci/config.ymlの最下部に追加

      - deploy:
          name: Deploy Master to Heroku
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME.git master
            fi

HEROKU_API_KEY、HEROKU_APP_NAME の環境変数をCircleCIダッシュボードから設定する。 environment variablesを開き、Add variablesを選択し、それぞれ値を設定する。

f:id:tic40:20180504011718p:plain

HEROKU_API_KEYは、Heroku上のaccount settingsから取得できる。(revealを押せば表示される)

f:id:tic40:20180504013214p:plain

ここまでできたら、最後に変更分をpush

$ git add -A
$ git commit -m '適当なコメント'
$ git push origin master

f:id:tic40:20180504013755p:plain

Deploy Master to Heroku タスクが成功していればOK。HerokuのアプリケーションURIにGETリクエストを投げてhello worldが表示されているか確認してみる

$ curl https://tic40-emperor.herokuapp.com/
hello, world

Web基礎知識をおさらいする

基礎中の基礎。いつでも体系的に口頭で説明できるように自戒を込めて。

HTTPってなに?

Hypertext Transfer Protocol.RFC2616で規定された、TCP/IPをベースとしたネットワークプロトコル

TCP/IPってなに?

ネットワークプロトコル。以下のように4層の階層型なっている

データ送信時は上から下の層へデータは流れる。データ受信時は当然逆の流れ。

HTTPSってなに?

ネットワークプロトコル。httpプロトコルとの違いは、TCPとHTTPの間にさらにTLS(Transport Layer Security)プロトコルを利用する点。 TLSを利用することで、セキュアな通信を実現している。

TLSについて

  • TLSでは一般にSSL(Secure Sockets Layer)と呼ばれる
  • 以下のセキュリティ上の機能を提供する
    • クライアントとサーバの認証機能
    • 通信データ暗号化
    • 通信データの改ざん検出
  • TLSTCP上で利用されるため、まずTCP接続を確立する必要がある
  • TCP接続後にTLSハンドシェイクを行い、TLS接続を確立する。
  • TLSハンドシェイクでは、TCP接続の3ウェイハンドシェイクでやり取りする処理に加えてさらにパケットを最低1往復半する必要がある。

ブラウザ上にWebページが表示されるまでの流れは?

クライアント->サーバ

  1. ブラウザにURL(http://example.com など)を入力する
  2. ゾルバを介してDNSサーバに問い合わせを行い、IPアドレスを取得する
  3. HTTPメッセージを作成し、上記で取得したIPアドレスへHTTPリクエストを送信する

サーバ->クライアント

  1. サーバがHTTPリクエストを受信すると、サーバ側ソフトウェアがリクエストを解析し、内容に応じて処理を実行する
  2. HTTPメッセージを作成し、クライアントにHTTPリクエストを送信する
  3. クライアントは受け取ったレスポンスを解析して、その内容に基づいてWebページを表示する

ブラウザがWebページが描画されるまでの流れは?

サーバからHTTPレスポンス受信後〜

  1. Loading: リソース読み込み
  2. Scripting: JavaScriptの実行。ブラウザのJavaScriptエンジンがコンパイルを行う
  3. Rendering: レイアウトツリーを構築する。CSSがどこに適用されるかはここで計算する
  4. Painting: レンダリング結果を描画する。ブラウザのグラフィックエンジンがレンダリングを行う

代表的なWebアプリケーション脆弱性は?

Webアプリに外部からの入力に応じて変化する箇所がある場合、この部分のHTML生成に問題があるとXSS脆弱性が発生する。 例えば、ユーザのクッキー値を送信するスクリプトを設置しておくことで、ユーザのセッションIDが盗まれるなど。

  • SQL Injection

ユーザの入力を発行するSQLに含めるような処理がある場合、適切に対応しないとSQLが改ざんされて、場合によってはDB内の全てのデータ盗まれてしまう。 対策としては、プレースホルダ方式を使い、後からSQLが改ざんされないようにするなど。

攻撃者によって用意された攻撃用Webページにユーザがアクセスすると、攻撃用Webページ内にあらかじめ用意されていた不正なリクエストが攻撃対象サーバに送信する。攻撃対象サーバ上のWebアプリケーションは不正なリクエストを処理し、ユーザが意図していない処理が行われてしまう。

クッキー生成の不備、セッションIDの盗聴、XSSによる漏洩、PHPやブラウザの脆弱性、URLにセッションIDを保持している場合など、セッション管理に不備があると第三者に利用者に対するなりすましを行われてしまう。

マスタリングTCP/IP 入門編 第5版

マスタリングTCP/IP 入門編 第5版

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)

暗号技術入門 第3版

暗号技術入門 第3版

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

カイゼンジャーニーを読んだ

読みました。以下は自分用のまとめ。

状況の見える化

  • タスクマネジメント
  • タスクボード
  • 朝会
  • ふりかえり

ふりかえり

  • KPT
    • Keep: 続けたいこと/やってよかったこと
    • Problem: 問題点/気にかかっていること
    • Try: 次に試したいこと
  • YWT
    • やったこと
    • わかったこと
    • つぎにすること

朝会

  • 昨日やったこと
  • 今日やること
  • 困ってること

1 on 1

  • 上司と部下が1対1で行うコミュニケーション。定期的に行う

タスクマネジメント

  • タスクの情報を洗い出す
    • 誰から依頼されたのか
    • 次は誰に渡すのか
    • 期日はいつか
    • どれくらい作業時間がかかりそうか
    • どうなったらこのタスクは終わるのか
  • 分割統治する
  • 緊急・重要のマトリクスで優先度をつける
  • タスクボードでタスクを見える化する
    • タスクボード運用
      • ステージに分ける(TODO/DOING/DONE/ICEBOX...)

スクラムの基本

  • スプリント
  • スプリントプランニング
  • デイリースクラム
  • スプリントレビュー
  • スプリントレトロスペクティブ

スクラムのチーム構成

  • プロダクトオーナー
  • 開発チーム
  • スクラムマスター

スクラムの作成物

スクラムの理論と精神

  • 透明性
  • 検査
  • 適応

スクラムウォーターフォールの大きな違い

  • スクラムは経験主義。小さいスプリントで振り返りながらカイゼンしていく経験主義が根本思想。Fail Fast(早く失敗する)の精神で、漸進的に開発していく。

インセプションデッキ

  • 以下の10の問いに答えることで、プロジェクトのWhy,Howを明確にする
    1. われわれはなぜここにいるのか
    2. エレベーターピッチ
    3. パッケージデザイン
    4. やらないことリスト
    5. 「ご近所さん」を探せ
    6. 技術的な解決策
    7. 夜も眠れない問題
    8. 期間を見極める
    9. トレードオフスライダー
    10. 何がどれだけ必要か

Working Agreement

  • チームで決めたチームのルール
    • ex. デイリースクラムは10時から15分以内でタスクボードの前で立って行う

成功循環モデル

  • bad cycle
    • 結果の質: 成果があがらない
    • 関係の質: 対立、押し付け、命令
    • 思考の質: 面白くなく受け身
    • 行動の質: 自発的・積極的な行動が起きない
  • good cycle
    • 結果の質: 成果が得られる
    • 関係の質: お互いに尊重し一緒に考える
    • 思考の質: 気づきがあり面白い
    • 行動の質: 自分で考え、自発的に行動する

ドラッカー風エクササイズ

  • チームビルディング手法の一つ。以下の4つの質問に答える。
    1. 自分は何が得意なのか
    2. 自分はどうやって貢献するつもりか
    3. 自分が大切に思う価値は何か
    4. チームメンバーは自分にどんな成果を期待していると思うか
  • 上記をチームで確認した後に、5番目の質問。
    1. その期待は合っているか

ファイブフィンガー

  • 「個人個人が本当はどう思っているか」を5本の指で表明するプラクティス

クネビンフレームワーク

リファインメント

  • プロダクトバックログに含まれるアイテムに対して、詳細の追加、見積り、並び替えをすること

狩野モデル

  • 顧客の求める品質についての分析モデル

むきなおり

  • むきなおりは、進むべき先を捉えて現在を正す作業。
    1. ミッション、ビジョンを点検する
    2. 評価軸を洗い出し、現状を客観的に見定める
    3. 評価軸ベースで「あるべき姿」と「現状の課題」を洗い出す
    4. 「課題解決」のために必要なステップを「バックログ」にする
    5. バックログ」の重要度と、一番効果の高いものを決める
    6. 時間軸を明らかにし、期限も明確に決める

合宿

  • メリット
    • 集中
    • リードタイム短縮
    • 高揚感

星取表(スキルマップ)

  • チームメンバーがどのようなスキルを持っているかを見える化して、俯瞰するための道具

チームビルディング三種の神器

モブプログラミング

  • チーム全員が一箇所に集まって、全員で同じ画面、一つのPCで作業する
  • PCを操作できるドライバーは一人、他はナビゲータとなる
  • ナビゲータはドライバーに指示する
  • 全員が交代でドライバーをする

バリューストリームマッピング

  • プロダクトの価値が顧客の手に渡すまでの仕事の流れを見える化するためのプラクティス

ECRS

  • 業務改善の方法論。Eliminate/Combine/Rearrange/Simplify の頭文字を取ったもの

ポストモーテム

  • プロジェクトを振り返って行う「事後検証」

タックマンモデル

  • 組織づくりにおける発展段階モデル。4段階で構成される。Forming/Storming/Norming/Performing

モダンアジャイル

  • 4つの基本原則で構成されいる概念

プランニングポーカー

  • 見積もり技法の一つ。早期にプロジェクトに導入可能なシンプルな見積もりプラクティス

パーキンソンの法則

  • 仕事の量は与えられた時間を満たすまで膨張する、という法則

CCPM(Critical Chain Project Managememt)

  • 各タスクに個別のバッファを持たずに抑えた見積もりをして全体としてのバッファを持ってプロジェクト管理をする方法

スクラム・オブ・スクラム

コンウェイの法則

デイリーカクテルパーティー

  • 「リーン開発の現場」で著者ヘンリック氏が紹介している

デザイン制作プロセス

  • おおよそ以下の流れで制作は進む
    1. サイトの全体像
    2. スケッチ
    3. ペーパープロトタイピング
    4. ワイヤーフレーム
    5. ビジュアルデザイン
    6. コーディング

ユーザーストーリー

  • 3段階構成
    • Who
    • How
    • Why
  • INVEST
    • Independent
    • Negotiable
    • Valuable
    • Estimable
    • Small
    • Testable

ギャレットの5段階

  • Surface: 視覚的デザイン
  • Skelton: インフォメーション/インターフェースデザイン、
  • Structure: インフォメーションアーキテクチャ
  • Scope: コンテンツ要求/機能要件
  • Strategy: ユーザーニーズ/サイトの目的

ジョブ理論

  • 顧客はやり遂げたい何かがあり、そのためにプロダクトやサービスを「雇用」していると考える

仮設キャンバス

  • 顧客の目的、課題解決達成のためのソリューションを得るためのフレームワーク。本書の付録参照。

ユーザーストーリーマッピング

  • 時間の流れに沿ってユーザーの行動を洗い出し、左から右にその変遷を可視化していくワーク

MVP(Minimum Viable Prodcut)

  • 「ユーザーにとって価値があり、かつ最小限の機能性を持った製品」のこと

ユーザーインタビュー

  • ユーザーの声を聴くための直接的な手段

ラポール空間

  • 相手との間に安心感や信頼関係を構築するためのテクニック

SL理論

  • リーダーシップ条件適応理論。SL(Situational Leadership)

ハンガーフライト

  • 組織の中に新しい場作りを行うための活動。勉強会など

感想

本書は、主人公の失敗から成功までを追体験できる構成になっている。

単なる技術本と違い、ストーリーがあり単純に読み物としても面白い。読んでみて、ああ、こういう現場あるよなぁ、という感じだった。

色々なテクニックはあるんだけど、やっぱり最後は現場の人のモチベーションだと思う。

大概、実際の現場は問題だらけでカイゼンする前にうんざりすることも多い。

一人でもカイゼンサイクルを回して、周囲を巻き込んでいくだけのモチベーションを維持するためには、 その開発/プロダクトに対して、そもそもカイゼン努力するだけの報酬や価値を自分の中で見出してないと厳しいなと思う。

本書に示されているように、まずは小さく始めて負担にならない範囲で継続していくのがいいんだろうな。

GitHub個人/組織アカウントのリポジトリを一括cloneする

準備

curl、jqが必要なので未インストールならインストールをする

$ brew install jq curl

実行方法

リポジトリのクローンを保存するディレクトリへ移動し、以下のコマンドを叩く。

  • 個人アカウントの場合
$ curl https://api.github.com/users/{PERSONAL ACCOUNT}/repos | jq .[].ssh_url | xargs -n 1 git clone
  • 組織アカウントの場合
$ curl https://api.github.com/orgs/{ORGANIZATION ACCOUNT}/repos  | jq .[].ssh_url | xargs -n 1 git clone

解説

上記ワンライナーの解説

  • curl

cURL*1はURLシンタックスを用いてファイルを送信または受信するコマンドラインツール。 今回はGitHub API にリクエストを投げるために利用する。

  • https://api.github.com/users/{PERSONAL ACCOUNT}/repos

GitHubが提供するAPIエンドポイント*2。 GET methodなのでパスの{PERSONAL ACCOUNT} を個人アカウント名に変えてブラウザで叩けばjsonが返ってくる。

例: https://api.github.com/users/tic40/repos

  • jq .[].ssh_url

jq*3コマンドラインjsonプロセッサーAPIレスポンスのjson配列の中から "ssh_url" の値を取り出す。

  • xargs -n 1 git clone

xargs*4Unixコマンドの一つ。 xargs -n 1 で1つの引数を受け取る。受け取った引数はその後に続く git clone の末尾に追加される。

感想

git clone ssh_url/*.git でいけるのかな〜とか思ったら、まあそんな簡単にはいかず。意外と面倒だった。

あと、privateリポジトリも含める場合はGitHubAPI token取得する必要があるのでご注意。

CentOS 7 + PHP7 + mysql 5.7 環境をdocker化する

構成

|- docker-compose.yml
|- Dockerfile

docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - .:/repo
    depends_on:
      - db
    tty: true
    privileged: true

  db:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - 3306:3306
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root

Dockerfile

FROM centos:7

# update yum
RUN yum -y update
RUN yum -y install yum-utils
RUN yum clean all

RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install wget git vim zsh curl

# install remi repo
RUN wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN rpm -Uvh remi-release-7*.rpm
RUN yum-config-manager --enable remi-php70

# install php7
RUN \
  yum -y install \
    php php-common \
    php-mbstring \
    php-mcrypt \
    php-devel \
    php-xml \
    php-mysqlnd \
    php-pdo \
    php-opcache --nogpgcheck \
    php-bcmath

# application directory
RUN mkdir /app
WORKDIR /app

# install composer
RUN curl -sS https://getcomposer.org/installer | php && \
  mv composer.phar /usr/local/bin/composer

# timezone setting
RUN cp /etc/localtime /etc/localtime.org
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

EXPOSE 8080

CMD ["/sbin/init"]

github.com

js勉強会用資料

ちょっとした勉強会用に書いたやつ

太古のコード

See the Pen jzNaoa by tic40 (@ccpzjoh) on CodePen.

特徴

  • DOMの状態管理がない
  • DOMを手作業で直接更新
  • DOMの状態を毎回把握しないといけない

データバインディング

See the Pen dmbJPy by tic40 (@ccpzjoh) on CodePen.

特徴

  • モデル(js object)の更新に伴って、ビュー(DOM)に変更が反映される
  • 手作業でDOMを更新する必要がない

データバインディング + コンポーネントベース

See the Pen yKBpwr by tic40 (@ccpzjoh) on CodePen.

特徴

  • DOMはほぼjs側で生成する
  • コンポーネント化することで、コードの再利用性が高まる
  • コンポーネントごとに単一の責任を負わせることで副作用が減る
  • テストが容易