Keep It MECE

あったこと、気になったこと、知っておきたいこと

PythonでBASIC認証

import base64


def create_basic_auth_header(id, secret):
    digest = base64.b64encode('{}.{}'.format(id, secret).encode()).decode()
    return {'Authorization': 'Basic {}'.format(digest)}

動作確認

>>> create_basic_auth_header("aaa", "bb")
{'Authorization': 'Basic YWFhLmJi'}
>>> create_basic_auth_header("aaa", "bbb")
{'Authorization': 'Basic YWFhLmJiYg=='}

Qiitaのページからタイトルを取得する

urlsというテキストファイルを作成します。

urls

http://qiita.com/leo1109/items/045c54d9a3a4f8979cc2

run.sh

#!/bin/bash
for url in `cat urls`;
do
    title=`curl ${url} 2>&1 | grep '<h1' | perl -e '$x=<STDIN>;chomp $x;if ($x =~ /(\<h1 class=\"ArticleMainHeader__title\".*?\>)(.*?)\</){print $2;}'`
    echo $title, $url
done

run.shを実行します。 以下の様に、記事のタイトル、URLが出力されます。

Pythonで書きたい! (1) コードのフォーマットチェック, http://qiita.com/leo1109/items/045c54d9a3a4f8979cc2

Firebase Realtime Database入門 (1)

※今日は技術のお話です。

Firebase Realtime Database

Googleのプロダクトの一つです。 ざっくり言えばクエリ"も"できるKVSです。

firebase.google.com


特徴としては、以下があります。

それぞれの特徴を簡単に紹介します。

スマートフォンアプリ向け

iOS, Android, Unityなどに組み込めるSDKがあります。その為、クライアントサイドから直接データを参照、更新、あるいは購読することができるため、サーバサイドの実装が最小限で済みます。

もちろん、web(ブラウザ)経由でも利用ができます。

ネイティブなSDK

SDKを利用することで、例えば以下のような手順が簡単にできます。

  • 認証
  • データの参照、更新
  • データの購読
  • プッシュ通知の設定

スマートフォンアプリでは、プッシュ通知をFCM(Firebase Cloud Messaging)経由で利用できます。これはiOS, Android両方に対応しているので、APNS, GCM個別の設定が不要になります。

REST API

データ構造はJSONを模した作りになっていて、特定のJSONのキーを指定すると、データを取得できる、という形式になっています。

これらは、SDKを経由して取得することもできますし、簡単な利用だけであれば、REST APIで操作することも可能です。

また、Streaming APIといったものも用意されており、コネクションを張って購読する、といった使い方もできるようです。

KVSのような、RDBのようなストレージ

データ構造は、以下のようになっています。

project = {
  "products": {
    "lemon": {
      "color": "yellow",
      "price": 200,
      "note": "SOUR!!",
    },
    "apple": {
      "color": "red",
      "price": 150,
    }
  }
}

上記の様な場合、例えば以下のようにしてデータを取得できます。

db = RealtimeDatabase()

db.target(["product", "lemon", "price"]).get()  # 200
db.target(["product"]).query("price", ">", 190).get()  # {"lemon": {"price"..}}

とても直感的ですね!

安い

Realtime Databaseの課金体系は、保持データ量と、ダウンロードサイズに依存しています。
firebase.google.com

そのため、以下の様なことがいえます。

  • データをいくら登録、更新してもお金はかからない
  • 揮発性のデータであれば、保持データ量は少なくてすむ

無料枠もあって、1Gbyte, 10GB/monthであれば、無料です。
同時接続数は100という制限があるので、小規模なチャットアプリ向けになると思います。
ただし、同時接続を想定しないストレージのような使い方であれば、同時接続は気にする必要がありません。
データ保持の価格は高めなので、永続データはGoogle Cloud Datastoreに逃がすと良いです。

以下は、Google Cloud Datastoreの価格です。
料金と割り当て  |  Cloud Datastore のドキュメント  |  Google Cloud Platform
こちらも無料枠があります。
課金体系は、ストレージの書き込み、読み込み、削除、保持データ量です。
操作するたびにお金がかかるため、データベースの操作が多い場合は、注意が必要です。
ただし、保持データ量はRealtime Databaseに比べて安いので、永続データ向きです。

Google Cloud Platformと連携できる

何よりこれが一番のメリットでしょう。
同じGoogleのプロダクトなので、両者を同時に利用することができます。
Google Cloud Datastoreには1秒に1回の書き込み制限があるため、それ以上の更新がある場合は、Realtime Databaseの利用が想定できます。
また、特定のデータが更新された場合に通知を受けることもできます。

追記

1秒に1回以上更新できるストレージとしてGoogle Cloud Spannerが発表されています。
こちらもパフォーマンスが気になるところです。
Cloud Spanner | 大規模な自動シャーディングとトランザクションの整合性  |  Google Cloud Platform

スピーカーを買いました

初めてAVスピーカーという物を買いました。

kakaku.com

そんなに高いものではないんですが、本体だけで40,000円以上するものに、スピーカーが2つ+ウーファーがついて46,000円ということで、かなり高コスパだと思い、こういった業界に詳しい友人と一緒に電気屋に行った上で、数時間くらい悩んだ上で、購入して持って帰ってきました。重くて持って帰るのが大変でした。運んでくれた友人、本当にありがとう。

今まで持っていたスピーカーは以下のものだったので、かなり良くなることを期待していました。

Amazon.co.jp: 【日本正規代理店品】Jawbone BIG JAMBOX ワイヤレス Bluetooth スマートスピーカー ホワイトウェーブ iPhone5対応 ALP-BJAM-WW: 家電・カメラ

結果としては、予想以上にすごかった。

 

今まで音楽をあまり意識して聴き比べたことはなかったのですが、低音の音量はともかく、音の広がりが全然違いました。

もちろん、10万くらいするものに比べたら全然ですし、いわゆる2.1chなので、これだけで分かった気になるのは尚早なのですが、値段を考えたら本当にお買い得だと思います。

欠点としては場所を取ることなので、ある程度の広さは必要な気がします。

この値段で、このクオリティのものが買える時代は本当にすごいな、と思いながら、感謝して音楽を聞いているのでした。

お勧めは、AmazonのFireStickと合わせて、映画を楽しむやり方です!

Python: requests Timeouts(タイムアウト)について調べた

Pythonのrequests.
人間が読みやすく、のポリシーが書いてあるあれです。

今回はその中のTimeoutについて調べてみました。

Timeoutを設定する

requestsのドキュメントには、普通のプロダクションコードならTimeoutを必ず書く必要があって、ない場合はハングアップするよ、と書いてあります。

You can tell Requests to stop waiting for a response after a given number of seconds with the timeout parameter. Nearly all production code should use this parameter in nearly all requests. Failure to do so can cause your program to hang indefinitely:

例えば、以下のようなコードで実現できます。

# hung upするかもしれないコード
requests.get('http://example.com')
# hung upしないコード
requests.get('http://example.com', timeout=10)

timeoutはfloatで指定してもいいようです(5.5など)
ちなみに、デフォルト値はNone(タイムアウトなし)です。
明示的にNoneを指定すると、デフォルト値としてふるまいます。

Timeoutエラーの種類

タイムアウトを設定した場合、例外が送出される場合があります。
内部的にリトライしている場合は、リトライ回数が超えた、という文言も一緒に出力されるかもしれません。

ConnectTimeout

下記の例は、リトライを設定した上で、タイムアウトを0.001秒に設定した例です。
送出される例外はConnectTimeoutです。

# code
requests.get("<HOST>", timeout=0.001)

# raises
requests.exceptions.ConnectTimeout:
 HTTPSConnectionPool(host='<HOST>', port=<PORT>):
Max retries exceeded with url: <URL>
 (Caused by
 ConnectTimeoutError(<requests.packages.urllib3.connection.VerifiedHTTPSConnection>,
'Connection to <HOST> timed out. (connect timeout=0.001)'))
ValueError

Timeoutは0未満の値を受け付けないようです。当たり前ですが。

# code
requests.get("<HOST>", timeout=-1)

# raises
ValueError: Attempted to set connect timeout to -1,
 but the timeout cannot be set to a value less than 0.

エラーには、less than 0はセットできないとあります。
この場合はValueErrorが送出されます。

ConnectionError

ではタイムアウトに0を設定した場合はどうなるのでしょうか。
0未満がだめということなら0は設定できるはず。

# code
requests.get('<HOST>', timeout=0)

# raises
requests.exceptions.ConnectionError: 
 HTTPSConnectionPool(host='<HOST>', port='<PORT'):
 Max retries exceeded with url: <URL>
 (Caused by 
NewConnectionError('<requests.packages.urllib3.connection.VerifiedHTTPSConnection>:
 Failed to establish a new connection:
  [Errno 36] Operation now in progress',))

今度はConnectionErrorが送出されています。ConnectErrorとConnectionError、とても良く似ています。

スタックトレースの最後まで見ると、0.001秒と設定した時と比べて、以下のような違いがあるのがわかります。

# timeout=0.001
ConnectTimeoutError
Connection to <HOST> timed out.

# timeout=0
NewConnectionError
Failed to establish a new connection:

そんなの当たり前じゃん、という感じなんですが、timeout=0.001の場合は、「繋ぎに行ったけどタイムアウトしたわ、ごめんね」となったのに対し、timeout=0の場合は、「繋ごうとしたらtimeout=0だったからコネクションすら確立できなかったわ、すまんな」ということなんだと思います。

なんでこんなことを調べたのか

タイムアウトする場合のテストを書いていて、

  • timeout=0.001くらいにとしておけばだいたい大丈夫か?
  • requests.Timeoutsのサンプルがそうなっている
  • でも、将来的にちょうはやい回線が出てきたときに、1ms以内でレスポンス返るようになることもあるんじゃ?
  • まあ、多分そんなことはないと思うけど。
  • (もしあった場合に)そしたら0.0000001とかにするんかな?
  • timeoutは負の値は無理だけど0はいけるらしい
  • じゃあ、0にすればいいんじゃね???

という経緯で、0にしてみたら微妙に違うエラーが出た…ということです。

デフォルト値がNoneなのが微妙

関数の引数にtimeoutを渡す場合、デフォルト値を設定したくなるんですが、Noneは意味がある(タイムアウトなし)ため、デフォルト値に悩みます。
デフォルト値を負にして、負の場合は無指定とみなすか、0にして0の場合は無指定とみなすか、とか色々考えているところです。
普通のユースケースなら0で十分な気もします(0の場合はテストができなくなりますが)

最後に

Timeoutを書き忘れると1時間とか止まるケースがあるようなので(実体験)皆様、気をつけてください。

通勤路線評価

東京の通勤路線を勝手に評価する。

混雑率を評価したサイトはそれなりにありますが、ここでは勝手な主観だったり、体験を踏まえた内容が多いはず。

乗ったことがあるところが優先的に、贔屓的に出てくると思われる。

2016/12/10 とりあえず書き始めた。

評価の目安

  • S:全体を通して快適。ただしオフィスの場所次第。
  • A:快適。長距離でもあまり気にならない。
  • B:まずまず。他人にお勧めできるラインのギリギリ。
  • C:座れることはあまりないが、許容できるレベル。人と触れ合うことがある。
  • D:俗に満員電車と呼ばれる。優先席という分類はもはやない。
  • E:女性専用車も満員。電車に乗れないことがある。遅れるのは日常茶飯事
  • F:東京に慣れていない人にはおすすめできない。

Sランク

Aランク

日比谷線 築地ー中目黒方面

築地、銀座あたりでほぼ人がはけるので、まず座れる。

周辺エリアはそもそも高いので、住めるところがあるかどうか…

東西線 日本橋ー中野方面

茅場町が乗り換え駅となっていて、それより先は空いている。

西側に住みたいところだが、反対側はそれなりに混んでいる。

Bランク

中央線 下り

上りが混んでいる分、下りは空いている。中央線沿いの駅は神奈川へのアクセスが悪いので、オフィスが川崎方面、横浜方面の場合はおすすめできない。

Cランク

日比谷線 上り 北千住ー中目黒

北千住始発なので、何本か見送れば座れる。

昔は東横線の菊名まで直通の電車があったが、副都心線の方にシフトしてしまった。北千住から築地までは非常に混む。霞が関までは千代田線の方がはやくつく。

千代田線 上り 北綾瀬代々木上原

北千住乗り換えの場合、日比谷線と千代田線でルートがかぶるため、そこまで混雑しない。北綾瀬なら始発なので座れることも。

Dランク

中央線 上り

乗る場所によって快適さが大きく変わってくるエリア。高尾、八王子からの通勤の場合は比較的快適だと思われる。

立川を過ぎたあたりから人が増え始め、それより新宿よりは基本的に単調増加と見てよさそう。

ピークは7時から7時半くらいだと思われる。

Eランク

田園都市線 上り 急行、準急

東横線 上り 急行

Fランク

小田急線 上り

JR埼京線 上り

責任を持たないということは責任を押し付けるということだ

※この話はフィクションです。

ここに2つのチーム(甲と乙)がある。

 

それぞれのチームに、営業担当と技術担当がいる。

技術担当は営業から言われた仕事をこなし、営業は外からの要望を技術に伝える仕事をしている。

基本的には甲と乙は独立しており、それぞれ営業と技術が会話をして仕事をこなしていいる。チームの関係性としては、やや乙チームの方が強いと考えていい。

あるとき、乙チームが甲チームと連携して仕事をしたい、と言い出した。言い出した人は、甲と乙チームの更に上のチーム(松チームとしよう)のメンバーだ。

乙チームの営業が取ってきた仕事を、甲チームでもノウハウを貯めるために把握しておきたい、ということだった。

そのためには、以下のアプローチがある

  1. 乙チームの営業が、甲チームの営業担当と連携を取る
  2. 乙チームの営業が、甲チームの技術担当と連携を取る
  3. 乙チームの技術が、甲チームの営業担当と連携を取る
  4. 乙チームの技術が、甲チームの技術担当と連携を取る

しかし、甲チームの技術担当は癖が強く、自分の営業担当と喋る以外は無口になってしまう。また、営業同士は非常に仲が悪い。

ということで、3以外の連携方法がない、ということになった。

連携を取る、ということが決まったものの、更に問題が生まれた。
誰がどうやって連携を取るのかが決まらないのだ。

  1. 甲チームの営業は非常に忙しいので、受注した仕事内容をいちいち説明するのが大変。概ね伝えることはできるが、漏れることがある
  2. 乙チームの営業と甲チームの営業の連携は必須なので、そこは乙チームの技術が頑張って欲しい
  3. 甲チームの技術担当は非常に気難しい上に多忙なので、そこから情報が入ることはないと思ってほしい。その情報が知りたい場合は営業担当に聞いてほしい
  4. 甲チームは、基本的に乙チームの仕事には興味がない。乙チームが甲チームに興味をもつのは勝手だが、こちらに迷惑はかけないでほしい
  5. 甲チームと乙チームが連携する、というのは松チームが決めたことなので、逆らえない

今回の連携で、新規案件を受注した場合、乙チームの営業担当→乙チームの技術担当、というルートの他に、乙チームの営業担当→甲チームの技術担当のルートが生まれたわけだが、このルートが必ず信用できるわけではない。よって、乙チームの技術担当は、定期的に甲チームの営業担当に話を聞きに行かなければならない。

彼らはslackやchatworkなどが使えないので、連絡手段はメールか電話だ。非常に効率が悪い。

その上、松チームは連携は素早くしなければダメだ、と強く主張している。(そもそももっと上からオリてきた話だ、とも言う)

そして、甲チームの技術担当は、新規案件が来たかどうかを乙チームに確認しに行かなければならなくなり、甲チームの営業担当とのやり取りも希薄になっていく。甲チームの営業は、案件情報を聞くために甲チームとの技術とやり取りをしに行かなければならない。

 

本来、上からの命令ということで、それに従わなければならないはずが、すでに出来上がっているチームの関係性が邪魔をしている、という状況が起きているわけだ。

新規案件の情報や、進捗を確認するには、乙チームの技術担当に話を聞くのが早い。しかし、甲チームから乙チームの技術担当に話を聞くのは無理だ。乙チームからすると、甲チームのほうから案件があった場合は声をかけてほしいと思うのだが、それもできない。

松チームのメンバーは「乙チームの立場は弱い。まずは自分たちが責任を持って、話を聞きに行くべき。相手から連絡がなくとも、定期的に連絡を取っていくのは義務」ということになってしまうのだ。

そして、お互いのチームが疲弊していく…