Quantcast
Channel: nashcft's blog
Viewing all 97 articles
Browse latest View live

#builderscon メモ: Haskellを使おう (Track B 14:30~15:30)

$
0
0

builderscon.io

speakerdeck.com

スライド見つつメモ読み返すとどこでついていけなくなったかがよくわかる 😇
最初は調べてメモの内容を充実させてから投稿しようと思ったけど現実的な時間でできそうにないしスライド読もうねという感想なので投げました

モナド周りは5月のJJUGで発表された↓のスライドがわかりやすかった記憶があるので読み直して勉強し直します…

www.slideshare.net

agenda

  • 話すこと
    • stack/ecosystem
    • 実行制御
    • IO処理
    • 外部パッケージの利用
  • 話さないこと

Stack

  • cabal-installに代わるbuildtool
  • 依存パッケージのローカライズ
    • cabalは全部globalな管理してたくさい
  • 最速でREPL
    • curlでインストール ->stack setup ->stack ghci
  • Stackage
    • package一覧
    • Hoogle (関数名/型名/型定義 (::型名) で検索)
    • doc (モジュール一覧、依存・非依存package)
  • buildポイント
    • ghc-options: -WALL @ *.cabal
      • 全警告表示
    • hlint
    • ghc-options: -threaded @ *.cabal
    • hpack
    • ghc 8.2.1
      • error表示がcolored

Haskellのコミュニティ

書籍が出る

実行制御

  • 順次処理: do
    • 操作を並べて書く
  • 分岐: caseなど
  • 繰り返し: リスト、Freeモナドなど再帰データ型を介した繰り返しは得意
    • map, foldr, mapM_
    • continue は filter
    • break は takeWhile
    • 手続き的なループは…
      • 再帰で同様な振る舞いを記述できる (loopを用いる)
      • Streamingライブラリを用いる (e.g. conduit)

I/O処理

  • 書けるけどそれほど得意でもない
  • appにおいてはほとんどの場合I/Oが主役
    • I/O処理ができないと利用価値が…
    • 利用価値のあるappを作りましょう
  • I/Oのノウハウを会得しよう
  • I/Oが可能な場所
    • IOモナドの中
      • e.g. main関数
    • IOをモナド変換子でラップしたモナドの中
      • a -> b ->… -> OtherMonadT Hoge (SomeMonad Foo Bar IO) z みたいな
      • lift
    • MonadIO型クラス
      • MonadIO m => a -> b ->… -> m z みたいな
      • liftIO
    • IOモナド
      • 入出力、mutable変数、例外やcatch
    • IOモナドがないとこれらの機能を利用できない
      • State, Errorなどのモナドはあくまで模倣
    • 書きやすいかというと…
      • >>=はcallbackを要求: callback hell…
      • doで隠す
    • モナド状の操作
      • 操作: 戻り値の型が Monad m => m a の形式のもの
        • putStrLn :: String -> IO ()
        • とか
      • 操作でないもの
        • unsafePerformIO :: IO a -> a
        • runState :: State s a -> s (a, s)
      • do記法にかけるもの
        • 操作に引数を適用した、Monad m => m a型を持つ式
        • 一つのdoブロックには1つのモナド操作しか書けない
        • 並べた操作がどう実行されるかはモナドによる
          • IOでは並べられた順に
      • do記法のコツ
        • 変数定義
          • let x = ... vs x <- ...
            • <-は操作を実行した結果を取り出して束縛
              • 操作を直接引数にできないので必ず <- で束縛してから使う
            • letは右辺をそのまま束縛

アプリケーションと状態

  • 状態の受け渡し
    • State, Reader
    • doブロックに書けるモナド操作は一つだけ
      • ウッ
  • モナド変換子
    • モナド m に操作を追加する
    • モナド m の操作は lift を経由して使う
    • runHogehogeT という命名でモナド m に戻す関数が存在
    • StateTモナド変換子
    • ReaderTモナド変換子
      • 読み込みだけでなく状態を表現できる
  • FWに現れるMonadIO

パッケージの選び方

  • Stackageの自分が使うLTSから選ぶ
    • Cのライブラリへの依存でハマることが多い (特にWindows)
    • ドキュメントをよく読んでおこう

eureka Meetup 04 -チーム開発ナイト- memo

$
0
0

6月末の

Pairsにおいて大事にしたいユーザ体験やプロダクトで大事にしている価値

  • テーマ: UX ->チームの作り方
  • 大事にするUX
    • 出会えること:
      • マッチングUU, メッセージUU
      • 誰でも迷わず使える
    • 安心・安全である: 24x365 監視体制

価値観

  • ユーザに対して真摯
    • don't be evil
    • ちょっとした不具合や触り心地の悪さを許さない
    • monetize < UX
    • マーケットリーダー: オンラインデーティングに対する印象に対する影響
  • 機能追加≠価値追加
    • 機能 < 提供価値
    • 仕様ないではなく課題への解決方法を考えるという文化
  • たくさん機能が欲しいわけではない
    • 減らす、磨く
    • 価値は何か?
    • 数字・ユーザが使う様子を見せる
  • 規律よりも規範
    • チーム数の増加: 10~12人超えたくらいでチームを分ける
    • 「語れる人」を各チームに必ず含める
      • 語れる人を増やす必要 ->考えていることがバラバラに
    • 局所最適化した動き・考えに傾きがち
    • ビジョン・理念の浸透スピード < 人の増加
      • 意思統一の難しさ
    • やってること
      • 最初はチームリーダーを通していた
      • PMとしてチーム全体に投げかける
      • 全社会
      • 社内SNSで発信、お気持ち課題の提起、同じことを何回も言い続ける
      • 張り紙、意外と効果がある
      • 良いことはどんどん褒める
      • エモい話をぶっ込む
    • recap
      • プロダクトの芯をぶらさず伝える
      • 発信者が実践者としてやっていく

自己組織化された開発チームの作り方

  • 何かを始める時のポイント
    • 変えることを目的にしてはいけない。何故を伝える
    • 「何故」 ->強いチームが必要 という流れのポエムを投稿
      • 熱量は大事
    • 自ら考え、小さく実践、フィードバックする
    • 自己組織化したチームを目指したい ->会社の理念に合致するね
    • 小さく、正しく始める (問題点の見える化、フィードバック)
  • 全社を動かす時のポイント
    • 2人目のフォロワーが重要
      • すでにチームになっている
    • 経営課題にリンクさせる
    • 解決されると得られる基準にCXOを常に会話する
      • 価値を提供するための手段
    • 短期での結果を求めず中長期で課題を解決させる大局的な視座が必要
    • 会社のステージに応じて作戦を考える ->画像の出典: elastic leadership
      • サバイバルモード
      • 学習モード
      • 自己組織化モード
    • 透明性大事: 十分な情報があれば自律的に動ける
      • みんなが見えるところで発信 (フィードバックとか) ->お互いで学び合うことができる
    • なんか楽しい・良さそう感を出していくことが大事
    • 外部の専門家を巻き込む
      • 全部自分でやらなくて良い
      • WHYを伝える努力、思いの代弁

スクラムマスター、プロダクトオーナーを両方経験して分かったこ

  • 何故チーム開発なの?
    • 一人でできることは小さい
  • scrumの具体的なお話
    • daily scrum
      • warmup (openingテーマ)
      • burndwon chartを見る: 単なる目安であって正確にやってはいない
        • 見積もりは1~2時間幅
      • 各自が話す (いつもの3つ)
        • 問題解決: みんなで
      • 5 finger: ゴールに全員で達成できそうかを評価 (1,2がでたら解決するためのアクションを話す)
      • あるある失敗談
        • 困ってるけどなんとかします (気合い): next actionは? 助けられることはない?
        • JIRAに乗ってないことをやった: 透明性を壊している. POへの確認は?
        • BCが落ちてない ->もう少し様子を見ましょう: 理由や状況をきちんと把握しよう
      • リファインメント
        • ?
        • ?
        • ストーリーポイントで素早く道もる
        • (次のスプリントなどで)開発できる状態に
      • その場で疑問が解消しなかったら即持ち帰り課題にして次の日までに調べてやり直し
      • 毎日にしてよかった点
        • PO <->開発チームの会話を毎日モテている
        • プランニングの時に慌てることがなくなった
      • 失敗談
        • ユーザへ価値を届けるための他の手段を議論できていない。価値にフォーカスして手段を議論する
        • POの要望がでかい ->会話しながら小さく分割していく。本当に価値を届けられるものを最も小さい規模で MVP
      • SMで大事にしていること
        • 推測より会話 (齟齬の原因は推測)
  • Q&A
    • 24x365の監視体制: 開発じゃなくてカスタマーケアのチーム
      • チーム分けると顧客フィードバックに関する学びが薄くなるのでは?
      • 改善のためのチームを作ってとか体制を作ってる
    • 開発チーム内のロールだったりとか
      • ios x 2, android x 1 server x 3
      • インフラ? ->専用チームがいて、開発チームと連携して活動したり

新チームで初スクラムして感じたチームの成長に大切なこと

  • 大切なこと
    • why and value
      • メンバー全員で議論して、回答を作り上げる ->インセプションデッキ
      • 認識統一
      • POから繰り返し伝えること
    • 選択と集中
      • 手広くやろうとすると崩壊
      • やってることを増やしすぎず着実に終わらせる
      • あるべき、 ありたい vs 現状
      • KPT -> Tryたくさん出てくる -> priorityをつける ->重要なのから着実に終わらせる
        • 着実にやって成功体験をきちんと積む
  • Q&A
    • やっぱTry溜まっちゃうよね
      • Tryを推進するための責任を持つパーソンが必要では? 誰かがやってる、or 他のやり方
      • 推進はSMが行っているがどうするか考えるのは開発チームでやってる
    • why and valueを実践、定着させるためのワークショップ・お話など

日記的なもの

$
0
0

継続的になんかしらの文章を書くということをしようと思ったので日記的なものを書くことにした。

今日は先週から取り組んでいた、CIにCircleCI を使っているレポジトリを 1.0 から 2.0 に移行する作業の残りを片付けた。先週の時点で半分は移行が終わっていて、残りはフローががほぼ一緒だったので殆ど時間もかからず終わらせることができた。
一点だけ躓いて、回避したもののまだ解決していないことがあって、working_directoryに指定した path を環境変数CIRCLE_WORKING_DIRECTORYを使って呼んでディレクトリ移動などをしようとしたところ、job出力の表示上は想定通りの path になったにもかかわらず "No such file or directory"となってしまった。環境変数を使っていた箇所をハードコードしたら全く同じ path なのに問題なく通ったので現在は全てそのようにしている。

circleci.com

とりあえずそれ以外は上手くいってて、2.0でのconfig の書き方や workflow の組み立て方も理解したし、移行後のCI実行時間もかなり短縮されたのでだいぶ気持ちが良かった。

あとは細かい修正のプルリクをいくつか出して、残りの時間は Androidとそのアプリ開発の概要に関するレクチャーを受けていた。

明日は Androidアプリ開発の勉強をしつつ Dangerを本格的にCIに組み込むタスクに取り掛かる予定。

$
0
0

午前

これはブランチ運用をどーのこーのというのが昨晩あったようでこのあとアナウンスがありPRの受け入れ先も用意されてめでたし。

午後

なんかAndroidSDKのインストール時にライセンスへの同意がまだ済んでないよとのことでビルドが通らなくなってしまった。
${ANDROID_HOME}/licensesのファイルを持ってきたりしてもダメで、docker image 側の問題だろうなーという感じだったのだが Docker Hub の見方がいまいち分からずどこに Dockerfile があるのか分からなかったので Discussで報告して帰宅。
業務時間の3/4くらいあれこれやって結局解決できず、CircleCIのビルドが真っ赤なまま帰らざるを得なかったのでとても悲しい。
書いてる今投げた報告を見たら別の報告と merge されてて、やっぱ docker image に build-tools がインストールされてなかったようだ。とりあえずなんとかなりそう。

同居人が夕飯を作ってる間に包丁で指を強かに切ってしまい、応急処置をして様子を見てたのだがそれだけじゃダメそうだったので救急外来に行って診てもらった。
救急外来っていうと重篤な状態じゃないのに使っていいのかなーと躊躇ってしまう印象があったが、夜間外来とか時間外外来とも呼ばれているようでなるほどとなった。
あと時間外で担当できる科が病院ごとに日によって違うそうなので、近所で時間外受け入れをやっている病院の外来に直接電話をかけるのではなく #7119に状況を伝えて適切な病院を紹介してもらった方が良いという知見を得た。

イベントが立て続けに発生し大変疲れた。これから夕飯を食べる。

平日の終わり

$
0
0

CIrcleCI の移行がひと段落したので勉強も兼ねて Androidアプリの新規画面の実装タスクを拾ってみた。
入門書をザーッと読んでどれくらい理解したかなーという感じで手をつけてみたけどどうも Layout 周りがダメっぽいのでその辺りの復習をしようというところ。

$
0
0

タイトルを考えるのが面倒になった

今日は演奏会を聴きに行ったり腕時計を修理に出したりと外をウロウロしていた。用事のついでに『テスト駆動開発』を買おうといくつか本屋に寄ってみたがどこも在庫切れになっていたのでamazonで注文した。とは言えamazonも現状在庫切れなので届くのは当分先になるだろう。
電子書籍ならすぐ手に入れられるのだがpdfしかないので今回は紙の本で購入する。epubとかで出されていたら電子書籍版を買ったのだけど...

本が届くまでの間に積読になっていた原著の方に目を通しておく予定。

$
0
0

様々な理由により帰宅時間が遅くなるとこのように日記的なものは書かれなくなっていきます

今回は退勤後にジムに行き帰りの電車の接続が最悪だったので日付が変わりそうな頃に帰宅をした。
仕事の方はレイアウトが書き終わって javaをもそもそと書き始めたところまで。 ConstraintLayout を layout editor で編集するのクッソ辛いなというのがここ二日くらいで得た知見であり、誰か上手いやり方と ConstraintLayout について教えてくださいという気持ち。

ここ数日やってたこと的な

$
0
0

終わったと思っていたレイアウト書きが実は終わっていなかったなどありここのところ ConstraintLayout と格闘して打ちのめされていたのだが、やっとひと段落つき定時で帰るなど時間や心に余裕ができたことにより日記的なものを書く気力が自然と湧いてきたのである。

レイアウトいじりというか実際は画面開発をもそもそとやってて、RecyclerView の使い方を覚えるとかうちのアプリの特徴を捉えるとか ConstraintLayout を習得するとか色々なことを同時にやっていて、そういうことをすると注意が散漫になり ButterKnife.bind()に与える targetを間違えて何も表示されないということが発生する。
それで ConstraintLayout で適当に View を並べて constraint を設定してエディタ上ではいい感じにできていたのが実際に動かしてみると例えば TextView に入ってくる文章の量によって View のサイズが変わって隣り合った View が重なってしまうとかあるよねーと思いながら直すのだけどエディタ上で再現できなかったり未だに理解していないことが多い。結局 1.1.0-beta をぶち込んで Barrier でねじ伏せることで解決したけれども、安易に beta をプロダクトに取り入れるのはどうなの? というお話があり審議中という感じ。

ConstraintLayout でレイアウトを作るとき、最初はレイアウトエディタで適当にものを並べたり簡単に constraint をつけたりというところまでした後、最終的には constraint に関しても xmlを手でちまちまやっていくことになり、一貫してどっちかでできないかなーという気持ちになった。

Constraint でのポジショニング、chain の作り方、bias, goneMarginの設定、alignment や guideline、Barrier の使い方あたりはだいたいわかったけど、まだ謎なことが多いのでもうしばらくの間は https://constraintlayout.com/とかを眺めて理解を深める時間を作る。


風邪と情報共有と

$
0
0

風邪を引いてて治りつつあるものの鼻水が辛い...

今日は小さいタスクを1つ片付けた以外はほとんどコードレビューをしていた。
昨日まで ConstraintLayout で苦戦していて自分しかこれを使っていないから頑張るしかないと思っていたら先行して別の画面を開発していたメンバーが実は ConstraintLayout を使っていたことに今更気づいた。割と和気藹々とやっているチームだけどこういう所の情報共有が課題なんだなあと思った。プルリクエストを出すまでの間のコミュニケーションがあまりに少ないのでそこから改善できないかなあ。

情報共有をはじめとしたコミュニケーション関連の問題はチーム内だけでなくチーム間でも以前からあって、チーム移動を経験してその辺の実害を割と具体的に実感していてどうにかしないとなーとなっている。今も前いたチームと今いるチームの間で地味な問題を抱えていて、今いるチームの人とは普段の会話の中でその辺の事情やら背景やらのお話をしてじゃあどうやっていきましょうかと話を進めることができているのだけど、前いたチームは自分がいた頃はそういう話を聞いたことなかったしどのくらい認識してるのかなーというのが掴めてなくてどういう切り口でお話をしたらいいかなーと変に気になって進められていない。

夜中のテンションでこういう悩ましいことについて考えるとよくない方向にしか進まないのでこれで、コミュニケーションはとても難しいのに無頓着な人が周囲に多くてつらい気持ちになるなあということだけ吐き出しておしまい。

😷

$
0
0

今日は出社したら Android Studio 3.0 がリリースされていたので早速アップデードした。とりあえず新しくできるところは新しくして、引っかかるところがどこかだけ眺めておいた。来週くらいから Gradle の android plugin のマイグレ作業をすることになる。

午後は半分ミーティングで残りの殆どは社内勉強会だった。今日は若者数人で『テスト駆動開発』のもくもく写経会を始めた。参加者全員がJava経験者というわけではなかったので取り組む際の言語は自由として、私は色々と折角な機会だったのでKotlinで進めることにした。ところでこの会では git レポジトリやプロジェクトを作ってもらうところからやってもらったのだが、今年新卒で入った人がその辺の知識・経験がなくて苦戦しており、それのサポートに結構時間がかかったので本の進みは1章の途中くらいまでだった。 git は普段から使っていて仕事始めてからもう半年も経つのだから問題ないかなーと思っていたのだけどそうでもなかったのは結構意外で、ちょっとこれはフォローしないとなとなり次回は git 会にすることにした。

風邪、直に治ると思っていたのに帰宅してから熱をはかったらまた上がってしまったので今週はもうおしまいです。

日記的な

$
0
0

風邪治った

昨日今日でタスク1個こなして、あと Effective Javaの読書会したりコードレビューしたりした。最近読書が疎かになりつつあるのでよくない。
今日のタスクでは ViewHolder まわりをいじっていたのだけど、 RecyclerView における ViewHolder とそれに紐つく (?) View の関係やライフサイクルとか、layout のxmlと実際に表示されている view がどうのとか、再利用とかメモリ効率がどうのとかってどうなってるんだろうなーというところが気になった。
そう言えば gradle plugin の移行はもうちょっと先になりそう。

今日読んだ本:

  • 融けるデザイン -> 63%
  • Effective Java -> 6章入った

Effective Javaの読書メモを会社のwikiに残しているけどそのうちこっちに持ってこよう。

日記

$
0
0

チームの人からのサーバサイドAPIの挙動に関する質問を聞いていたらAPIの不備が見つかったのでシュッと直してプルリクを投げた。
大した規模の修正ではなかったのでその場ですぐプルリクにしたのだけど、弊社では基本的にタスクをチケット化するのが決まりで、チケットも作らずにこういうことをしていると見えないタスクを生み出してしまい、誰が今どのくらいタスクを持ってるかとか誰がどの期間で何をどのくらいやったかといったトラッキングを正確にできなくてよくないですねということが考えられる。でも縦割りチームだとチームをまたいだ作業は記録しても見えにくいし開発タスクはGitHubの草でも見たらいいじゃーんというか、そういう行動データがJIRAだったりGitHubだったりetcだったり散っちゃっててそもそも上手くトラッキングできてないじゃーんウワーつらい眠いのでおわり。

JJUG CCC 2017 Fall に参加した

$
0
0

20分枠で Eclipse Collectionsの紹介をした。

slides.com

発表時の様子をコミッタの1人である @itohiro73さんがまとめてくださっている。

togetter.com

発表後の振り返り

余談

このライブラリは今勤めている会社のサーバサイドチームで Stream APIの代わりとして1年半くらい使われていて、最近はチーム加入後に取り組むハンズオントレーニングの題材にも組み込まれるようになった。
プロダクトの中で両方が混在していると混乱するだろうということで Stream APIを使わないように規約で決まってるので面白がって以下のようなやりとりをすることがある。

Eclipse Collections と私と今後

まとめのところで何かコントリビュートするぞと口走ったので来年末くらいまでに何かできたらいいなあと考えている。Immutable なコンテナでできることを増やしていきたいなあとか。
仕事ではサーバチームから Androidアプリ開発チームに移動して使う機会がなくなってしまっているのがネックかなー...

Binder transaction buffer は1MBとは限らないかもしれない話

$
0
0

今開発しているアプリで特定の端末・条件でとある画面への遷移時に画面が真っ暗になって操作を受け付けなくなったり、該当する中で古い端末だとアプリが強制終了したりしてしまうという現象に出くわして、ログを眺めてみたら以下の例外が出続けていた:

Exception thrown launching activities in ProcessRecord{(略)}
    android.os.TransactionTooLargeException: data parcel size 645548 bytes
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(Binder.java:615)
        at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:893)
        at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1330)
        at com.android.server.am.ActivityStackSupervisor.attachApplicationLocked(ActivityStackSupervisor.java:892)
        at com.android.server.am.ActivityManagerService.attachApplicationLocked(ActivityManagerService.java:7116)
        at com.android.server.am.ActivityManagerService.attachApplication(ActivityManagerService.java:7194)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:542)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3032)
        at com.android.server.am.ActivityManagerServiceEx.onTransact(ActivityManagerServiceEx.java:594)
        at android.os.Binder.execTransact(Binder.java:565)

それでリファレンスを読んだりQiitaの記事を漁ったりして、上記の例外は Binder transaction buffer に対して上限を超えたサイズのデータをやりとりしようとした時に発生するっぽいことがわかった。

読んだ記事: qiita.com

qiita.com

確かに問題の画面遷移では Intent にそれなりなサイズになるデータを1つ保持させるのでそれかなーと納得しかけたが、ちょっと変なことに気がついた。
読んだページの中で Binder transaction buffer の上限は1MBと書かれているが、上の例外には data parcel size 645548 bytesとある。つまり読み方が間違ってなければだいたい650KB弱のデータで音を上げていることになる。さっきの「それなりなサイズのデータ」以外に保持させている大きなデータは無いし、そうなると transaction buffer の上限が1MBならばこれで too large と判断されるのはおかしいはず。

それで気になってググってみたら StackOverFlow の以下の記事がすぐに引っかかった:

stackoverflow.com

The limit is supposed to be 1MB but it varies by device from little less than 512KB up to almost a full 1MB.

質問は2013年、上で一部引用したベストアンサーの回答も2015年とやや古いが、端末によって transaction buffer のサイズが異なるとある。それで "binder transaction buffer size vary"とかでさらにググってみたら他にもいくらか引っかかる様子。

https://www.neotechsoftware.com/blog/android-intent-size-limit

リファレンスはまるで一律1MBだと定めているように読めるのでなんだかなーという気持ちになった。リファレンスの記述は以下の通り:

The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process.

さてどうやって対応したものかね...

久々の日記的な

$
0
0

色々あり3週間弱もの間日記的なものを書かないでいた...

先々週の土曜日までは JJUG CCC の発表資料を作っていたとか、先週は業務でタスクが突然押し寄せてきたので残業しまくっていたとかそういう言い訳をすることもできるが実際それを言い訳に忙しいから落ち着いてから再開すればいいやとか考えてた。
とまあそんな感じで最近は細かいバグ取りタスクを捌くことに気を取られていたので他のことはあまりやっておらず、でも休日には怪獣惑星を観るなどはしていた。ところでバグ捌きをしているとQAチームとのコミュニケーションが増えるのだけどここもまたニャーン

ニャーン

先週で怒涛のようにバグを潰したので今週は結構落ち着いていて割と余裕がある雰囲気。今日は息抜きに社内wikiを眺めていたら若者がいつの間にか日報を始めていたのに気づいて最新の分までさらりと読んでいた。日報って1人でやってると虚無になってしまうので私も日報仲間になろうかなーと思っている。

前回の記事のことを思い出したけど、あれは後から見直して正しくなさを感じたので調べ直して修正する予定。業務の方では Intent に保存するデータ量を雑に記録して適当な上限を設けるなどしてなんとなく解決した。感覚的には端末間で binder transaction buffer のサイズにばらつきがあるという方がしっくりくるのだけど、とりあえずAndroid One S2は600KBくらい放り込むとTransactionTooLargeExceptionを吐いて死ぬがXperia系は問題なく処理する。別件でXperia系に苦しめられていてどちらかというとXperia系の方がいい加減なのではないかという気持ちになりつつある。

とりとめがないけどおしまい


+メモ書き

$
0
0

前回のブログで余裕があるとか言ったな、あれは嘘だ。嘘だったんだ... Binder transaction buffer の記事修正は今週末にやろう...

先週も結局ヒイヒイ言いながら開発タスクをやっつけてて、今週も厳しそうな雰囲気がある。そんなこんなもあり昨日今日とバス係数についてふわふわと考えているような状態になっていて、それは色々な事があるからです。

ところで先月頭に始めた『テスト駆動開発』の写経会、最近は参加者各位の多忙により全く進められておらず、とはいえ皆の予定が合うまで延期というのではつまらなくなってしまい先週末から1人で進め始めてしまう事にした。

github.com

レポジトリ名の通り Kotlin で進めているのだが割と面白いことになっていると感じているのでElmで進めている方がやっているようにブログに過程をまとめようと思う。章の区切りも合わせようかな。第一弾は今週末までに書く。

今回ブログを書いたのは日記的なものを書くというよりもTODOを書き残しておこうという理由で、今週末までにやることを以下にまとめておく

  • Binder transaction buffer のサイズについて再調査 & 記事の加筆修正
  • Kotlin で『テスト駆動開発』をやった過程についてブログを書く (1~4章?)
  • TDD_kotlin: 14章を終わらせる
  • "Reactive Android Programming"の写経レポジトリを作成して chapter 1 まで終わらせる

オッ、なんか増えましたね...

Kotlin で『テスト駆動開発』 (第1章 - 第4章)

$
0
0

せっかく『テスト駆動開発』を読むのだから写経をしながら、それにただ写経するだけというのもなんだし他の言語でやろうということで学習がてら Kotlin で取り組んでいたのだが、これが中々面白かったので取り組んだ過程を、ある程度整理した上で*1書いてまとめる事にした。

大雑把にいうと以下の記事に影響を受けており、章の区切りなどもこちらに沿うようにしている。

qiita.com

レポジトリは↓

github.com

なぜ過程を書くのか?

もともと『テスト駆動開発』の内容は、新訳版の翻訳者である t_wada さんのブログ記事にもある通り、著者 Kent Beckテスト駆動開発の手法を用いながらインクリメンタルにプログラムを書き進めていく時の思考の推移を辿っていくような構成になっている。

本書の第I部、第II部は、ペアプログラミングのような語り口で、そのときどきの思考の言語化を挟みながら、コードがだんだん育っていくという構成を採っています。

この「思考」が、使用した言語によって変化させられる様であるとか、その結果として書き上げられるコードの形にも表れるところがとても興味深く感じられたので、私自身が辿った思考の流れも残しておけば誰かにとって参考になったり興味深い読み物になったりするのではないかなあと思ったからである。

進め方

Qiita の記事の方針に沿って本の内容と変わらないところは TODO リストとコードだけで進め、Kotlin特有の何かや思考が本の内容と異なった部分に関してはそれについて書いていく。

事前準備

プロジェクトのセットアップは各自適当にやってください。私はこれを参考に IntelliJ IDEA で build.gradleを書いていたら色々サジェストしてくれたので結果的に このようになった。

第1章 仮実装

最初の TODO リストは以下の通り:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [ ] $5 * 2 = $10

早速テストクラスを作る。

// MoneyTest.kt// package, import は省略class MoneyTest {

    @Testfun testMultiplication() {
        val five: Dollar = Dollar(5)
        five.times(2)
        assertEquals(10, five.amount)
    }
}

このレベルだとJavaと殆ど差異がない。ここでの Kotlin 的要素といえば以下のようなものがある:

  • デフォルトの公開レベルは public (classfunの前に修飾子をつけていない)
  • 変数宣言時に valをつける
    • val/varがあり、前者は再代入不可、後者は再代入可
  • 型は後置表記
    • 型推論が効くので省略が可能。以後明示する必要がなければ全部省略する

以後進行にあまり関係のない Kotlin 要素はスルーしていくので各自適当にググってください。

最初のテストを書いたところで TODO リスト更新:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [ ] $5 * 2 = $10
  • [ ] amountを private に
  • [ ] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?

まずはコンパイルエラーを直す。 Dollarクラスに amounttimes(Int)があれば良い。

// Dollar.ktclass Dollar(var amount: Int) {

    fun times(multiplier: Int) {}
}

Kotlin はコンストラクタで引数に受けた値をそのままフィールドに代入するだけ、という場合はクラス名の後の()に修飾子つきの引数を記述するとそのまま値を入れてくれる。今回 amountはそれに当てはまるので Dollar(var amount: Int)となった。

とりあえずコンパイルが通って、次はテストが red になる。
テストを通すには amount10を返してくれればいいのでとにかく10を返すようにする。
テストが green になったらリファクタリングtimes()のなかで amountを変更するようにする。

class Dollar(var amount: Int) {

    fun times(multiplier: Int) {
        amount = 5 * 2
    }
}

数字のハードコーディングになっているところをメンバや引数に置き換えて重複を排除していく。この辺は本の内容と一緒。

class Dollar(var amount: Int) {

    fun times(multiplier: Int) {
        amount *= multiplier
    }
}

この間コードを修正するたびにテストを実行して green であることを確認し続ける。ここまでくれば TODO リストの項目を1つ完了にできる。

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [ ] amountを private に
  • [ ] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?

第2章 明白な実装

本の内容と変わりがないのでスキップ。

class Dollar(val amount: Int) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)
}

amountに再代入しなくなったので varから valに、また times()は値を返却する1行の関数になったのでブロック表記から式表記に変更できた。

TODO リスト更新:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [ ] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?

3章 三角測量

Value Object パターンのお話から始まり、DollarValue Object として扱うための TODO (equals(), hashCode()) がリストに項目が追加される。
これらの事情は Kotlin も一緒なので本のコードとほぼ同様に equals()実装して、最後にまた TODO リストを更新。

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [ ] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [ ] hashCode()
  • [x] nullとの等値性比較
  • [ ] 他のオブジェクトとの等値生比較
class Dollar(val amount: Int) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)

    overridefun equals(other: Any?) = amount == (other as? Dollar)?.amount
}
class MoneyTest {

    // ...@Testfun testEquality() {
        assertTrue(Dollar(5) == Dollar(5))
        assertFalse(Dollar(5) == Dollar(6))
    }
}

上記のコードで Dollar同士を equals()ではなく ==で比較するように実装しているが、Kotlin の ==Java==とは異なり equals()を用いた比較の糖衣構文でだからある。ちなみに equals()==は全く同じ機能ではなく、リファレンスによると a == ba?.equals(b) ?: (b === null)と同等の判定を行うとのこと。==に関しては後でちょっと話題になる。
あと Kotlin は基本的に nullを扱う場合は ?が最後についた型や演算子を使ってNPEを吐かないように実装しないとコンパイラに怒られ、結果的に equals()の実装は nullとの等値性比較をクリアしている。

ところで Value Object を作るたびに equals()とか hashCode()とかいちいち実装しなきゃいけないとか等値性比較で色々考慮しなきゃいけないの大変面倒で、Kotlin に来てまでジャバ界のつらみを背負いたくないとなるが、そこはさすが最近の言語ということで、 data classというものがあり、これは以下の特徴を持っている:

  • Data class として定義するとそのクラスに適した equals(), hashCode()が自動的に付与される
  • toString()"<Class name>(<field>=<value>[, <field>=<value>...])"という出力のものが実装される

Dollarをただの classから data classに変更すると、テストをそのままにさっき実装した equals()を捨てることができ、さらにおまけでこの章の最後に追加された TODO の項目も潰せるようになる:

dataclass Dollar(val amount: Int) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)
}
  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [ ] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値生比較

Data class, Value Object を作る手間がだいぶ省けるので地味に嬉しい機能だ。

第4章 意図を語るテスト

ここはやることに変わりなし。 Dollar(val amount: Int)Dollar(private val amount: Int)とすると amountの公開レベルを private にできる。

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値生比較

この時点でのコード:

class MoneyTest {

    @Testfun testMultiplication() {
        val five = Dollar(5)
        assertEquals(Dollar(10), five.times(2))
        assertEquals(Dollar(15), five.times(3))
    }

    @Testfun testEquality() {
        assertTrue(Dollar(5) == Dollar(5))
        assertFalse(Dollar(5) == Dollar(6))
    }
}
dataclass Dollar(privateval amount: Int) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)
}

ここまでのまとめ

テスト駆動開発』の第4章までを Kotlin で進めてみた。ここまでは基本的に Javaと変わりなく、違いといえば言語間の記述方法の違いと data class くらいなので、基本的な流れが変わらない分この記事単体では面白さに欠けるものかも知れない。これはクラス単体の表現の仕方に Javaと Kotlin で変わりがないことの表れだとも言える。
次回以降は複数のオブジェクトの関係や抽象化などの話が加わり、Kotlin でできる表現の方法と Javaのそれとの違いが見えるようになって、環境の違いによる思考や実装の変化というこの一連の記事で示したいことを見せることができる、はず。

*1:実際に取り組んだ時は通り過ぎて暫くしてから、またこれを書いている最中に気づいたりより Kotlin っぽい書き方を知ったりしてコードを書き直したり記事の内容に盛り込んだりということがままあったので順番通りに書こうとすると脱線が激しく記事としてまとまりがなくなるため、それらを必要な地点で記述できるように並び順を直している。そのためレポジトリのコミットログとこのまとめの内容に乖離が発生しており、大雑把にいうと GitHubのレポジトリは1周目、この記事は2周目の世界として見ていただきたい。

穏やかに週末をむかえる

$
0
0

直近の日記としてのブログで忙しいとかつらいとかニャーンとか言ってた原因の切羽詰まった状況が木曜で終わり、その開放感に任せてTDD写経のブログを書き上げた後、とても穏やかな気持ちでむかえた今週最後の平日はそれなりな進捗と共にとても穏やかに過ぎ、帰る前にちょっとバタバタしたのをとても穏やかな気持ちで対応して帰りしなに寄り道してラーメンを食べて帰宅して諸々の後に今がありこれから寝ます。Rxの勉強はやり損ねました。土曜日は幕張までガルパンを観に行きます。おわり。

Kotlin で『テスト駆動開発』を進める (第5章 - 第7章)

$
0
0

前回 nashcft.hatenablog.com

今回は第5章から第7章まで進める。
これまでの過程で書いたコードは以下の通り。前回の脚注で触れているが実際に私が取り組んだ時のものに対して順序の再構成やコードのブラッシュアップなどを行っているため、レポジトリのコードやコミットの流れとは異なっている部分がある。

MoneyTest.kt

class MoneyTest {

    @Testfun testMultiplication() {
        val five = Dollar(5)
        assertEquals(Dollar(10), five.times(2))
        assertEquals(Dollar(15), five.times(3))
    }

    @Testfun testEquality() {
        assertTrue(Dollar(5) == Dollar(5))
        assertFalse(Dollar(5) == Dollar(6))
    }
}

Dollar.kt

dataclass Dollar(privateval amount: Int) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)
}

第5章 あえて原則を破るとき

これまでは1種類の通貨に関して注目していたが、この章から本題となる「多国通貨の足し算」を行えるようにするための準備が始まる。
まずはもう1つの通貨としてフラン (Franc) を追加し、これまで扱ってきたUSドルと同じように動作させたい:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値性比較
  • [ ] 5CHF * 2 = 10CHF

この章で行うことは Francクラスに対して Dollarに対して書いたものと同様のテストを追加し、 Dollarをコピペして Francクラスを作るというもの。短時間で確実に前進できる手段を選ぶためならばこんな行いも許容される。ただしその後きっちりリファクタリングをするならば、だが。

class MoneyTest {

    // ...@Testfun testFrancMultiplication() {
        val five = Franc(5)
        assertEquals(Franc(10), five.times(2))
        assertEquals(Franc(15), five.times(3))
    }
}
dataclass Franc(privateval amount: Int) {

    fun times(multiplier: Int) = Franc(amount * multiplier)
}

さて、これまでは殆どの場合テストを書くところからコードをリファクタリングするところまでをセットに進めてきたが、この点に関してはこれから第11章にかけてのより大きな流れでリファクタリングをしていくことになるので、とにかく先に進もう。

犯した罪を追加した現時点での TODO リスト:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値性比較
  • [x] 5CHF * 2 = 10CHF
  • [ ] DollarFrancの重複
  • [ ] equalsの一般化
  • [ ] timesの一般化

第6章 テスト不足に気づいたら

この章では前章で作ってしまった重複を消していくために、まず共通の親クラスを作りそれを継承して equals()の一般化を行う、という進め方をする。
ところで私は Dollar, Francとも data class として実装したので、equals()を自分で実装しておらず共通化するものがないのだった。

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値性比較
  • [x] 5CHF * 2 = 10CHF
  • [ ] DollarFrancの重複
  • [x] equalsの一般化
  • [ ] timesの一般化

とはいえ後のことも考えて、書籍の内容に則り Moneyクラスを作成し DollarFrancに継承させ、ついでに本章で追加される assertion も足しておく。

// Dollar.ktdataclass Dollar(amount: Int) : Money(amount) {

    fun times(multiplier: Int) = Dollar(amount * multiplier)
}

// Franc.ktdataclass Franc(amount: Int) : Money(amount) {

    fun times(multiplier: Int) = Franc(amount * multiplier)
}

// Money.ktopenclass Money(privateval amount: Int)

Kotlin のクラスはデフォルトで finalなので継承できるようにするためには openを足しておく必要があることに注意。

ところで実際に写経をやっていた時は書籍と Elm 版記事の両方を開きながら進めていて、この章に取り組んでいた時に Elm 版の同じ章のところを見返してあー Union Type いいよなーパターンマッチいいよなー使いたいなーってなって探したら sealed classというのがあってそのものズバリな感じの使用感だったのでそれを使った。これによって times()の宣言自体は Moneyの中で行えるため、 Elm 版と同じく共通化を一歩先に進められるようになる。

// Money.ktpackage money

dataclass Dollar(privateval amount: Int) : Money(amount)
dataclass Franc(privateval amount: Int) : Money(amount)

sealedclass Money(privateval amount: Int) {

    fun times(multiplier: Int) = when (this) {
        is Dollar -> Dollar(amount * multiplier)
        is Franc -> Franc(amount * multiplier)
    }
}

Sealed class の主な特徴は以下の通り:

  1. 宣言されたファイルの中でしか sealed class を継承することができない
  2. Constructor がデフォルトで private で、private でない constructor を持つことができない
  3. when式と合わせて Union Type っぽくパターンマッチすることができる
    • when式で検査対象に sealed class を渡して is <class>で分岐させると、その sealed class を継承したクラスだけ並べれば網羅されたことになり、 elseを書く必要がない

上のコードでは times()は 3. によって関数内で when式を用いて自身をパターンマッチにかけ、マッチしたクラスに計算を適用したものを返すように書くことで1つの式にまとめ上げることができ、 Moneyの関数として持ち上げることに成功している。パターンマッチのケースも Moneyを継承した DollarFrancだけでよい。このような方針で2017年現在の*1Javaでやろうとすると times()メソッド内では instanceofを用いた分岐フローが積み重なる嫌なコードになってしまうのでそんなアプローチを採用するわけにはいかず、まだ Moneyに持ってくることはできない。
また、上記以外にも 2. によって Moneyクラスを直接インスタンス化して使用することを防いでおり、ユーザが不用意な使用をできないようにもなった。これはこの一連の記事の最後で小話に使うかもしれない。

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値性比較
  • [x] 5CHF * 2 = 10CHF
  • [ ] DollarFrancの重複
  • [x] equalsの一般化
  • [ ] timesの一般化 -> WIP

第7章 疑念をテストに翻訳する

DollarFrancを比較するという内容。ここも data class としてそれぞれを実装したため異なるクラスで比較しても失敗するようになっている。
ところでここでテストを追加する時、 Dollar(5) == Franc(5)と記述すると以下のメッセージと共にコンパイルエラーが発生することに気がつく。

Operator '==' cannot be applied to 'Dollar' and 'Franc'

これを Dollar(5).equals(Franc(5))とするとコンパイルが通るし結果も本章で期待するものになる。==は前回書いたように a?.equals(b) ?: (b === null)の糖衣構文のようなものだがどうやら完全に同じ挙動をするわけではなく、直系の親子クラスでないとコンパイルレベルで受け付けてくれないようだ。気持ち悪いけど今回はここだけ as Moneyをつけるなり equals()を使うなりしておくことにする。

ここまでのまとめ

現在のコードの様子:

MoneyTest.kt

class MoneyTest {

    @Testfun testMultiplication() {
        val five = Dollar(5)
        assertEquals(Dollar(10), five.times(2))
        assertEquals(Dollar(15), five.times(3))
    }

    @Testfun testEquality() {
        assertTrue(Dollar(5) == Dollar(5))
        assertFalse(Dollar(5) == Dollar(6))

        assertTrue(Franc(5) == Franc(5))
        assertFalse(Franc(5) == Franc(6))

        assertFalse(Dollar(5).equals(Franc(5)))
    }

    @Testfun testFrancMultiplication() {
        val five = Franc(5)
        assertEquals(Franc(10), five.times(2))
        assertEquals(Franc(15), five.times(3))
    }
}

Money.kt

package money

dataclass Dollar(privateval amount: Int) : Money(amount)
dataclass Franc(privateval amount: Int) : Money(amount)

sealedclass Money(privateval amount: Int) {

    fun times(multiplier: Int) = when (this) {
        is Dollar -> Dollar(amount * multiplier)
        is Franc -> Franc(amount * multiplier)
    }
}

TODO リスト:

  • [ ] $5 + 10CHF = $10 (レートが 2:1 の場合)
  • [x] $5 * 2 = $10
  • [x] amountを private に
  • [x] Dollarの副作用をどうする?
  • [ ] Moneyの丸め処理をどうする?
  • [x] equals()
  • [x] hashCode()
  • [x] nullとの等値性比較
  • [x] 他のオブジェクトとの等値性比較
  • [x] 5CHF * 2 = 10CHF
  • [ ] DollarFrancの重複
  • [x] equalsの一般化
  • [ ] timesの一般化 -> WIP
  • [x] FrancDollarを比較する
  • [ ] 通過の概念

今回は通貨のクラスを1つ増やし、それらに共通の親クラスを作って継承させるところまで進めた。第6章では書籍に載ってるコードの構成から離れて sealed class を用いた実装を行ってみた。今回は主な特徴の紹介程度の使い方ではあるが、その便利さから今後も使われることになるので覚えておいてほしい。

*1:Javaもパターンマッチを実装する提案 (http://openjdk.java.net/jeps/305) が上がっていて、早くて 10 から実装されるかもしれない

週末までにやったこと

$
0
0

週の頭に今週これやろうとメモってたことに対する振り返り

TODO に書いてあったこと

Binder transaction buffer のサイズについて再調査 & 記事の加筆修正

やってない 😇
来週末までに終わらせる。

TDD_kotlin: 14章を終わらせる

第I部の終盤だし1章1章が結構かかるかなーという予想に反して分量が少なかったので勢いで進めてたら第I部終わった。

Kotlin で『テスト駆動開発』をやった過程についてブログを書く (1~4章?)

7章まで書いた:

"Reactive Android Programming"の写経レポジトリを作成して chapter 1 まで終わらせる

レポジトリを作ってプロジェクトのセットアップをするところまでは終わらせた。Chapter 1 の内容に対する進捗としては半分。
欲を出してこっちも Kotlin でやろうとして色々調べていたら時間がかかってしまった。

書いてないことでやったこと

Viewing all 97 articles
Browse latest View live