Hatena::ブログ(Diary)

Memo

2014-04-04

[] 最近の日報の作り方

4 月に常駐が終わって自社に戻ったのを機に日報という物の書き方を以下の様に変えた。


1. memolist.vim でメールで送る件名で新規に作成

2. sonictemplate-vim定型文と Markdownテンプレートを挿入

3. 何か作業を行ったら Markdown で記述

4. 一日の終わりに ggvG"*y で日報の文章をクリップボードに送信

5. ランチャーでメーラを起動し、クリップボードに入った日報をペースト

6. メーラのテンプレート機能を使って送信先を設定

7. 読み返して問題なければ送信


最初 reStructuredText にするか Markdown にするかで迷ったが、QuickRun を使ってブラウザプレビューするのに楽なのが Markdown なのと、今はやってないけど Jekyll と連動してアーカイブを静的配信するには Markdown の方が楽そうだったため Markdown にした。

# Sphinx や Tinkerer にすれば別に reStructuredText でもいいか

# Blockdiag を使いたくなったら考えよう


あとは Vim からメールを送信できる(Gmail は禁止なのでダメ)、もしくは Vim から Thunderbird へすぐにエクスポートできるようになればもっと楽が出来るはず…。


日報は社内ブログという Increments は和製 GitHub の夢を見るか? - @kyanny's blog エントリに勇気づけられたのでこのスタイルを少し続けてみよう。

2014-03-16

[] Gokyoto に行って来た

Golang に興味あるけど、他に優先したい事があるから環境構築を終わって、Hello World を出して終わってたのを何とかせんといかんなーと思ってたら初心者向けハンズオンがあって、しかも講師が @Jxck_ さんという事で行って来た。

f:id:heavenshell:20140315170254j:image

ハンズオンの資料は Go Kyoto(Go勉強会 そうだ京都、行こう) のハンズオン資料 (http://www.zusaar.com/event/4367004) にあるのをやった。

これがちょうど良い難易度で、Golang基本的な説明と慣習などを解説されながら一緒に手を動かす感じ。


途中時間が余りそうとの事だったので急遽スライスの説明をされて、それまでスクリプト言語みたいな感じだった所から急に C っぽさを感じるようなのが出て来て面白かった。


個人的に Golang で魅力を感じてるのは、クロスプラットフォームでも動くという事と、バイナリだけを配れば動くという事で、これは JVM な言語を触る上での魅力と同じ。

もっとも JVM というか Java には過去の膨大な資産*1があるのも魅力で、Golang は今後増えて行くのだろうけど*2

あとスクリプト言語っぽく Vim で開発できるのも嬉しい。


とりあえず Golang で作りたいものは一つあるので、今のが落ち着いたら手をつけてみよう。


懇親会では何故か Erlang の話し(パターンマッチングずるい)や immutable infrastructure の話しとか @Jxck_ さんが何故 Golang を選んだとか話しが出てた。

*1:個人で作ってるのプロダクトのエージェントは Java で書いてる理由がまさしくそれ

*2Golang で同じようなフレームワークがあれば乗り換える

2014-03-10

[] API のオーケストレーション層

Rebuild: 35: You Don’t Need API Version 2 (Kenn Ejima) で話題になった API のオーケストレーション層(ラッパー層)を設けるという方法について、作っていたシステムでそういう事をしていた(因にこの作りにして 2 年目くらい)。

# ただし API のバージョニングという観点で作った訳ではない

f:id:heavenshell:20140310141414p:image

システム感じはこんな感じ。


自分の担当は 上図の Backbone.js と Python まで。

ここまでをフロントエンドとしている。

バックエンドの API は他の人が作っていて、複数のシステムが動いている。

# 一部自分が作ってるのもあるけど

# バックエンドの URL はそれぞれ異なる(つまり物理的*1サーバは別)


フロントエンドの Python サーバーはバックエンドを基本的には JSON-RPC*2 で呼んで結果を受け取って、クライアントに渡す。

またフロントエンドが RPC だけでバックエンドを呼ぶだけではなく、バックエンド側の情報をリアルタイムにクライアントに情報を表示したいたという要求があった。

バックエンド側に WebHook っぽいものを用意して フロントエンド API サーバURL を登録し、バックエンド側で処理が終わったら POST で呼び出してクライアントに返すなどをやっている。

メリット

  • クライアントがバックエンドのサーバと直接やりとりするのではなく、一層挟む事によって自由度が広がった
  • クライアント側で処理する必要がないものはサーバ側に持ってくる事が出来た
  • バックエンド側がも開発中の時はとりあえず Python でダミーのデータを返すようにした
    • バックエンド側が対応完了になったらダミーをやめる

デメリット

  • 複雑になった(複数人でやる場合は担当が決まるので責務がはっきりする)
  • バックエンドに API が増えたら、クライアント側、ラッパー側両方に対応を入れないといけない
  • 一層挟むので速度が気になる
    • 現状クライアント(Backbone.js)がリクエストを発行して、データを取得するのにだいたい 200msec くらいだけど、利用者数が増えるとどうなるか分からない

システムがモノシリックな作りな場合はあんまりメリットが見えないと思うけど、SOA 的な作りをする際には良いと思う。

あ、因に本題の URLAPI のバージョン情報を加えるかどうかは、バージョン番号を付与してる。

加えた理由が元々バックエンドが SOAP でしかやりとりできなかったのが、JSON-RPC で出来るようになった時に元のを壊したくなかったからやった。

やったのはいいけど、いつまで昔のバージョンのを残しておくかという元々の問題提起はまさに直面した。

結局今も残ったままだし、バックエンド側が完全に廃止しないと消せないかな。

ただしバックエンドと切り離してるからフロントエンド側で廃止するなどの判断は自分になるので、そういう意味では楽かな。


追記:

rebuild.fm 57:18くらいで「どういう API になるのかな?」とあったけど、内はまさにクエリインターフェイスみたいな感じになってる。

バックエンドで検索条件を受け付ける口があるので、そこに対して JSON-RPC でパラメータとしてクエリを定義して送信する形。

*1:仮想マシンだけどw

*2:元は SOAP だったのでブラウザから直接呼び出せなかったのが導入の一番の要因

2014-03-07

[][] Mosquitto を試してみる

ほぼ @ さんが書かれた MQTT コトハジメmqtt - Mac OS X で Mosquitto をビルドする - Qiita の通り。

$ curl -O http://mosquitto.org/files/source/mosquitto-1.2.3.tar.gz
$ tar xvfz mosquitto-1.2.3.tar.gz
$ cmake
$ make all

インストールはせず、バイナリを起動だけしてみる。

$ cd src
$ ./mosquitto
1394187979: mosquitto version 1.2.3 (build date 2014-03-07 15:41:07+0900) starting
1394187979: Using default config.
1394187979: Opening ipv4 listen socket on port 1883.
1394187979: Opening ipv6 listen socket on port 1883.

pub.py と sub.py

@ さんが書いたのをコピー。

あ、Python3 でもちゃんと動いた。

$ pip install paho-mqtt

sub.py

# -*- coding: utf-8 -*-
import paho.mqtt.client as paho

def on_connect(mqttc, obj, rc):
    #mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))
    

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))
    

def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))
    

def on_subscribe(mqttc, obj, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))
    

def on_log(mqttc, obj, level, string):
    print(string)
    
    
if __name__ == '__main__':
    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_subscribe = on_subscribe
    
    mqttc.connect("localhost", 1883, 60)
    mqttc.subscribe("my/topic/string", 0)
    mqttc.loop_forever()

pub.py

import paho.mqtt.client as paho

def on_connect(mqttc, obj, rc):
    #mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))


def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))


def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))


def on_log(mqttc, obj, level, string):
    print(string)


if __name__ == '__main__':
    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_publish = on_publish
    mqttc.connect("localhost", 1883, 60)
    mqttc.publish("my/topic/string", "hello world", 1)

実行する。

$ python sub.py
rc: 0
Subscribed: 1 (0,)

sub.py をブローカーに接続したら、以下の様に出た。

1394188158: New connection from ::1 on port 1883.
1394188158: New client connected from ::1 as paho/8C989768D40DE7F7D2 (c1, k60).

Publisher を起動すると Subscriber に以下のように出た。

my/topic/string 0 b'hello world'

Publisher から Subscriber に通信できた。

トピックを my/topic/foo にして送信してみたら、Subscriber には送信されない。


気になる点

Publisher がブローカーに送信した際に以下のメッセージが出る。

1394188592: New client connected from ::1 as paho/EDA65D0D6E0896539C (c1, k60).
1394188592: Socket read error on client paho/EDA65D0D6E0896539C, disconnecting.

なんだろこれ。

2014-02-19

[] テストをどこまで書くか

Flask を使ってアプリケーションを開発している。

テストを書いていてどこまで書くかに悩んでる。


例えばユーザー登録の画面があって、Form ライブラリを使っている。

Form にはバリデーションのルールの一つに正規表現を使ったルールを書いた。

その正規表現が正しく動作しているかテストコードを書く。


次にフォーム登録時に view のテストを書いて、バリデーションが失敗したらエラーをテンプレートに渡しているかテストを書く。

で、ここでさっきのバリデーションと同じパラメータをリクエストとして送信して失敗するか確認するテストを書く。


二回同じテストを書く必要あるのかなぁ…とどこまで書くのかというのに悩んでる。

不安ならテストを書くというのが基本だから書くけど、皆どうしているのだろうか。

2014-02-17

[] Flask-Featureflags で呼び出しを制限する

Flask-Featureflags というものを見つけた。

trustrachel/Flask-FeatureFlags ? GitHub

何をするものかというと、Flask でこの機能はまだ一部のユーザーにベータテストとして見せたいとか、会員のみこの機能を許すみたいな感じで機能制限をできるもの。


app.py

from flask import Flask
from features import feature, test_feature
from configs import Settings
from views import app as view


def create_app():
    app = Flask(__name__)

    app.config.from_object(Settings())
    
    app.register_blueprint(view)
    feature.init_app(app)

    #feature.add_handler(test_feature)

    return app


if __name__ == '__main__':
    app = create_app()
    app.debug = True

    app.run()

configs.py

class Settings(object):
    FEATURE_FLAGS = {
        'unfinished_feature' : False,
    }

features.py

from flask.ext.featureflags import FeatureFlag
from flask.ext.featureflags import StopCheckingFeatureFlags
from models import User

feature = FeatureFlag()


def test_feature(feature):
    if User().active is True:
        return True

    raise StopCheckingFeatureFlags

models.py

class User(object):
    _active = False

    @property
    def active(self):
        return self._active
from flask import Blueprint, render_template, request, current_app
from flask.ext.featureflags import is_active_feature

app = Blueprint('index', __name__)


@app.route('/')
def index():
    return 'index'


@app.route('/active')
@is_active_feature('unfinished_feature')
def active():
    return 'active'

ソースコードはこんな感じ。

まずは設定ファイルに

FEATURE_FLAGS = {
    'unfinished_feature' : False,
}

と書いた場合、view の @is_active_feature('unfinished_feature') がついている uri にアクセスした場合に 404 not found が応答する。

@is_active_feature('unfinished_feature', '/') と第二引数uri を書いてやると、そこにリダイレクトされる。


設定ファイルだけだと、例えばモデルからそのユーザーがアクティブかどうかを見る事が出来ないので、features.py の test_feature を handler に追加する。

feature.init_app(app)
feature.add_handler(test_feature)

で、test_feature は models.py の active を見ているので、そこが True の場合、True を応答するようにした。

これで /active にアクセスした場合、ちゃんと active という文字列が応答される。


上記サンプルはデコレータメソッド単位の制御を行ったが、if 文で制御する事も出来る。

また Jinja2 のテンプレート上でも制御できる。

テンプレート上で制御出来るという事は、会員と非会員とで表示するコンテンツを制御のような物が出来る。

機能の表示/非表示だけだけど、CookPad の Chanko みたいになったら素敵なのになぁ。

現状 Flask-Featureflags の is_active だと True, False しか返らない。

やるとしたら Jinja2 のマクロを使って、テンプレートと分離する形かなぁ。

2014-02-02

[] Injector の仕様変更

Flask-Injector を使っていて以下の様な警告が出た。

Injector Modules (ie. configure) should not be injected. This can result in non-deterministic initialization. Support will be removed in the next release of Injector.

configure を直接注入するのはダメというのはどういう事かというと、注入の設定をしている箇所で以下の様にしている。

injector = init_app(app=app, modules=[configure])
post_init_app(app, injector)


@inject(app=Flask)
def configure(binder, app):
    pass

この modules=[configure] が次のバージョンからサポートされなくなるよう。

以下のようにする。

injector = init_app(app=app, modules=[MyModule])
post_init_app(app, injector)


@inject(app=Flask)
class MyModule(Module):
    def configure(self, binder):
        pass