インターフェースで副作用を分離する

techlife.cookpad.com

この記事、わざわざgemを作ったりしていて、まあそのgem自体は便利そうだからいいと思うんですが、時刻以外の場合はどういうアプローチをしてるんでしょうか。そのたびにgemを作るんでしょうか。 そんなに悩まなくとも、オブジェクト指向の引き出しがあれば一瞬で片付く問題です。

package com.example

import java.time.LocalDateTime

// Clockインターフェース
trait Clock {
  def now(): LocalDateTime
}

// デフォルトのClock実装
trait DefaultClock extends Clock {
  def now(): LocalDateTime = LocalDateTime.now()
}

// 時刻を取得する時にはClockインターフェースを通して取得する
class SpecialContent(clock: Clock) {
  def enabled: Boolean = clock.now()
    .isAfter(LocalDateTime.of(2016, 7, 1, 0, 0, 0))
}
package com.example

import java.time.LocalDateTime

import org.scalatest.FunSuite

// 固定された時間を返すClockインターフェースの実装
class FixedClock(fixedDateTime: LocalDateTime) extends Clock {
  override def now(): LocalDateTime = fixedDateTime
}

class SpecialContentTest extends FunSuite {

  test("disabled at 2016-06-30 23:59:59") {
    val content = new SpecialContent(
      new FixedClock(LocalDateTime.of(2016, 6, 30, 23, 59, 59)))
    assert(!content.enabled)
  }

  test("enabled at 2016-07-01 00:00:01") {
    val content = new SpecialContent(
      new FixedClock(LocalDateTime.of(2016, 7, 1, 0, 0, 1))))
    assert(content.enabled)
  }

}

java.time.Clock というものが存在するので自分でClockを定義する必要はないんですが、そういうのがあるないの問題じゃないので。

Java/Scalaの世界とLLな世界を行ったり来たりして文化の違いに戸惑ったことがあるのですが、 こういう外部入力とかが絡んだ場合、Java/ScalaおじさんはOOPっぽくインターフェースを使って分離したりしようとするのに対して、 LLの世界だとクックパッドの記事中にも触れられているようにtimecopみたいにメソッドごと置き換えてしまうとか、個別のアプローチを取ることが多かったです。 オブジェクト指向は無駄だと主張する人が多いんですよねえ。

またScalaな世界でもOOPではなくモナドがどうという話になることがあります。 確かに参照透過であることは良いんですが別にファンクショナルなアプローチに頼らなくてもテストは書けるし、参照透過でもテストが辛いこともあるのでまあみんな仲良くしましょう。

Python/Flask と Backbone.js で Markdown エディタを作った

Atom はまだいまいちだし、Sublime Text は使ってると金を要求してくるし、emacs はそろそろ引退かな。Markdown 書くのに Mou とかは便利だけど、長い文章を書いてるとだんだんもっさりしてくる。と、普段使いのテキストエディタをどれにすればいいかここのところずっと考えている。

それとは別に、保存したテキストファイルたちをどう管理すればいいかもよく考える。ファイル名を考えるのがめんどくさい。どこに保存したのか忘れる。ファイルツリーをたどるのがめんどくさい。⌘+s を押すのすらめんどくさい。正直エディタのほうでなんとかしてほしい。

Evernote とか便利だけど、勝手にフォーマットされて困る。コードとか貼付けられない。

というわけで少し前に自分用の Markdown エディタを作った。

tototoshi/gfm-editor

左側にエディタ、右側にリアルタイムプレビューが表示される。Markdown エディタとしてはよくある UI。左上にあるプルダウンでメモを選択することができる。メモはサーバーのポスグレに保存される。保存は左側のエディタに書き込みをした時点で自動で行われる。保存ボタンはない。

簡単な Web アプリだけど自分の用途としては必要十分な感じ。 UI のほうは Backbone.js で APIPython/Flask で作った。Python にしたのは Pygments が使いたかっただけ。

Pygments は py-gfm というライブラリと一緒に使うことで Github Flavored Markdown も扱えるようになる。それについては、「Python で Github Flavored Markdown をレンダリングする」 で書いた。

Backbone.js については使うのほぼ初めてで苦戦したけれど、慣れると確かにきれいに書けるなってことで気に入った。Angular よりいいんじゃないかな。(Angular 使ったことない人のご意見です)

あと _.debounce を覚えたので使った。(こういうの毎回自分で実装してた...) javascriptで発生するイベントを間引く - 終わる世界とコンテンツ

Fluid でネイティブアプリ化する

Web アプリとして作ったのでアクセスするには当然 Web ブラウザでアクセスするんだけど、ネイティブアプリにしたほうがよくわからないけどなんかかっこいい気がする。

node-webkit とか試してみたりもしたけど、モチベーションに対して頑張り過ぎな気もしたのでやめた。

そうこうしてたら Fluid という Web アプリをネイティブアプリっぽくみせかけるアプリを見つけたのでこれで適当にネイティブアプリ化した(ことにした)。

http://fluidapp.com/

先のスクリーンショットは Fluid を作ったので Web アプリなのにネイティブアプリっぽい見た目になっている。あと、アプリケーションのアイコンも設定できるようになる。iconfinder でフリー素材落としてきてつかった。

これでだいたい目的は達成できた。めでたしめでたし。