hirapi's blog

ちゃんとしたふりをする

Hanami公式入門ガイド日本語訳【1】Introduction

Hanami | Guides
英語のリハビリがでら和訳してみることにした。

はじめに

Hanamiとは?

Hanamiは、多くの小さいライブラリで構成されたRuby MVCフレームワークです。
Hanamiはシンプルで安定したAPI、最小限のDSLを有しています。また、過度な責務を負ったわかりにくいクラスよりも、純粋なRubyオブジェクトを使うことを重んじています。

明確な責務を持ったシンプルなオブジェクトを使うと、一般的にボイラープレートなコード(訳註:定型的なおまじないが繰り返し現れるコード)になります。
Hanamiを使えば、基本的な実装を保守している間、この余計な地道な作業を軽減することができます。

なぜHanami?

ここに、Hanamiを選ばざるを得ない3つの理由を示します:

軽量

Hanamiのコードは比較的短く、(実装に関係無く)全てのwebアプリケーションが必要とするようなことだけに関心を置いています。
Hanamiには様々なモジュールが備わっており、またその他のライブラリも簡単に組み込むことができます。

わかりやすいアーキテクチャ

"Rails way"に逆らっているように感じている人は、Hanamiをきっと評価することでしょう。
Hanamiにおいてコントローラーアクションはクラスから生成されています。そしてそれゆえに独立したテストを行いやすくなっています。
またHanamiでは、ビジネスロジックユースケースオブジェクト(いわゆるinteractor)に書くことが推奨されています。
Viewはテンプレートと分離しているため、内部にロジックを十分に書くことができ、また独立してテストすることができます。

スレッドセーフ

スレッドを使うと、アプリケーションのパフォーマンスを劇的に向上させることができます。
スレッドセーフなコードは簡単に書けるべきであり、Hanamiは(フレームワーク全体においても、その一部においても)スレッドセーフに実行されます。

ガイド

ガイドでは、高次のHanamiコンポーネントと、フルスタックアプリケーションの中でそれらの設定・活用・テストを行う方法を説明します。
ガイドで扱うのはBookshelfという想像上のプロダクトです。Bookshelfは読書体験をシェアし、本を購入することができるオンラインコミュニティです。
初めてのHanamiアプリケーションを構築するために、ガイドを始めましょう。

未経験新卒エンジニアの社内生存戦略@だいたい新卒エンジニア技術交流会(LT)

だいたい新卒エンジニア技術交流会#12でLTしてきました!

dark.connpass.com

資料はこちらです。

www.slideshare.net

初参加でLT申し込むっていう謎テンションしちゃって当日ドタキャン欲とたたかってたんですが,発表中みなさんあたたかいリアクションでうれしかったですw 行ってよかったw
用事があってぜんぜん懇親できなかったんですが,これからもくもく会とかごはんとかこそっと参加させていただきます!

hikariなふりをしていましたが根はyamiだということは追って主張したい。

生存戦略()

実際うちの会社でどういうふうに案件が振られてるかはまったく知らない(別にたずねてない)ことをこの場でことわっておきます。
ただここ4ヶ月くらいこういう気持ちで過ごしてましたっていうお話でした。

ひとつの言語をきわめる(?)前にあれこれ手を出すのはどうなの,という説もあると思います。
でも実務でしか得られない経験は今のところ会社でしか得られなくて,それを取りに行くのは大事なことなのかなあと。

それと,存在する案件はぜんぶ重要で会社の役に立つ仕事だということも理解しています。
だたその中でも自分が特に興味をもっているもの・経験したいことを担当させてもらえるなら,それに越したことはないというのが私の考えです。

そういえば技術以外のところだと,最近「広告の配信アルゴリズムに興味がある」って言い続けていました。
バンディッドアルゴリズムとかロジスティック回帰でCVR予測とかの記事をぺたぺた貼ってぼそぼそ言ってみたり。
それが功を奏したのか次の案件でそのへんに絡ませてもらえるみたいです。
社内政治って意外と何かを左右してると思うんです,そういうのに乗っかるのもひとつの生存戦略

おわり

LT楽しい。

XMLHttpRequestでクロスドメインリクエスト

つまり

XMLHttpRequestでクロスドメインのリクエストを送って、リクエスト先でCookie付けたりリクエスト元に値を返したりするときは、XMLHttpRequest・レスポンスヘッダに↓をつけること。

  • XMLHttpRequest
    withCredentials: true
  • レスポンスヘッダ
    • Access-Control-Allow-Origin: (リクエスト元ドメイン)
    • Access-Control-Allow-Credentials: true

(リクエスト元ドメイン)のところに * を使うと、もうひとつの Access-Control-Allow-Credentials がきかずエラーになり、Cookieが付与できない。
サーバー側のプログラムでリファラを取得して動的に指定してあげると通る。
ただしセキュリティ的にそれでいいのか感はある。

くわしく

やりたいこと

  1. XMLHttpRequestで異なるドメインのサーバーにあるプログラムにリクエスト飛ばす
  2. リクエスト先のプログラムでCookieを付与する
  3. リクエスト元に値を返す

fooドメインのjsからbarドメインPHPにリクエスト飛ばして、PHPCookie書き込んで、PHPからjsに値を返したい。

NG

こんな感じで送るとうまくいかない。

リクエスト元

// client.js
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (this.readyState === 4 && this.status === 200) {
        var id = this.response.id;
        console.log(id);
    }
};

xhr.open('GET', 'https://bar.jp/server.php', true);
xhr.send();

リクエスト先

<?php
// server.php

header('HTTP/1.0 200 OK');

$id = 'hogehoge';

setcookie(
    'id',
    $id,
    time() + 60 * 60 * 24 * 180,
    '/',
    'bar.jp'
);

echo json_encode(array('id' => $id));

Chromeだとこういうエラー

XMLHttpRequest cannot load https://bar.jp/server.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://foo.jp' is therefore not allowed access. The response had HTTP status code 500.

さらにCookieの付与もできていない。Cookie読むのはできるけど書けない。

OK

  1. リクエスト元のjsで、XMLHttpRequestに↓を設定 withCredentials: true
  2. リクエスト先のサーバーで、レスポンスヘッダに↓を追記
    • Access-Control-Allow-Origin: (リクエスト元ドメイン)
    • Access-Control-Allow-Credentials: true
  3. ※ ↑のリクエスト元ドメインワイルドカード以外を指定する
    • 限定されるならそのドメイン
    • なんらかの事情で限定できないなら、リファラを取得するなりで動的に指定する

サーバー側で付けている Access-Control-Allow-Origin: (リクエスト元ドメイン) はクロスドメインリクエストで値を返したりCookieを付けたりするために必要。
どうでもいい値を返すだけなら「どこからでも良いよ」の意で Access-Control-Allow-Origin: *ワイルドカード指定しても良い。

ただし、ここでワイルドカード指定すると、Cookieなど大事な情報を扱うための Access-Control-Allow-Credentials: true がきかなくなる。
リクエスト元が自分の運用する別ドメインなど限定できるなら、ちゃんと Access-Control-Allow-Origin: https://bar.jp と指定する。
大人の事情で限定できず、事実上「どこからでも良いよ」な状況なのであれば、サーバー側でリファラを取得して指定すると通る。

これをjsとPHPで実装するとこうなる↓

// client.js
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (this.readyState === 4 && this.status === 200) {
        var id = this.response.id;
        console.log(id);
    }
};

xhr.open('GET', 'https://bar.jp/server.php', true);
xhr.withCredentials = true;
xhr.send();
<?php
// server.php

header('HTTP/1.0 200 OK');
header('Access-Control-Allow-Credentials: true');

$parsed_url = parse_url($_SERVER['HTTP_REFERER']);
header('Access-Control-Allow-Origin: ' . $parsed_url['scheme'] . '://' . $parsed_url['host']);


$id = 'hogehoge';

setcookie(
    'id',
    $id,
    time() + 60 * 60 * 24 * 180,
    '/',
    'bar.jp'
);

echo json_encode(['id' => $id]);

実際は「サーバー側で事故ったら500」とかの処理もあったけど今回の話にかかわるところはこんな感じ。

おわり

値を返すところ、JSONPなるものをうまくつかうといいのかもしれない。
今回つかわなかったからまた機会があれば。