nashcft's blog

時々何か書く。

#builderscon メモ: Antipatterns of Android app development (Track E 13:20~14:20)

builderscon.io

www.slideshare.net

AP 1: 古い本買う

  • 開発環境が古い
  • プラグインのサポートが終了している
  • android: java -> jarをクラスパスに放り込む
    • jarにリソースを入れたい、入らない
    • aarができる (.zipにすると見られる)
androidを知る1: Activity
  • 開発者はactivityを継承したクラスを定義していく
  • OSからいろいろな情報を受け取る: 画面の回転など

AP 2: 画面回転 -> android:configChanges

  • configChanges()は使わない

AP 3: 画面進む -> 戻るでたまに落ちる

  • activityの復元を考えていない
  • onSaveInstanceState()で保存
  • onCreate()で復元
  • onRestoreInstanceState() だとうまくいかない
  • OSが破棄するタイミングがマチマチ
    • 動作確認時は開発者向けオプション「アクティビティを保持しない」を設定する

AP 4: アクセストークン -> static変数に入れる…?

  • サードパーティでもやらかしてるのがある
  • Androidのプロセス: プロセスでJava (Dalvik) VM が起動する
  • 1 app: 1 proc
  • activityはいろんなappで起動、static変数はプロセス単位で持つ
  • 別アプリから呼ばれなくても…?
  • static変数: プロセス止まると消える
    • プロセスはいきなり止まる: activityの中断中 (backgroundにいる時) 止められることがある
      • PC appは最小化してもプロセスは死なない
      • でもちゃんと再開できる、がstatic変数は揮発
  • 永続化or状態をactivityに持たせる
  • 動作確認?
    • 開発者オプション「バックグラウンドプロセスを使用しない」

AP 5: UIをfragmentで -> 2つある -> android.app.Fragmentを使う

  • Fragment?
    • viewの生成と管理
    • activityはUIを提供するがOSとのやりとりがあったりして大変
      • activityに全部やらせると破綻する
      • 3.0からFragmentがviewの生成と管理をactivityから引き剥がした
    • android.app.Fragment
      • プラットフォームで提供
      • OSバージョンに縛られる
    • android.support.v4.app.Fragment
      • サポートライブラリで提供
      • v4: api Lvのこと (ただしLv14?)
      • 更新すれば新しい機能が使える
  • サポートライブラリ版を使いましょう

AP 6: 呼び出し元に処理結果を伝える実装をfragmentで

  • fragment処理をinterface経由?で渡す
  • NextFragment表示中に中断すると->callbackオブジェクトは復元できない
    • bundleに放り込めるのはprimitiveと放り込める条件を満たすオブジェクト
  • setTargetFragment()でfragment間の値を渡せる
  • getTargetFragment()で呼び出し元を取得
    • Fragment::onActivityResultを使ってなんたら

AP 7: iOS appのAndroid版つくる依頼 -> 見た目、操作感をiOSそのまんまにする

  • 下タブが悪いとは言えない
  • トップレベル項目が2つなら下タブ以外の表現で
  • 横スクロールしないのに > マーク
  • まずmaterial designに従ってデザインしよう
  • アンチパターンがいっぱい -> 知ってれば回避できる -> 勉強しましょう

Neo4jユーザ勉強会#11 に参加してきた

“Living Clojure” の読書メモが積み上がってる状態で書くのもどうなのというのはあるけど参加してきたので書く。殆ど読み終わってるけど日常的にブログを書くというかアウトプットする習慣が全くついてないよね…

jp-neo4j-usersgroup.connpass.com

ところで第1回以来の参加です。

お知らせ

タイムテーブルなどの説明。

Neo4j を MS Azure 上で動かす (workshop)

事前にAzureのセットアップをしてきて、この時間にNeo4jをインストールしてbuiltinのGUIで遊ぶということをした。
実際このGUIで遊ぶというのはNeo4jのサイト上のsandboxで触れるようなことをわざわざAzureに突っ込むという手間をかけた上で行うというもので特にAzureが絡んでくることの意義が見出せず、MSの協力があったためにどうにかしてMSと関連づけようとした苦しい何かを感じるものだった。

Graph Connect 2017 Europeの参加報告

登壇者の方がGraph Connect 2017 Europeに参加してきたということで、そのカンファレンスとkeynoteの紹介という内容。Graph Connectの発表資料は全部サイト上で録画を視聴できるし、スライドもslideshareに上がっているということでありがたいということがわかった。
keynoteは、まあ国際カンファレンスのkeynoteを駆け足とはいえ20分で読んだり説明したりしながら紹介しきれるわけがないよね、ということで半分いかないくらいで打ち切り。keynote自体はあとで全部読んでおく。紹介されていた範囲は直近の大きな事例紹介みたいな内容で、最近はknowledge graphがアツいとか何とかだった気がする。eBayが購買アシスタントのbotの裏側をNeo4jでやってて、ユーザへの質問の回答をパラメータとしてクエリを作って商品のレコメンドをしてる、とかそんな。

openCypher Meetup in Londonの参加報告

Neo4jのクエリ言語だったcypherがいつの間にか独立していて*1openCypherというプロジェクトになっていた。それで定期的? にmeetingを開いて課題をこなしたり議論したりしているらしい。報告にあったLondonでの会は2回目の開催だそうで、次は秋頃にNewYorkで行われるそう。
openCypherとして独立したことで汎用的なグラフ探索クエリ言語として様々なプロダクトに実装されるようになっており、プロジェクトのページで紹介されている。
帰宅してから適当に検索したら当日の流れが公開されているのを見つけた。Prologで実装とか強い事が書かれている。
あとこれか一個前の発表の中でジェンダー的にアレな発言があって渋い顔になった。

LT

上記の報告発表の後で軽食とビールが振舞われて、それを食べたり飲んだりしながらLTを聞いた。MSの予算的なアレで潤沢な食事とビールが提供され、ビールは1人あたり500ml瓶2.5本分あるよとのことでMS様様という感じだったが私は普段アルコールの類を飲まないので1本で限界だった。

グラフ可視化ライブラリまとめ

D3.js, GraphViz, Cytospace, Linkurious (sigma.js), Keylinesの出力を比較した感じ。
Cytospaceが使いやすさと出力の見た目的にオススメだそう。後↓のスライドいいよとのこと。

www.slideshare.net

Neo4jのStored ProcedureとFunctionの紹介

タイトル見たときに何だと… となったけど、Javaで処理を書いたものをjarとしてNEO4J_HOME/plugin/に置いておくとcypherからCALL foo()という感じで呼べるよということだった。実装は去年から入ったとのこと。Documentも見つけたのでこの土日で読む。
Procedureやfunctionは以下の3つに大別されるとのこと:

  • Neo4j builtin
  • APOC (Awesome Procedures On Cypher)
  • User defined

APOCはthird partyの実装で2009年から存在していたのだが2016年にNeo4jがprocedureを導入するまでずっと日の目を見なかったとかそんな道のりを歩んできたというエピソードが面白かった。これには全部で320以上のprocedureやfunction実装されており、一部はbuildinと被るものもあるが大体はこれの中から使いたいものが見つかるレベルだそうな。

居酒屋

元居酒屋店長で今はkusanagiエヴァンジェリストをやっているという人のグラフデータモデルいいですねというお話だった。気がする。この頃には酔いが回ってきててちゃんと内容覚えられなくなってきてた。

日本OSS推進フォーラムの紹介

正式会員と政府からもらったお金で夜にメイド喫茶で飲み会をする組織という理解をした。政府からお金は出てないかもしれない。中韓と合同の会議? への渡航費諸々は自腹って言ってたから飲み会も自腹かもしれない。

全体的な感想

第1回の勉強会に参加した時にも書いたけどベンダのご紹介感の強いというか、それ使って開発してるとかそういう雰囲気のある発表はprocedureとfunctionの話くらいだったしもっと何とかなんねーのという感じもある。グラフデータベースとかNeo4jとか学びたいという人が参加しても大した収穫は得られないし各自やっていくとかtwitterでワイワイやるとかの方がずっと学びを得られると思った。

*1:Neo4j 2.2 くらいから追ってなくて、その頃cypherはまだ「Neo4jのクエリ言語」だった

Living Clojure 読書メモ

Clojure入門のために “Living Clojure” を読んでいる。
読みっ放しにするのも何なので、適当なところでメモをまとめて記録しておくことにした。

Preface

Chapter 1. The Structure of Clojure

Simple Values

  • Decimal以外にRatioによる表現がある
;; decimal
3.14

;; ratio
1/3

Collections

;; List: 
'(1 2 3)
;; Vector: 
[1 2 3]
;; Map:
{:key1 "value1", :key2 "value2"}
;; Set: 
#{:foo :bar}
  • Listの区切りはコンマではなく空白
    • コンマも無視されて空白として解釈されるので使用はできる
  • consはList以外に使うとListにキャストされるっぽい ((cons 1 [])の返却値が(1)だった)
  • nthlastといったCollectionの先頭以外の要素を取得する関数はListとVectorの両方に使えるが先頭からのtraversalが必要なListよりもindexでアクセスできるVectorの方がパフォーマンスが良い
    • indexによる要素へのアクセスが必要な場合はVectorを使う
  • 全てのCollectionはimmutableでpersistent
    • persistent? -> “… these collections will do smart creation of new version of themselves by using structural sharing.”
  • conjはデータ構造によって要素を追加する場所が異なる
    • Listなら先頭、Vectorなら末尾
  • Mapでvalueを取得するときはgetを使う方法とkeyを関数として扱う方法がある
    • keyを関数とする方法がよりClojure的だが場所によってgetを使うこともある (明示のため)
  • Setに対する集合操作 (union, intersection, difference) を呼ぶ際は clojure.set/unionというように記述する

Binding

  • 変数に値をバインドする的な方法は (def foo "value")
    • 厳密にはいわゆる変数とは違うけどそれについてはChapter 3で
    • global variable的な立ち位置っぽい
  • letだとletの中だけアクセスできる
(def foo "foo")
foo
;; -> "foo"

(let [foo "foo2"
      bar "bar"]
    [foo bar])
;; -> ["foo2" "bar"]

foo
;; -> "foo"
bar
;; -> CompilerException java.lang.RuntimeException: Unable to resolve symbol: bar in this context...

Functions

  • Anonymous functionのfnがあって
(fn [<params>] <body>)
  • defn(def some-fn (fn [<params>] <body>))の略
(defn some-fn [<params>] <body>)
  • Anonymous functionは省略っぽい記述がある
    • #(<body including params>)
    • パラメータは% (複数ある際は%の後に数字をつける) で表す
;; Textの例
(#(str "Off we go" "!" " - " %1 %2) "again" "?")

Namespace

  • (ns foo.bar)で作成(と切り替え、はREPLのみ?)
  • *ns*がnamespaceを返す
  • require
    • 引数にnamespaceだけ: (require 'clojure.set)
      • Fully qualified namespaceでアクセスできる e.g. clojure.set/union
    • as: (require '[foo.bar :as fb])
      • (fb/some-fn) とかそんな
    • refer all: (require '[foo.bar :refer :all])
      • 呼び出したnamespaceに対象のnamespace内のすべてのsymbolをロードしてsymbolだけでアクセスできる
      • symbolの衝突とか由来が分かりにくかったりするのでやたらと使わない方が良い
  • userequire:refer :allしたのと同じ、だけどrequire:refer :allで書いた方が良いっぽい

Chapter 2. Flow and Functional Transformations

  • 用語 (本書を読むにあたって十分なレベルで)
    • expression: 評価されて結果が得られるコード
    • form: 評価してエラーが返ってこないexpression

Logic Tests and Flow Control

  • =はequalityを検査している
  • Equality of Collections
(= #{:a :b} #{:a :b})
;; => true
(= #{:a :b} [:a :b])
;; => false
(= #{:a :b} '(:a :b))
;; => false
(= '(:a :b) [:a :b])
;; => true
  • empty?seq

※追記 (2017/02/26) ※

Twitterで各collectionはSeqableを継承したIPersistentCollectionを実装しているという指摘をいただいて、Clojureソースコードを読み直してみると確かにそうだった。継承や実装をちゃんと見ていなかった。
しかしそれでも何か腑に落ちないものがあり、もう一度よく読み直してみたらそもそも自分が勘違いをしていたことがわかった。
つまり、最初私は各collectionが共通のinterfaceか何かを持っていて、「それの振る舞いとして」seq関数が実装されており、それを介してsequenceを得ることができると考えていた。
だが実際はseq関数 (の実装) とcollection及びそれらが持つ共通の抽象構造は分かれていて、seqcore.cljで定義された、これを通してcollectionをsequenceに変換する、構造とは独立した関数 (実際に処理が実装されているのはRT.java?) で、各collectionは単に遡っていくとSeqableを実装している構造体で、そのためにseqを通してsequenceにすることができる (RT.seqを見ると厳密にはこの説明は正しくないのだけど、簡単のため)、ということのようだ。

というかきちんとサンプルコード見れば(seq coll)となっているのだからseq関数自体は構造から独立してるのわかるじゃん…

※追記終わり※

  • someの返却値
    • 第二引数のcollectionの各要素に対してpredicateが最初に返すlogically trueな値
    • nil (predicateを満たす値がなかった場合)
  • someの第一引数 (predicate) にSetを使うこともある
    • logically falseな値をSetに入れると破綻する
  • condcase
    • マッチするものがない場合、condnilを、caseIllegalArgumentExceptionを返す
    • caseはdefaultを設定できる (リストの要素が奇数の場合最後のexpressionがdefaultとして評価される)

Functions Creating Functions ~

  • partial
    • curryingじゃなくてただの部分適用の話…?
  • 関数合成はcomp

Destructuring

  • :asで元々の構造を保持できる
  • :orでデフォルト値を設定できる
  • [{:keys [param1 param2]}]という形での指定が一般的

Recursion

  • looprecur
    • loopを用いると初期値の隠蔽ができる
    • recur再帰呼び出しに使われる (loopを使ってるとloopの開始地点から再帰処理を開始?)
  • recurはstackを積まないようにしてくれる
    • なんか条件がありそう (末尾再帰のみとか)

The Functional Shape of ~

  • mapreduce
  • 副作用が発生するタイミング
    • doall
  • mapには複数のcollectionを渡すことができる
    • それぞれの同じindexの要素を用いて関数を実行する
    • 素数が少ない方に合わせる
  • complement: 関数を引数にとり、反対の論理値を返す関数を返す
;; Vectorから`nil`を取り除く: 
(filter (complement nil?) [:a nil :b :c nil :d])
;; => (:a :b :c)
;; 以下も同じ挙動
(remove nil? [:a nil :b :c nil :d])
  • for
    • 複数のcollectionを与えるとネストする
    • :letによってfor内のlet bindingができる
    • :when <condition>を与えると条件を満たす時のみ評価が実行される
  • flatten
  • into
  • partition
    • partition-all
    • partition-by

JJUG CCC 2016 Fall memo

 最後の枠のセッションしかメモ取ってなかったのでそれだけ

Featherweight Java の漸進的型付けと Groovy の紹介

by kyon_mm

単語の整理

  • Featherweight Java
    • Java言語のコアとなりそうな部分を抜き出して形式化したもの (型付け規則、操作的意味論)
    • merit: 机上で言語拡張の実験をしやすくなる
    • Generics非対応
      • 対応したFeatherweight Generic Java (FGJ)
      • OderskyによるGenericsの貢献 -> Scala
  • 漸進的型付け
    • 静的型付き、動的型付きのいいところを両立させるための仕組み
    • プログラマがそれぞれを行う箇所を選択できる
    • 書きながら動的な部分を徐々に静的に移行させられる
  • Groovy

論文の概要

  • 漸進的型付けを導入したFJをFJ?(FJ^?)と定義
  • FJ? -> FJrefl(リフレクションを加えた体系)
  • ?型: wildcard
    • 動的に検査される
  • 実行時の?型: リフレクションを用いる、コンパイルが通っても実行時エラーになることもある

Groovy

  • 漸進的型付け
    • 基本的に動的型検査、コンストラクタにannotationをつけて静的型検査を指定する
    • FJ?における?型はGroovyでは変数
    • FJ?: ?型のオブジェクトに大してFJreflでなんちゃら
    • GroovyではMOP (Meta Object Protocol)の仕組みを持ってる
  • @CompileStatic, @TypeCheck
    • @TypeChekは静的型検査するだけ
    • @CompileStaticは動的型検査が行われないようにする (ドキュメントなどでは "bypassing Groovy meta object protocol" などと書かれている)

場所は伏す

『市ヶ谷Geek★Night「型のあるフロントエンドの世界〜フロントエンド・フロンティア〜」』メモ #ichigayageek

ichigayageek.connpass.com

Togetterまとめ (ダブっているが完全に重複している訳ではないので両方載せておく)
togetter.com

togetter.com

感想

5月に転職してサーバサイド開発ばかりやるようになってから*1フロントエンド事情にだいぶ疎くなっていたので、GraphQLの事とかElmがバージョン上がる度に言語仕様が小さくなっている事とかは全然知らなかったし、静的型付き言語を含むスタックやFlowTypeを実際に使ってみての知見が結構蓄積されつつあるんだなあということを知ることができて大きな収穫を得られたと感じた。Elmはもう一度学び始めてみようかと考えている。

懇親会でGraphQLの話をしているのを聞いていたが、そこで聞いた感じGraphQLはクライアント側でリクエストを送る際の形式の一つで、データソース側は特に指定されていないという認識をしている。DB側がMySQLだったりMongoDBだったりとそこは関係がないらしい。この辺はもう少し調べて確かな知識をつける必要がある。

あとクライアント側でグラフ的な柔軟なクエリを作成できるが、その分サーバ側では簡単に許容外なレベルの負荷になってしまいがちで、規模が大きなサービスで使うなら、金にものを言わせてマッチョなサーバを用意するか、サーバ間でのリクエストなどある程度クエリをコントロールできる形で使用するかという感じらしい。結局クライアントがデータの関係性についてのクエリを自由に作れるようになったからといって、DB側はそれが不得意なままだし、という事か。DBがグラフデータモデルだと相性はいいのだろうか。ちょっと興味が出てきた。


以下メモ

*1:実際のところ開発すら稀にしかやらなくなってきているのだけど

Read more

『再演 ~ 組織にテストを書く文化を根付かせる戦略と戦術 +α』メモ #t_wada

また過去に参加した勉強会のメモ。今回のは3/11ともはや半年以上前...
まあもう諦めても良かったのだけど、9月頭 (これも1ヶ月近く前...) にあったprivate methodの件だったり職場で最近あったお話だったりがこの講演で扱われた話題に関連している気がするなあと感じたので、折角だしと思って掘り出してまとめることにした。

connpass.com

togetter.com

www.slideshare.net

転送サーバおけるテストの自動化 · GitHub

メモは最後に貼るとして、講演の内容の内2点について、この記事を書いている時点までにあったことも含めて思っていることをまとめる。これらを書いていて、半年以上前の講演で、それもスライドに残されていることではなくその場で話されていたようなことやそれについてその時感じたことなのに、今でもこうやって覚えていてそれなりな量の文章を書けるのは、自分にとってこの講演がそれほど感銘を受けるもので、その後の自分の考えや行動の指針となっているのだなあとしみじみ思ったのであった。

リファクタリングとビジネス価値、日々の開発の関係

スライドにおける「リファクタリングのジレンマ」の部分。スライドにはこれだけしか書かれていないがこの会ではここを掘り下げた話があった。

リファクタリングを独立タスクにすると、そのタスクは着手されない

どういうことかというと、リファクタリングそれ自体はプロダクトに新たにビジネス価値を付与するものではなく、振る舞いを変えることなく内部を改善する「だけ」なので、「〇〇のリファクタリングを行う」とタスクとして独立してしまうと、他の新機能開発や機能追加・改修といったタスクに対して短期的な視点からエンジニアの自己満足とみなされたり早く顧客に新たな価値を提供したいというビジネス判断をされたりして後回しにされ続けてしまい、ついぞ着手されることなくTODOリストの奥底に沈み込んでしまう、ということだそうだ。
ではリファクタリングのビジネス的価値とは何かというと、中長期的に見て同様のタスクをこなすのにかかる時間を一定以内に保ち続けられるようにすることであるとのことで、つまりビジネスの進行に対するブレーキをプロダクト内に作らないようにすることと言える。

リファクタリングされないまま開発を進めてしまった場合どういうところに行き着くのか、というのは、最近だと以下の記事の「コードの乱れが生むもの」がイメージしやすく書かれていると感じた。

d.hatena.ne.jp

この記事によれば、行き着く先とは最早リファクタリングどころではなくなってまた一から同じシステムを作り直すという、開発にもビジネスにも多大なコストを支払わざるを得ない状況となる。計画された再構築でなければ実施しようとする頃にはそれをするにも心許ない、最悪実施すらできないような状況に陥ってしまっているというのは恐ろしい話である。

短期的には後回しにされがちだが、かと言ってしないままだとその内まずいことになるのでやらねばならないリファクタリングを、じゃあどうやって実施したらいいのかと言うと、日々の開発タスクの中に小さなリファクタリングをまぶして、日々の業務に改善を組み込んでいきましょう、とのことだった。

これは言われてみればなるほどその通りで、規模の小さい内に問題を潰せることができればその後起こりうる大きな問題 (大規模なリファクタリング) を未然に防げるだろうし*1、結局開発もリファクタリングもソフトウェアエンジニアとしてはどちらもコーディングタスクと見做すことができるので、あえて別タスクに分離して実施しなくても一緒にやってしまえばいいよな、と思う。
とは言うものの中々実行はされないもので、今の職場では割とカジュアルにリファクタリングを独立タスクにしていく傾向があり、見かねて一度「そういうのは良くないよ、こういう風に日々の開発タスクの中で少しずつリファクタリングしていきましょう」ということをプルリクエストで実例を紹介しつつ訴えかけたことがあった。その時はあまり注目されてないなーと思ったのだけど、2, 3人ほどそれ以降実践してくれているのを観測したので、文化を作るきっかけにはなったのかなと考えている。

この講演でも話されていたことなのだけど、本当は上記のように大勢に呼びかけるような方法というのは戦術的には筋が良くなくて、一人ずつ伝授していくようにできる人を増やしていくという方法が紹介されていた。確かに、考え方や実践のためのスキルなど習得すべきことの性質や量を考えると個別にみっちり指導していく方がよく定着するだろうなと思う。とはいえ現実問題としてはそんな気長に構えていられないような状況もあるだろうし、まだ小さくリファクタリングする習慣を会得していない人のタスクに対してもどうにか改善を適用したいという思いがないこともない。
これに関してはプルリクエストによるコードレビューを行うとそれなりにカバーできるのかなあと考えている。講演でも戦術としてコードレビューが挙げられていて、人に見られるコードを書いているという意識を植え付けることで、コードの品質を向上させられるというような話があった。そのためには、単に実施するだけではダメで、レビュイーに自分の書いたコードやどのような変更を行ったかが見られ、その内容が評価*2されるということを認識させるように、レビュアーはきちんと見なければならないし、見ているという姿を表さないといけないが。

それで、どうやってコードレビューで日々の改善をカバーしていくかと言うと、レビューの際に改善ポイントをがあったら、普段からこういうのを見つけたらこういう風に直していきましょうねー、というのを指摘・解説しつつ、改善を適用して (してもらって) からmergeするようにする感じ。はじめの内はレビュアーのコストがかかるのは仕方ない。いわゆる投資というものである。人によってはこれでレビュアーが見つけてくれるからと完全に甘えてしまって改善を行わない人も出てくるかも知れないが、そうしたら素直に張っ倒して (比喩表現)、自らやるように導いていくなりする必要がある。
これも全体に〜という話だとレビューするプルリクエストの量が多くなって大変になってしまうが、改善活動を日々の開発に取り入れるならば、それの啓蒙や教育も日々の活動の中にまぶしていくのが良いのではなかろうか。

「設計の可動域を確保した」テストについて

前半の方で品質を上げるのはテストではなく設計とプログラミングという話があって、品質改善のために再設計を、それによって実装の変更を行うとして、その際にテストが実装に寄り添ったもの (= 実装をテストしているテスト) になっていると、これらの活動の足を引っ張るようになってしまう。なので、設計や実装の変更を後押しするような、実装と距離を持ったカバー範囲に遊びのあるようなものにして、カバー範囲内で変更を行う分には落ちないようなテストを作りましょう、という話だった。

それから時間が経って9月になって、private methodのテストと設計についての話が以下の記事を発端として話題になった。

su-kun1899.hatenablog.com

private methodにまつわる設計の是非は置いておくとして、この記事に対してt_wadaさんが紹介したQ&A記事において、質問者がprivate methodも実装した瞬間に実装のテストがしたいという発想のもとテストを書いてしまいたいな、と述べており、それに対してt_wadaさんは「プライベートなメソッドのテストを書く必要は 無い と考えています」と先に結論した上で、以下のように説明している。

繰り返すと、プライベートなメソッドや関数をテストする必要は無いと考えています。プライベートなメソッドは、実装の詳細であるからです。 (中略) プライベートメソッドに対するテストは内部の実装に対するテストになってしまうことが多く、そして内部の実装に対するテストはリファクタリングの妨げになりがちです。自動テストの助けを借りて積極的にリファクタリングを行いたいのに、その自動テストがリファクタリングの妨げになる。これはとても皮肉な状況です。避けられれば避けたいものです。
テスト「できる」ことと「するべきである」ことは異なります。リフレクションを使えばプライベートなメソッドのテストは「できる」のですが、そのテストはやがて実装改善の邪魔になりかねません。

Q&Aの記事がちょうどこの講演 (再演) の3年前くらいで、その頃からリファクタリングを後押しするための実装に対して距離を保ったテストという考えがあって今日まで一貫してきてるんだなあという感動があったのはさておき、実装のテストを書いてしまうと実装を変更するたびにテストも改修しなければならないためリファクタリングのコストを無闇に上げてしまうことや、リファクタリングが振る舞いを変えずに実装を改善することだというところから、リファクタリングによって継続的にコードを改善できるようにするために実装に対して遊びのあるテストを書きましょうということについては私も同意したのだが、「実装のテストを書くべきではない」というのはちょっと違うのでは、という考えを話を聞いた当時に持った。
それについて、講演後に呟いた以下の一連のtweetが上記の話を受けての実装のテストに対する考え方を表している。

まとめると、この講演では書くべきでないとされた「実装のテスト」について、私は実装をしているまさにその時はそれぞれの部品が正常に動くことを確認するための一時的な、目的を達成したら (部品が期待通りに動くことが確認できたら) 捨ててしまう「寿命の短いテスト」としてであれば別に書いても良いと思っていて、実装後も再設計やリファクタリングできるように残すテストは設計・実装に関してカバー範囲に遊びのある「寿命の長いテスト」にする、というように使い分ければ良いのではということである。

ここでいう「寿命の短いテスト」= 「実装のテスト」は役割的には補助輪のようなものだし、書くべきではないというより書かなくてよい、言い方としては「後に残すべきではない」の方が適切かな? というのが私の意見となる。

まあ時間軸の視点を持ったところで、結局「寿命の短いテスト」は書かずに済むに越したことはないし、「寿命の長いテスト」だけ書きながら書き上げられるようなプログラムがいわゆる良い設計のプログラムと言えるのかも知れない。


以下当日のメモ (当日若干遅刻したので途中から)

*1:根本的な設計そのものみたいな問題はこの方法では対処できなさそう...?

*2:コードの評価であって、人事評価ではない。念のため

Read more