c-bata web

@c_bata_ のメモ。python多め

PyCon APAC 2017 参加レポート

今年で3回目のPyCon APAC参加になりました。 前回まではgihyo.jpさんの方で連載していたのですが、今回はpyladiesの方々が書いてくれるみたいなので楽しみ。

詳しいレポートはgihyo.jpの方にあがると思うので、LTの話とマレーシア(クアラルンプール)について知ったことをメモ程度にまとめようと思います。

物価は安いし、大体どこに行っても英語も通じるし、治安もそれほど悪くなくていい街でした。

PyCon APAC/Malaysia

トークセッションのプロポーザル (Rejected)

Talk: Develop a Web Application Framework from the Ground Up.

While developing web application in python, most of pythonista uses WSGI Framework like Django, Flask. However, there are not many people who understand the implementation of these frameworks very much. In this talk, I will explain the specification of WSGI and the components of wsgi framework such as Router, Request object, Response object, and so on. The full source code that I will explain is here: https://github.com/c-bata/webframework-in-python/blob/master/src/app.py

トークセッションのプロポーザルを出してました。 内容は昨年のPyCon JPで話した、WSGIフレームワークの作り方。 残念ながらRejectされました。

基礎から学ぶWebアプリケーション・フレームワークの作り方 at PyConJP 2016

採択されたトークのほとんどはデータ系でしたが、PyCon KoreaのKwon-hanさんがいうには、Koreaでも同じ状況らしい。ここはPyCon JPもそうですね。

データ系の盛り上がりに乗っかって、Python x Webも少し盛り上げていけるといいな。

日本からは、関根さん、野中さん、赤池さんの3人のプロポーザルが採択されてました 👏。 赤池さんは初のPyConだったらしい、おつかれさまでした。

Lightning Talk

f:id:nwpct1:20170829211840j:plain

事前にスケジュールを見てLTが見当たらなかったので、無いのかなと思っていたんですが、当日行ってみたら普通に募集していた。カンファレンス2日目の朝、ぶっちゃけ寝坊したんですが、朝食あと回しにして会場に寄ったらLT枠に空きがあったので応募。

2日目のセッションは台湾のTzu-ping Chungさん(Macdown開発者。PyCon JP 2016でもasync/awaitの話をしてました)のトークだけ聞いて、その後はスタバでLTの資料作りしてました。

Tzu-ping Chungさんのトークは、自分にとって特に新しい話は少なかったかなとも思ったのですが、うまくまとまっていて話も面白かった。自分とそれほど歳も変わらないと思うんですが、自分よりもずっとコードを書いているんだろうなと、ふと思ってしまった。負けないように頑張ろう。。。

発表スライドはこちら

今回のカンファレンスでは特に動画撮影がなかったのでYoutubeとかにもあがらない。あとで見返すように撮っておけばよかった。

マレーシア / クアラルンプールについて

今回が初のマレーシアでした。

基本情報

f:id:nwpct1:20170825091014j:plain

  • 公用語に英語が含まれていて、大体どこにいっても英語が通じるので楽だった。
    • 教育を受ける時に、英語とマレーシア語を選ぶ感じらしい。マレーシア語を話せない人もそれなりにいるという話を聞いた。
  • 通貨はMR(マレーシア・リンギット)で、1MR=30円くらい。
    • 空港よりも市街地の方がレートがいいので、次行くときは食事、ホテルまでの移動費、SIM代ぐらいだけ空港でExchangeしておけばよさそう。
  • 物価は1/3くらい。写真は空港で食べたご飯も12MR(=360円)だった。
    • 都市部の企業でも初任給8万円とかだったりするらしい。
    • 酒税が高いらしく、お酒の値段は日本とあまり変わらない。
    • ムスリムの人がお酒飲まないからか、メニューにアルコールがない店とかもわりと多かった
  • インターネットは、7日間のSIMを20MR(=600円)で購入。
    • 4Gが使えて速度も十分に速い。安くてよかった。

天気・気候

  • 1年中、大体30度くらいで少し暑い。
  • 今の時期は雨季らしく、天気予報全部雨マークだったので残念がってたけど、スコールが2-3時間降るだけですぐ晴れた。傘も持っていったけど結局1回も使わず。
    • カンファレンスのランチの時に、1人できてた女性がいたので一緒にご飯食べて話していたんだけど、EAST AREAの方(クアラルンプールはWEST AREA)はこの時期大量の雨が降っているらしい。
    • マレーシアだとEAST AREAの離島(海がめっちゃきれいで人気の観光地)は、すごくおすすめだけどこの時期は雨のせいで近づけないという話を聞いた。
  • 1年中、気温があまり変化しないけど、どうやら旬はあるらしい。ちなみにドリアンの旬は6-8月。

移動手段

f:id:nwpct1:20170825085143j:plain

  • 日本から来た他のメンバーと空港で合流したので、ホテルまではタクシーを使った。
    • 1人あたり30MR(900円)くらいだった気がする
    • ↑の写真にあるような、ミニバンみたいなのに乗った
  • モノレールは、1.5MR(45円)くらいで乗れる。
  • 市街地でも徒歩で移動するのは少し大変。
    • 都市部はいろんな所で工事をしていて、当然のように歩道が途切れたりする
    • 押しボタン式信号は大体反応しないので、車やバイクに注意しながら横断歩道を渡る。
  • タクシーは特に中心部だとぼったくられるらしいので注意。移動はUber使ったりした。

おわりに

まずは思っていた以上に楽しかったのでよかった。 PyCon APACでもない限りマレーシアには来ないかなと思っていたけど、普通に楽しい国でした。 来年はシンガポールでAPAC開いてほしい。

あとは柔軟に出勤日を調整してくれた、会社の人たちにすごく感謝してます。 今の会社でそんなに楽しそうに仕事してるのがちょっと不思議でいまだによく分からないというのを、今回お酒飲ん出る時に言われたのですが、普通に楽しく働けてます。

就活終わってからもなんでこの会社にしたのみたいな声は各所から頂いていたんですが、詳しい話聞きたい方はご飯行きましょう

オマケ: 撮った写真

f:id:nwpct1:20170825122014j:plain

チャイナタウン

f:id:nwpct1:20170829010607j:plain

Younggun(PSF ボードメンバー)が、2日目の夜に飲んでたJPメンバーを案内してくれたホテルのバーの夜景

f:id:nwpct1:20170828000255j:plain

ツインタワー前のウォーターショー。良すぎて2日連続行った。

python-prompt-toolkitをgolangに移植。kubernetesクライアント作った

Github Trendingに載ってから、予想以上に伸びました。ありがとうございます。

python-prompt-toolkitをgolangでも使いたいなと前から思い移植していたのですが、今日go-promptという名前で公開しました。

kube-promptは実際にgo-promptを使って作成したインタラクティブなkubernetesクライアントです。

kube-prompt

python-prompt-toolkit の移植

GitHub - jonathanslenders/python-prompt-toolkit: Library for building powerful interactive command lines in Python

python-prompt-toolkitは簡単にいうとインタラクティブな補完ができるライブラリなのですが、これを使った便利なツールがたくさん登場していて、かなりのstarを集めています。

自分はpython3を当然のようにインストールしているので、Pythonのツールを使うことが面倒には感じないのですが、普段pythonを使っていない人はpythonのインストールから始めないといけないので結構面倒そうです。

python-prompt-toolkitをGolangに移植する人が現れないかなと思っていたのですが、中々登場しませんでした。 ふと思い立って実装を読んでみると、テストコードなしの実装だけでも2万行以上とボリュームがあります。この強力な補完のために裏では結構面倒なことをしていて、実装もそれなりに複雑になっているので、なるほどこれは大変と思い挑戦してみました。

自分はこういう端末制御ゴリゴリのソフトウェアを作ったことなく、コードを読む上で必要な前提知識が色々と欠けていたので、いい勉強になりました。この記事では実装に関して書きませんが、需要がありそうなら記事書くかどこかで話すかしたいと思ってます。

詳しい使い方はREADMEに書いたので興味のある方は使ってみてください。比較的かんたんに使えるようになっているかなと思います。 オプションも色々用意してます。

f:id:nwpct1:20170813221708p:plain

今後追加予定の機能は

  • Windowsサポート
    • mattnさんがPRくれました。ありがとうございます。windows環境手元にないのでまだ試せないのですが、どうしようか
  • vi modeのサポート
  • multi line inputに対応
  • emacs キーバインドが本来と違う挙動をする箇所が見つかったので修正
    • Ctrl+Wの挙動だったのですが、b4b4r04さんが直してPRくれました。ありがとうございます。
  • Fuzzy Searchingとかprompt作る上で便利なutility系の用意

あたりです。

kube-prompt

kubernetesクライアントも用意したので、kubernetes触ってる方はぜひ使ってみてください。 Github Releaseからバイナリ落とすか、Homebrewで入ります。

2週間半のReact Nativeアプリ開発を振り返る

ここ2週間ちょっとReact NativeでiOSアプリ書いてました。 サーバサイドをメインでやってきた自分にとって面白い技術で、今後も趣味で使ってみたいなと思えているのでTipsや所感を残しておきます。

目次

選定理由

3人でとあるアプリを開発しているのですが、自分も含めてサーバエンジニア2人、iOSエンジニア(Webフロントとかもできる)1人の状態でした。 開発期間が短いわりに画面数の多いアプリケーションの開発だったので、JS経験のある自分もネイティブに加われるようReact Nativeを検討。苦労しそうな部分は早い段階で、検証しておきました。

  • カメラ撮影
  • iOSライブラリとReact Nativeのブリッジが問題なく作れるか確認
    • 画像のフィルタ処理(iOSのCIFilter)用ライブラリをReact Nativeから呼び出した
  • 動画再生
  • APIクライアント(fetch apiが使える)
  • Firebase JavaScript SDK(Firebase Authenticationを使用)

開発を始めて強く思ったのは、やっぱりネイティブの知識があって気軽に質問できる人が近くにいないと大変だったなと思います。 幸いiOSに詳しいチームメイトがReact NativeとiOSのブリッジを書いてくれて助かった。

一方で、アプリケーションのほとんどの画面はAPIを叩いてレスポンスを表示するだけだったりサーバに何か文字列を送るだけだったり、意外とJavascriptの範囲で出来ることが多くてサーバサイドばかりやってきた自分もがっつりiOSアプリ開発が手伝えます。

普段あんまりネイティブアプリケーションの実装とかを意識することはなかったんですが、スマホのアプリを立ち上げるとコンポーネントの組み方を考えるようになったり、細かいアニメーションに意識がいくようになりました。

Tips

エラーハンドリング・状態管理

f:id:nwpct1:20170528191247g:plain

React Nativeのコンポーネントや状態管理の設計は、ReactでSPAを作るのと感覚的にかなり似ているのかなと思っています。 今回は次のような手順で管理しました。

コンポーネントの状態を管理するStoreを用意。 このStoreでは、各ComponentIDに対して以下の4つの状態を持つフィールドとエラーメッセージを持つFieldが存在する。

  • BEFORE_LOADING : データをフェッチする前(コンポーネント生成時に、この状態に設定するActionを発火)
  • LOADING : データをフェッチ中 (ぐるぐるのローディングアイコン表示)
  • COMPLETE : 無事にデータを読み込みできている状態
  • ERROR : データのフェッチ中に何かしらのエラーが発生している。コンポーネントはこの場合エラーを表示

コンポーネントは次の手順で表示を変える。

  1. constructorで自分自身を示すIDを生成
  2. 各Componentに上のStoreの情報を伝搬させる
  3. componentWillMount で、自分自身のIDをstoreに登録(Storeでは BEFORE_LOADING にセット)
  4. componentDidMount で、データのフェッチをするActionを発火。自分の状態を LOADING に設定するActionも発火
  5. 200番のレスポンスが帰ってきたら
    • COMPLETE に設定するActionを発火
  6. 何か問題があったときは
    • ERROR に設定するActionを発火
    • エラーメッセージを登録する
    • エラー情報を表示するModalアニメーションを表示するActionを発火
  7. コンポーネントは自分自身の状態が ERROR ならエラーメッセージを表示、 COMPLETE なら受け取ったデータを表示

今回選んだ、エラーハンドリングや状態の管理方法はかなりうまく機能していた気がするので今後も積極的に使っていきたい。

入力欄をキーボードの出現に合わせて動かすアニメーション

書くか悩んだのですが、結構多くのアプリケーションで必要になる処理かなと思ったので載せておきます。 必要になった際は参考にしてください。

f:id:nwpct1:20170528193253g:plain

次のようにkeyboardの入力に応じて高さの変わるコンポーネントを用意

import React, { Component } from "react";
import { Animated, Keyboard } from 'react-native';

const defaultHeight = 48;

export class AvoidableKeyboard extends Component {
    constructor(props, context) {
        super(props, context);

        this.state = {
            height: new Animated.Value(defaultHeight)
        };

        this.keyboardWillShow = this.keyboardWillShow.bind(this);
        this.keyboardWillHide = this.keyboardWillHide.bind(this);
    }

    componentDidMount() {
        Keyboard.addListener("keyboardWillShow", (e) => this.keyboardWillShow(e));
        Keyboard.addListener("keyboardWillHide", (e) => this.keyboardWillHide(e));
    }

    keyboardWillShow(e) {
        Animated.timing(this.state.height, {
            toValue: e.endCoordinates ? e.endCoordinates.height : e.end.height,
            duration: e.duration
        }).start();
    }

    keyboardWillHide(e) {
        Animated.timing(this.state.height, {
            toValue: defaultHeight,
            duration: e.duration
        }).start();
    }

    render() {
        return (
            <Animated.View style={{ flexBasis: this.state.height }}></Animated.View>
        );
    }
}

あとは flexGrowflexBasis プロパティをうまく使って表示します。

(省略)

export class CommentListComponent extends Component {
    render() {
        (中略)
        return (
            <View style={{ flex: 1, backgroundColor: "#FFFFFF" }}>
                <ScrollView style={{ flexGrow: 2 }}>
                    {comments.map((c) => <CommentItemComponent key={c.id} comment={c} />)}
                </ScrollView>
                <View style={{ flexBasis: 50, flexDirection: "row", alignItems: "center", borderBottomColor: "#ddd", borderTopColor: "#ddd", borderBottomWidth: 1, borderTopWidth: 1 }}>
                    <TextInput
                        style={{ height: 50, flexGrow: 1, fontSize: 15, paddingLeft: 10 }}
                        onChangeText={(text) => this.setState({ text })}
                        value={this.state.text} />
                    <TouchableWithoutFeedback onPress={this.postComment} disabled={this.state.text.length === 0}>
                        <View>
                            <Text style={[{ fontSize: 15, fontWeight: "bold", paddingRight: 10 }, postTextStyle]}>投稿する</Text>
                        </View>
                    </TouchableWithoutFeedback>
                </View>
                <KeyboardSpace />
            </View>
        )
    }
}

今回使ったライブラリ

使ったライブラリも載せておきます。 ライブラリ選定の際に参考にどうぞ。

react-native-focus-scroll

ScrollViewの中で今ディスプレイに表示されているアイテムを知る方法がなかったので作成・先ほど公開しました。

Vertical Scrolling Horizontal Scrolling
sample - vertical sample - horizontal

react-navigation

今回はiOSアプリのみの開発だったので、公式の NavigatorIOS を最初つかっていたのですが、navigate時に渡したpropsが変化しても値が更新されないようです(NavigatorIOS optimizations break functional components · Issue #13539 · facebook/react-native · GitHub)。 これだと困るシーンがあったのでreact-navigationを使用しました。react-navigaitonのscreenPropsでstoreの情報とかを伝播させています。

f:id:nwpct1:20170528184130p:plain

見た目もカスタマイズ出来る範囲がNavigatorIOSより多そうです。

react-native-vector-icons

TabBarIOSのItemに画像を入れようとすると、うまくリサイズできなくて困っていました。 このライブラリはTabBarIOSに組み込むためのComponentも提供してくれています。あとSVGからttf生成して追加してあげれば自作のアイコンとかも使うことが出来ます。

f:id:nwpct1:20170528183852p:plain

react-native-camera

カメラで使用。 ここは全部チームメイトがやってくれて、自分は使い勝手がわからないのですが無事動いてくれています。

react-native-video

動画の再生で使用。 解説は特にないのですが、muteやpauseもpropsで指定できて使いやすかったです。

firebase

認証はFireabase Authenticationを使用しました。 JS SDKが問題なく動きます。

Firebaseから取得したJWTは、サーバ側で検証するのですが、SDKJavascriptとかPython用が提供されています。 Go用のSDKはないので、 こちらの説明 に従って自分で検証処理を書く必要があります。 検証用のコードを公開したので、ご活用ください。

Verify the JSON Web Token obtained from Firebase Authentication. But now, Go SDK is released by firebase organization. · GitHub

現在は公式でサポートされたので、そちらをご利用ください。

github.com

react-native-user-defaults

iOS限定ですが、JWTの保管はUser defaultsで行いました。

苦労したこ

スタックトレースについて

苦労した点はいくつかありますが、スタックトレースはReact Nativeを採用するか悩んでいる人の多くが心配しているかもしれません。 実際スタックトレースから情報がなかなか読み取れずデバッグが大変なシーンはいくつかありました

実際に発生したエラーのスタックトレースを3つほど載せておきます。

エラー1 エラー2 エラー3

エラー1は、バンドル後のJSファイル jsBundle.js 内での行数が表示されてしまっているケース。 エラー2とエラー3は、Objective-Cのブリッジ等の部分でエラーが起きてそちらのスタックトレースが表示されてしまうケースです。 自分の理解できそうな範囲を超えている感じがあって、原因を掘り下げられる気がしないときはトライ&エラーを繰り返す、くじけない気持ちが必要かもしれません。

再現性のないバグ

React Nativeに限らないかもしれませんが、再現性のないバグが比較的多く発生してしまた気がします。 自分の実装がまずかった場合も多いかと思いますが、決して成熟しきった技術ではないので、フレームワークやライブラリのバグを疑う回数も多いです。

再現性の無いバグについては自分も理解できていないのであまり多くは紹介しませんが、文字通り時間が解決してしまったケースもあります。 ほとんど参考にならないかとも思いますが、おかしな挙動に遭遇したときに自分がとりあえずやっていることを残しておきます。

  • git cleanでgitの管理対象外のファイルを消して、ビルドし直す
    • git clean -x -d -f -e node_modules -e .idea
    • 何か変更を加えてエラーが出たとき、戻してもまだビルドできないとかがたまにあります。開発序盤はとりあえずこれで乗り越えました
    • 1週間もしてくるとだいたいどの辺に問題があるのか感覚的にわかってきて、git cleanを使う回数が自然と減ってきた気がします
  • 自分が加えた変更が反映されずReloadしてもずっとエラーを吐き続ける場合 (実機Buildはうまくいくけど、Simulatorで動かない場合もある):
    • iPhoneのSimulatorのCacheを消す。git cleanも実行
    • Websocketサーバを一度止めてから react-native run-ios
    • どこにキャッシュが残っているのか、これでも何故か以前のコードがSimulator上で実行されてしまうときがありましたが、気づいたら直っていてもう再現できないので自分もよくわかっていません

サーバサイドのアプリケーションを開発していると、多くのバグは掘り下げることで突き止めることができる気分になれますが、iOSは自分には知らないことが多すぎてとにかく色々手を動かして条件を変えてうまく動くことを祈ることが多かったです。

開発をやってみて

冒頭でも書きましたが、カメラやフィルター処理といったネイティブの機能をガリガリ使うところ以外は自分でもかなり開発に参加できます。 また普段使っているスマートフォンのネイティブアプリケーションもネイティブの機能は使わずAPIの通信と表示のみで成り立っている画面も多いなと感じました。 スマートフォンの細かいアニメーションにも意識がいくようになり、色々とこれまで感じることのなかった面白さがあったかなとおもいます。

また趣味で使ってみたいですね。 終わり。

Learning React Native: Building Native Mobile Apps With Javascript

Learning React Native: Building Native Mobile Apps With Javascript