ductとataraxyでふつうのWebサイトを作る

「ふつう」には全く深い意味はなくて、ただただHTMLをGETできてPOSTリクエストを受け付けられるふつうのWebサイトを作ろうとしてみた。 ふつうすぎて逆に情報がなかったのでまとめてみる。

バージョン情報

  • duct: 0.6.1

前提知識

やったこと

とりあえずプロジェクト生成する

lein new duct sample +site +example

DBは置いておく。作者が書いたAPIサーバーを作れるブログエントリがあるのでそれを見れば触れるようになると思う。ここで出てくるboundaryという概念もクールだなーと思ったけどそれはまたいつか。

とりあえずエディターからREPLにつなぐ

おもむろにEmacsを立ち上げてcider-jackinする。

動かしてみる

この時点で localhost:3000/example にアクセスするとサンプルページが出る。

formを書く

[hiccup "1.0.5"] を依存に追加して以下のようなコードを書いてみる

[::response/ok
 (html [:h1 "hello"]
       (form-to [:post "/example"]
                [:p (label {} "username" "username")
                 (text-field {:placeholder "username"} "username")]
                [:p (label {} "email" "email")
                 (email-field {:placeholder "foo@example.com"} "email")]
                [:p (label {} "password" "password")
                 (password-field {:placeholder "your password"} "password")]
                (anti-forgery-field)
                [:p (submit-button {} "submit")]))]

すると localhost:3000/example で

f:id:blackawa:20171201154449p:plain

みたいな画面が見える。

POSTする

ルーティングをいじる。

:duct.module/ataraxy
 {"/example"
  {[:get] [:example/new]
   [:post {user :params}] [:example/create user]}}

 :sample.handler.example/new {}
 :sample.handler.example/create {}

で、関数のnamespaceとかも書き換える。

(defmethod ig/init-key ::new [_ options]
  (fn [what-is-this]
    (println what-is-this)
    [::response/ok
     (html ;; 省略
      )]))

(defmethod ig/init-key ::create [_ options]
  (fn [{[_ user] :ataraxy/result}]
    (println user)
    [::response/ok "created"]))

この状態で localhost:3000/example にアクセスしてformを送信すると画面遷移するし、REPLにリクエスト情報が出てくる。 やったぜ。

リクエスト自体をもらいたくなったらどうする?

routing時点でのデスラクチャリングはataraxyの強みだけど、もしもっとガツッとほしくなったら? その時はhandlerの無名関数が受け取る引数を、バラさずにそのまま受け取れば中にリクエスト内容が全部入ってる。

anti-forgeryとかのミドルウェアどこで差し込まれてるの?

github.com

がconfig.ednに差し込まれてて、うまいことデフォルト値を定義してくれているよ。 定義内容が知りたければREPLで

(prep)
(pprint config)

したらわかる。

感想

しばらく前にClojure始めてよかったなーという気持ちしか沸かないくらい過去の資産をうまーく組み合わせて実現されてた。 これだけのエコシステムを数年かけて作ってきたring / ductのコミュニティとそれを牽引したweavejester本当にすごいな。

Spring Fest 2017 Fallに参加してきた

弊社がいいよって言ってくれたので、弊社Springframework率ゼロに等しいのに平日に1日使って仕事としてSpring Fest 2017 Fallに参加してきた。弊社ありがとう。

聞いてきた話を感想や学びと一緒にまとめておく。

NOTE : 間違いのないように気をつけてはいますが、誤解している箇所があればぜひ後学のためにご指摘ください。

普段Javaを触らない各位のために

ちょっとだけ解説すると、SpringframeworkはJava製のアプリケーションフレームワーク。 数年前まではいくつかのフレームワークがあったが、現在は一強になりつつあるように思う。 オブジェクトをDIで組み合わせて巨大なアプリケーションを構築できるのが特徴。

リクルートホールディングスYahoo!Japanなどのメガ企業にはじまり、様々な企業が採用している。私が浅学なだけで山ほど採用企業はある。

基調講演: What's new in Spring?

Pivotalの強い人で、Springframeworkファミリーの様々なプロダクトの開発に関わってきたDave Syer氏による基調講演。 穏やかな話し方をする方だった。イケるやろと思って同時通訳なしでチャレンジしてみたら半分くらいしかわからなかった。

スライドは以下。

What’s New in Spring?

PivotalはSpringframeworkのメンテナ企業。Pivotal Cloud FoundryというクラウドプラットフォームやConcourse CIも開発している。

Springプロダクトのレイヤーについての概要

Springframeworkの各プロダクトは、大きく分けて3階層で構成されている。 生SpringframeworkとSpring Boot、そしてSpring Cloudである。

Spring Bootを使うと生Springframeworkで辛かった設定の管理が簡単になって、Spring Cloudができたことで分散アプリケーションを開発できるようになった。

直近のアップデート内容

2017/11にかなりいろいろアップデートがあった。 Framework自体5.x系に上がったし、Securityも5.0.0.RC1に。Bootは2.0.0に。 Project Reactorというのもあって、WebsocketサポートとかReactiveなアプリケーション開発の基盤を提供している。

Spring 5.0ができること

以下のような変更を行っている。

  • パフォーマンス改善
  • Functional bean configuration(設定をもっと簡単に書ける)
  • ReactiveにWebFluxとRouter Functionsを追加(イベントループ型の処理を可能にする)
  • JUnit5サポート(最新のテストライブラリに対応)
  • JDK9サポート(最新のJavaに対応)
  • HTTP2サポート
  • Kotlinサポート

Project Reactorについて

今までは、IOExceptionを起こしうる操作はtry-catchしなければいけなくて、Imperative(命令的)でBlockingだった。 でもFunctionalスタイルだと、Mono型を返してdoOnErrorでエラー処理できるのでNon-blocking。

Javaではもともと、1つのHTTPリクエストに対して1スレッドを起動するモデルでWebアプリケーションを開発する必要があって、つまり大量のリクエストを一度に受け付けるとスレッドが枯渇してしまう問題があった。 それに対する解決策としてSpring 5.0で提供されたのがFunctional Routerで、これでNode.jsに代表されるイベントループの仕組みをSpringframeworkが実現できるようになる。

Controller層もReactiveに書けるようになった!ControllerからMono型を返せる。 ただしWebFluxを使うと組み込みサーバーがNettyになる。TomcatはNon-blockingをサポートしないので。

新しいAPIクライアント

WebClientを使うと、APIアクセスする時にWebClient.create()してそのまま使える。 書き方はBuilderパターンみたいになっていて、client.get()...とメソッドチェーンをつなげていって、結果Reactiveなオブジェクトを取得できたりする。 テスト用のモックオブジェクトなども用意されていてテスタブル。

ServletとWeb MVCはなくならない。

Cloud

Spring Cloud Function / Spring Cloud Gatewayが2018Q1、SpringBoot2.0.Xに計画されている。 FaaSをSpringで書けたり、API GatewayをSpringで書けたりするようになるらしい。これまた楽しそうなテーマ...!

所感

最近さらに、どの言語でやるかではなく何をするかに集中できるようになってきた気がする。 JavaでもRailsでもそれ以外でも、ノンブロッキングIOが使いたくて使えるならそれでいいし、dev.toみたいに適切にCDNを噛ませれば早くなる。

Functional Routerは書き方の問題じゃないか?なんでフィーチャーされてるんだ?と思ってたので、Dave Syer氏に質問してきた。 いわく、「Function」Routerとはいうけど実際にはFunctionalであることよりもリソースの削減ができるのが良い。これがない時代には、何百ものクライアントからの接続をさばく時山ほどスレッドプールを用意して処理が終わるまでスレッドプールを開放できなかった。でもFunctional RouterやMonoを返すようなControllerを書けばスレッドプールのリソースを削減できる。だから、たしかにFunctionalなのはtaste(好み)の問題だけど、良いことはある。

Introduction to Spring WebFlux

Pivotalの中の人になったmakingさん。

スライドは一度公開されたのだが現在非公開設定の模様。 アウトラインはgistにあがっている。

まずWebFluxを使ったデモアプリケーションのお披露目があった。

github.com

このデモアプリケーションはIoTデバイスからの通信を受け取ってリアルタイムにさばくアプリケーションで、このセッションを聞くために集まった聴衆からの80ほどのリクエストをさばいていた。 Tomcatは1リクエスト1スレッド消費するので、普通に書くとリクエストの数だけスレッドを消費するはずだが、このアプリはWebFluxというReactive Programmingの基盤を使っているので、5-10スレッドでさばける。なんだそれすごい!!!

Springに追加されたReactive StackはNon-Blockingを扱う。

今までのServlet Stackは1リクエストごとに1スレッドを生成するが、Reactive Stackはイベントループを使って処理を行うので、少ないスレッド数で処理を行える。具体的には、Tomcatがデフォルトで200のスレッドプールまで対応するのに比べてWebFluxはデフォルトでCPU数と同じ数だけのスレッドを使いまわしてスレッド数の10倍の数のリクエストを捌く。

Reactive Stream自体はJava API仕様で、SubscriberとPublisherが存在する。 Java9 APIでもRxJavaでもSpring ReactorでもAkka Streamsでも使える。 Flux(0..n件用)とMono(0..1件用)というインターフェースが重要。

Publisher側は情報を流す量を調整できて、1秒ごとに情報を流す、みたいなことができる。

Spring MVCとSpring WebFluxの違い

全く同じコードベースでも動くがそのままだと同期的なコードのままになるので、Mono.fromCallableとかを使ってMono型やFlux型を返す。 Spring MVC上でMonoを使うこともできる。が、非同期処理専用スレッドを立ててそいつを同期的に動かすことになる。(?)

無限ストリーム

content-typeをstreamに指定すると、無限ストリームを受け取ることができる。 使えるのは以下 - text/event-stream - application/stream+json - application/json

BackPressureを調整できるcontent-typeは上の2つだけ。これが効いてるとサーバー側でよしなにBackPressureを調整してくれるので、サーバーが圧倒されることがなくなる。(?)

POSTする時にRequest BodyをFluxでもらうこともできて、これをやるとリクエストが終わる前にレスポンスが返りはじめる。 Transfer-encoding: chunkedにするとじわじわとHTTPリクエストを送ることができる。

Streamをshare()すると、Streamがブロードキャストされて接続してきた人全員に同じストリームを配信できる。

Blockingなコードを使う時は気をつけて

Reactive StuckでBlockingなコードを書かなきゃいけない時は、あっさりCPUコア数分のリソースを食いつぶす。

Spring Data Kay

Reactiveサポートが入った。RedisとかのNoSQLとの通信でReactiveなインターフェースを扱えるようになった。 Repositoryのインターフェースが変わったので、バージョンをあげるとそのままでは動かないかも。気をつけて。

JDBCはReactorと一緒に使うとブロッキングになる。 具体的にはJDBC自体がブロッキングなI/Oしか提供しないので、イベントループ型のControllerなどを書いても結局JDBCアクセスで詰まってしまう。 すると、CPUコア数しかスレッドがないのでパフォーマンスが落ちる。 次のJavaでは非同期JDBCが入るはずなので、それを待つ方が良い。

だから、RDBMSにつなぐアプリケーションはWebFluxじゃない方が良い。

また、Spring SecurityもReactive用の設定がある。 ThymeleafでもReactiveモードがあって、chunked modeをサポートしてる。

これからWebFluxを使いたい時は、 FrontendにWebFlux、BackendのRDBがある時はSpring MVCで作ると良い。 BackendもWebFluxを取り入れたい時はNoSQLが必須。

Spring Cloud GatewayAPI GatewayをSpringで作れるようになる。

所感

Reactiveに胸躍った。 Javaレベルが足りなくてスレッドを生成するコストとか保持するコストのイメージが沸かない。 でもAndroidでUIスレッドとBackendスレッドを使いわけるコードを書いたおかげで、ちょっとは分かる。

Yahoo! JAPANのコンテンツ・プラットフォームを支えるSpring Cloud Streamによるマイクロサービスアーキテクチャ

コンテンツプラットフォームというYJ内部の基盤開発の話。 スライドは以下。

www.slideshare.net

コンテンツとは

天気、スポーツの試合情報、ニュースなど...。

コンテンツプラットフォームとは

個人・企業などの配信者から入稿されたコンテンツを管理する基盤。 リプレイス前はC+Perlの巨大なアプリケーションでテスト不可能・リファクタ不可能。

リプレイスの設計

処理自体は文字列の処理が中心なのでPaaSに行けるはず。 スパイクアクセスに耐えられるよう柔軟にしたい。 MQで非同期に処理を流したい。 データストアはCassandra。YJ!っぽい。 入稿受付サービス、入稿処理サービス(形態素解析、ジャンル判定など)、入稿通知サービスなど20ほどのサービスが連携してPivotal Cloud Foundryで動いている。 (ここらへんの仕組みが必要な点は、弊社にも共通する。本筋と少し違うけど、入稿するデータごとの違いはどうモデリングしてるんだろう。) 非同期部分はSpring Cloud StreamとApache Pulsar。 Apache PulsarはYahoo.Inc製のMQ。

Spring Cloud Stream

Source Processor Sinkの概念がある。 Brokerが必要。 テストツールでBrokerをモック化してテストできる。

つくってみて得た知見

処理のどこでエラーが発生したのか、関連するどのサービスが原因なのかわからない。 これを解決するために、Spring Cloud Sleuthを使ってリクエストごとに一意のIDを振る。 これにさらにZipkinを組み合わせてIDを可視化することができる。

所感

弊社も規模は比較にならないくらい小さいといえど、入稿 -> 配信の流れは同じ。 同じようにキューを挟んでマイクロサービス化するのはアリだと思う。

ドメイン駆動設計のためのSpringの上手な使い方

現場で役立つシステム設計の原則」の著者、Guildworksの増田さんによるセッション。 博士みたいな風貌のおじいちゃん。

スライドは以下。

www.slideshare.net

DDDの魅力

サックと作ってリリースして終わり、であればいらない。 長く保守し続けること,価値を生み続けることが真意である。

DDDの基本活動

開発者がドメインを学ぶ

学んだことを"コード"として書けることこそ技術者 「継続的に学習する」 深い洞察に進む、姿勢

学んだことをコードで表現する

技術者たるものドメインの知識をコードで表現できる、説明できること

モデルと実装(の構造)を一致させる

  • モデルと実装を関連付けることで、実装が整理され見通しが良くなる 実装からfeedbackすることで、モデルが実用的になる
テクニック
  • ドメインの記述を 技術の関心事から独立させる isolating-the-domain
  • 概念の単位とプログラミングの単位を一致させる
    • モジュール化
    • 型(class interface enum)で知識を表現する
    • 基本データ型ではなく、ユーザ定義型で表現する
  • 最初からピッタリの方は見つからない
    • [実験 feedback 設計]の改善を繰り返す

深いモデルを探求する

  • 正直言って... ここの議論はされていない。 (エバンス本の9-13章だったかな...?)
  • 成果を最大化するために必要な作業だ

  • 中核の複雑さ/機会に焦点を合わせる "中核"を探す作業こそが "モデルの探求作業"

  • 役に立つ型を見つけるための実験を繰り返す
    • 暗黙の概念を明示的に表現する
      • 制約 (BeanValidation, Policy)
      • プロセス (業務の流れ/手順)
      • 区分の分析 「12の区分を分析したときに、3種類の状態の組み合わせだったなど」 -> 暗黙の知識を宣言的に表現できると if文がどんどん減っていく!!

巨大な複雑さに立ち向かう

  • 戦略的に取り組む
    • 時間がかかる
    • 地道な努力の積み重ねのエネルギー
  • 巨大な複雑さに立ち向かうためのスキル (14-16章) 巨大になればなるほど如何にシンプルな構造を見つけるか 「コードとしてどう表現するか?」
    • 俯瞰
    • 蒸留
    • 大きな構造化

SpringとDDD

Springのprograming-model

Springはアプリケーションの「基盤」を提供する 開発者はドメイン固有のロジックに集中する ドメイン駆動設計の考え方そのもの -> SpringはDDDを実践するためのフレームワーク (@Service, @RepositoryはDDD本からでてきているのだ)

Springを使えばDDDになる?

MVCのモデル(@Controller/@Service/@Repository)をやっているだけでは(サービス層にスクリプトをゴリゴリ書くだけでは)得られない -> この3層からドメインを抽出することで初めて効果が得られる

DDDのためのSpringの使い方

spring-boot-starter-*
  • 初日から...
    • 動くアプリケーションで考える
    • 学んだことをコードで記録する
    • コードでモデルを表現する
    • End to Endで実験してみる
spring integration

「巨大な複雑さに立ち向かう」 - 境界づけられたコンテキスト (Bounded Context) = gitリポジトリ単位 - コンテキストマップ - EIPの実装技術 分析・設計・実装するための枠組み - Messaging Model

spring batch
  • 今でも多くの業務を裏で支えている
  • ドメインの理解度の違いが現れる場所
    • job/step etc.

まとめ(DDDを現場で取り組むためのヒント)

日本一やさしく説明する予定のマイクロサービス入門

JSUG会長長谷川さんのセッション。 スライドは以下。

www.slideshare.net

メッセージングでコラボレーションを行いつつ全体で1つの仕事をする、自立分散協調のアーキテクチャオブジェクト指向をシステムレベルに適用した、と考えることができる。 マイクロサービスにはチームや会社のチームワークが必要だよ。でもそれもオブジェクト指向からの拡張と考えれば同じ。

オブジェクト指向が騒がれた当初、小さすぎるクラスや神クラスを作ってしまって今笑い話になるように、マイクロサービスに関してもそうなると思う。 今は大きすぎたり小さすぎるマイクロサービスを作ってしまうことがあると思うけど、正解は一つじゃない。

複雑なものは新しい技術で簡単にはならない!!! 今すごく複雑な業務プロセスを、マイクロサービスで簡単にするんだ!みたいなのは通用しない。 また新しい複雑なものができるだけ。

本当に簡単にしたければ、やり方を変えるしかない。業務プロセスを変えるとかね。

データモデルがぐちゃぐちゃだと、マイクロサービス化をそもそもできない場合がある。 Mybatis便利だよね、と言っている時点でなにかおかしくて、やばいSQLが書いてあるのでは?

最初から最高を目指さずに、切り出せるところから切り出していった方がいい。

マイクロサービスが増えると、「誰も知らないサービス」が出てきそう。100とか200のマイクロサービスを作ったとして、全体の仕様を管理できない、復元もできないみたいなことになる。 開発チームがバラバラ、RDB製品もバラバラでは、今後それをマネジメントする人がいなくなったらどうするのか? 全部SpringBoot x Javaで揃えた方が良いのでは? あるいは本当に必要なところだけ、その特性を活かしてNodeなりRubyなりつかえばよいと思う。

所感

最近あんまりマイクロサービスについての議論を追っていなかったけど、納得感のある話。 今はまだ提唱されてからの時間が短すぎて、今後どうなるかわからない。 でも今時点で試す価値は十分にある。要点を間違えなければ。

The Road to Serverless: Spring Cloud Function

Cloud abstractionについて話す。 Spring Cloud Functionについて話す。 Raising the value lineについて話す。

スライドは以下。

The Road to Serverless: Spring Cloud Function

Cloud Abstraction

VMから始まってコンテナ、アプリケーション、Functionの順に抽象度を増していく。

Serverlessはイベント・ドリブン、動的リソース最適化、メッセージに対して課金され、プロダクションコードを極めて高速に開発できる。 ビジネスロジックに集中できる。

Google Cloud Functionはなかなか良いよ。 WebUIで試せるよ。もちろんちゃんとやるならこれじゃダメだけど。CIが必要だし自動化が必要。

JavaのFunction APIを試せるよ。

Spring Boot Thin Launcherってのがあるよ。

SpringでOAuth 2.0 / OpenID Connect 1.0を使う

インスタンスを初めて目視確認したうらがみさんのセッション。

SpringでOAuth 2.0・OpenID Connect 1.0を使う

OAuth 2.0は仕様の日本語訳があるから見てみてね。 もちろんリソースオーナーもそれを利用する側もSpringで作れる。

cloud-oauth2を依存に追加する。 @EnableAuthorizationServerアノテーションで、それ用のエンドポイントとかが作られる。

アノテーションとapplication.propertiesの設定でSpring Securityを使ってOAuth2による認可を使ったログインが可能になる。

OIDCのくわしい仕様とかは話さない。

所感

OIDCまわりが全然前提知識として足りず、ついていけなかったので勉強する。 TwitterのOAuthログインも、専用ライブラリに頼らないでもここらへんを使うと作れるのかな。 要はユーザーの名前とかアイコン画像、メールアドレスを取得できればいいわけだしね。

まとめ

Springframeworkは今、特にクラウドネイティブ・非同期処理・マイクロサービスまわりのエコシステムが整ってきていると感じた。 NetflixやPivotalのような企業がJavaやSpringframeworkの周辺ツールを提供してくれているおかげでこのような環境が整ってきた。

たしかにマイクロサービスをやろうと思ってエコシステムから作るはしんどい。 すると、アプリケーション開発言語はエコシステムがどの程度整っているかで選ぶのも筋が悪くはないのでは?と思う。 PHPにはPHPに得意な、RailsにはRailsに得意な、SpringにはSpringに得意な領域がある。 そして現状Springのそれは、マイクロサービス開発に関わる部分のようだ。

文章を見直す、って何を見直せばいいのかまとめてみた - 箇条書き・表組み編

前回は単に日本語を連ねた文章のチェック方法についてまとめたが、同僚氏の文章をよくよく見てみると実際にはドキュメント管理ツールの機能を使うことによって論理的でない文章が隠蔽されていることがあることがわかった。

ので、今回はこれらの機能を使って書かれた文章をどの観点でチェックすべきか、について考えてみる。

箇条書き

箇条書きにすると接続詞を飛ばせるので、なんとなく論理的に整っているような気がしてしまう。自分もそうだった。 暗黙的に接続詞を伝えるのは難しいのだが、慣れないうちはそういう機能を使うとそれっぽくなる気がしてついつい使ってしまう。

ので、自分で書いた文章に箇条書きが含まれる場合は以下を行う。

明示的に接続詞をつけて読んでみる

箇条書きの兄弟要素は

  • 理由の列挙
  • 事例の列挙

であることが多いので、「また、」や「さらに」などの接続詞を使って読んでみる。

- 全文検索エンジンにElasticSearchを使う場合
(または)
- 同じくSolrを使う場合

箇条書きの親子要素はより詳細な理由を説明することが多いので、「${親}。なぜなら${子}だから。」と読んでみる。意味が通らなければ直す。またはその項を消す。

- 外部アクセスできる必要がある
    - サーバーからS3にアクセスしなければいけない

表組み

表も難しい仕組みのひとつ。うっかり行・列の項目設定を間違えるとあっさり泥沼にハマることができる。 表組みを書いた時は以下のことをチェックする。

見出しをつける

表が何を示すのか、1行で述べる。

## S3とcronを採用した場合のメリデメの比較検討

|       |メリット          |デメリット                          |
|:------|:--------------|:--------------------------------|
|S3のhook|リードタイムが少ない|外部からのリクエストを受け付ける口が必要  |
|cron   |全部Rubyで書ける  |実行タイミング次第ではリードタイムが長くなる|

見出しの内容と表組みの行ラベル(S3のhook)・列ラベル(メリット)の設定がズレている場合、言いたいこととズレた表を書いている。 あるいは見出しだけを読んで何の表がつづくのかわからない場合、言いたいことが何なのかまだまとまっていない。

ラベルと具体的な内容をつなげて読んでみる

ラベルをつけて分類するとなんとなく分類できているような気がするが実態が本当にそうかとは全く関係がない。 自分の表が論理的に正しい分類をしているかを調べるためには、見出しと具体的な内容をつなげて日本語にして読んでみる。

- S3のhookのメリットは、リードタイムが少ないことだ。
- cronのデメリットは、実行タイミング次第ではリードタイムが長くなることだ。

読んでいて違和感があれば、書いてある内容がズレているので直す。

文章を見直す、って何を見直せばいいのかまとめてみた

同僚の資料を添削する機会があって、添削と議論の中でわかったことをまとめておく。

NOTE: ここで資料とは、要件を議論するたたき台資料とか設計の選択肢の検討資料を指す。

正直自分も同僚と同じ年代の頃に「これロジカルじゃないよ」とか言われても、いや分からんなぁ...と思ってたし、その時にこんなことを分かってればもう少しうまいことやれたのかなぁ、と思いつつ。

自分が書いた文章を例文として拝借されることを快諾してくれた同僚氏、ありがとう。

資料を構成する要素を一つずつチェックする

資料を構成する一番小さな要素から順にチェックしていく。

資料は

  • 単語
  • 段落

が集まってできている。 チェックの観点は、これら一つ一つが日本語として正しいことと論理的に正しいこと。

単語

PCで書くなら関係ないけど、存在しない日本語を書いていないか調べる。 論理構造はないので調べない。

同音異義語を使い間違えていないか調べる。

破戒的変更を許容します。

日本語として「てにをは」が破綻していないか調べる。

この処理には外部アクセスに必要ない。
    -> 外部アクセス「は or が or ...」

主語と述語だけを読む。それだけでも主張がズレないかを調べる。

自分の意見は、S3にあるファイルをサーバーの特定の箇所に置くという処理です。
    -> 主語と述語だけを抜き取ると「意見は、処理です」となり、文章の意味が通らない。

ズレる場合、修正する。文を短く切るのが有効な場合があるので、検討する。

段落

ここらへんから日本語として正しいかを調べる必要がなくなってくるので、ある段落が論理構造的に正しいかを調べる。 あと、正直好みもある気がするからなんとアドバイスしてよいか悩ましい...。

段落の結論を述べている一文を探す。ない場合、作る。ある場合、それが1、2文目に入っていなければ移す。 2文目でも良い理由は、たとえば問いかけから始まったり、前の段落を受けての1文で始まったりする場合が考えられるから。 (というか本来は何文目でもいいはずだが、慣れないうちから変な場所に結論を書くのは筋が悪いと思う。)

次に、段落に見出しがある場合は、見出しだけを読んでみる。見出しだけを読んでその段落の主張が分かるか調べる。 わからない場合、わかるように書き直す。

## 自分の意見
自分の意見は、今回はS3のPUTイベントを使って処理を行うべきだと考えています。
==========================
## S3のPUTイベント通知を使うべき
自分の意見は...

文と文のつながりが破綻していないか調べる。 具体的には、ある文の主張と次の文の主張を比較して、その関係を表すのに適切な接続詞を使ったり使わなかったりする。

案としては、S3のPUTイベントを使うことが考えられます。さらに、バッチ処理で実装することも考えられます。
    -> 2つの文は内容は案の列挙。しかし接続詞の「さらに」は前の文に詳しい説明を追加する時に使う。よって不適。

また、段落の主張と、段落に含まれる文リストを比較して十分な論拠を示せているか調べる。 具体的には、今まで出会った中で一番意地悪な質問をする人を脳内でエミュレートしてその人にツッコませる。 ロジックツリーを書いても良いけど、どちらにせよセルフツッコみは必要。

文章

段落に対して行ったチェックを文章に対しても行う。

文章の結論を述べている一文を探す。ない場合、作る。ある場合、それが最初に書いていなければ移す。

文章には普通見出しがあるので、なければ作る。ある場合、見出しだけを読んでみる。見出しだけを読んでその文章の主張が分かるか調べる。 あるいは文章の見出しなら、主張ではなく目的がわかるだけでも良い気がする。 たとえば、以下の見出しはどちらでも良い気がする。

# ○○処理の自動化の実装方針を決める
==========================
# ○○処理の自動化をS3のPUTイベント通知をつかって実装したい

段落と段落のつながりが破綻していないか調べる。 こちらは段落内の文のチェックと違って、前後のつながりというよりは論理構成が正しいかを確認する。 具体的には、まず段落の見出しだけを読む。それを読んだだけで大筋は納得できるか調べる。

まとめ

まとめてみた。 文章の論理構造が正しいかのチェック方法を、まだうまいこと明文化できない。自分でもうまいことできてないんだろうな。

継承か保有か

public class Price {
    private Long price;

    public Price(Long price) {
        this.price = price;
    };

    public add(Price another) {
        return new Price(this.price + another.price);
    }
}

みたいな Price クラスがあった時に、

public class Yen {
    private Price price;
    public Yen(Price price) {
        this.price = price;
    };

    public Yen add(yen) {
        return new Yen(this.price.add(yen.price));
    };
}

//...

Yen yen = new Yen(new Price(10));
yen.add(anotherYen);

を定義するのか

public class Yen extends Price {
    // ...
}

// ...

を定義するか。

最初に考えたのは、「それぞれここがしんどいなー」だった

ここがしんどい継承

継承だと、子クラスのインスタンスを使う側は親クラスのドメインを知らないと結局どんなメッセージを打てるのかわからない。 複雑なアプリケーションならより一層、親子関係にあるすべてのクラスのドメインが果たす責務に詳しくならなければ...。

ここがしんどい保有

こっちがわりと有用なのではないかと思っていた。 親クラスのデフォルト実装を公開するのに、毎回関数を定義しなければいけないけど、そのかわり親クラスの振る舞いを一部しか知らなくて良い。

そもそも役割が違うのでは?

委譲か継承か、それが問題だ – Where is the mate to the Sock ?

やっぱりそうらしい。 ていうか社内の情報共有ツールで他の人が書いた日報のツッコミでこのブログを見つけた。弊社良いな。

いや、そもそも設計思想が違うのか??

Priceを継承したYenは、通貨単位の「円」はPriceの振る舞いを拡張したものだというドメインの理解を主張している。 一方でPriceを保有するYenは、通貨単位の「円」はPriceを自身の属性の一部だと主張している。

どっちがいいとかではなく、ドメインの理解が違うんだろうな。

Clojure/conj 2017 上映会 #1 に参加してきた

NOTE ただの参加ログです。雑な情報の再生産なのでちゃんとしたやつとか本家を読んでください。

clj-nakano.connpass.com

に参加してきた。 開催者様、会場の準備、ピザとコーラ、そしてそもそも開催自体していただいたこと、ありがとうございました! みたことある人がチラホラいる感じだった。

Rich Hickeyの話をちょっと再生しては訳が入る形式だったので、正直言ってRich Hickeyが何言ってるかは5%くらいしかわからなかったけど話についていけた。

Rich Hickeyについて

Rich Hickey、突然現代に現れた未来人だと思ってたけど大学卒業後18年間ふつうに(?)開発者やってた。 Rich Hickeyは 「Situated」なプログラムをイメージしている。ビジネス要件で簡単に自分が心血を注いだアルゴリズムが無意味になるのはよくあること。

現実世界は対応を迫られる不整合に満ちている

現実のアプリケーションでは純粋なアルゴリズムはほんのすこしで、残りはほとんど情報処理用のプログラムである。 しかもその純粋なアルゴリズムも、ビジネス要件で簡単に翻る。 情報処理というのは、たとえば外部ライブラリを使用したり、DBと通信したり、別システムと連携したりすることを指す。

これに時間軸を加えれば、システムが対応しなければいけない変化には「ライブラリがメンテされなくなった」「DB製品が変わる」「システムのI/Fが変わる」「要件が変わる」ことも含まれると分かる。

RichはORMでRDBMSプロトコルをラップしてあたかもプログラミング言語の世界のプロトコルであるかのように使えるのは努力の方向性が違うと言っている。 んー、Datomicならいいのか?どういうORMを想定しているんだろう。

現実の複雑さ

talk-transcripts/00.29.49.png at master · matthiasn/talk-transcripts · GitHub

上の図がわかりやすい。

Rich Hickeyは上の図で型を間違えることを些細な問題と表現しているが... Clojureを触っていてもMapがくるかListがくるかそれとは別の何かが来るか気にしなければいけない。 とはいえそれは瑣末な問題で、プログラミング言語のレイヤーで解決しないことにした、ということかな。 今仕事でRubyを触っているけど、Rubyはメッセージ中心だから型が何かは気にしない、という思想があるのに対してClojureはそもそもそんなところ瑣末な問題だから気にしないわ、と切り捨てているのが、設計思想の違いを感じて面白いと思う。

Pythonとかの他の動的型付け言語はどんな思想で作られてるんだろう。

Immutabilityの背景

RichはPLOP(PLace Oriented Programming)という言葉を出している。 PLOPはイミュータビリティと相反するプログラミング手法で、メモリやディスクのアドレスと結合したプログラミング。 しかしそれではイミュータブルにできない。メモリのアドレスの中身に入ってる情報は刻一刻と変わる。

Clojureを支えるイミュータブルなシーケンスが以下らしい。

clojure/PersistentHashMap.java at master · clojure/clojure · GitHub

全然知らなかった。

情報は変化し続ける

静的型付け言語では、情報を操作するのがめんどくさすぎる。 クラスはデータのコンテナが意味を持ってしまったものだが、これを使ってEffectiveなプログラムを書くには情報を一つ一つクラス化しなければいけない。 具象を必要以上に持ち込んでしまったのが問題だ。

うーん...。 ドメインが多くて複雑なら、その分だけ扱う意味が増えてクラスが増えるのは自然なことだと認識してたけど...。 ていうか意味のないデータ構造だけでは、結局プログラマーは巨大なシーケンスのネストしたハッシュマップを指差して「ここにはユーザーのデータを変換したものが入ってるんだよ」とか話すことになる気がする。

巨大なシーケンスだとしても、その連想配列のキーに適切な名前をつければいいじゃない、ってことか、な?

Parochialismへの批判

ある異なるドメイン領域でユーザーをなんと呼ぶかが一致しないことは問題だという。 それは当たり前では...?

いや、そういうことじゃないか。 あるデータが持つ意味をクラスとして表現するのではなく、データのキーとすればいいでしょ、という話か。

結局ネットワーク越しに他のシステムに届くのはクラスではなくコレクションオブジェクト。 じゃあ自分のソースコード内でもそれと同じように書けばいいでしょって話か。

まとまらない... 読み直さなきゃ... Rich Hickeyが何言ってるかわからないから反論もできないのが悔しすぎる。

参考

Rich Hickeyのプレゼンのスクリプトgithub.com 今回の勉強会で使われた、上記プレゼンテーションの訳。 https://gitpitch.com/k2n/effective-programs-ja#/

Node.jsの抽象構文木を操作してソースコードを生成する

ソースコード生成してみたい!けど、そういや1年くらい前にASTって言葉を知ってから何もしてなかったな」、と思ってASTを書いてそいつを食わせてソースを生成してみた。

もともとはさいきょうのスタブサーバーを作りたいねって話から始まったからそういう感じのリポジトリ名の以下リポジトリに実際に今夜書いたコードが乗っかってる。

github.com

構文木ってなに?

プログラムの構造を、(Javascriptの場合)JSON形式にパースしたもの。 何段階かに分かれているっぽい。

詳しくは以下のブログエントリーで。詳しい記事ありがとうございます。

efcl.info

どうやってASTを生成するの?

ASTの仕様を知ってそれを満たすJSONを構築すれば、それをASTからソースに変換するライブラリに食わせればコード生成できる。 ソースコード ⇔ ASTのライブラリはJS界にいくつかあるみたいで、今回はEsprimaを使うことにした。 Babelもトランスパイラー?だから同じような機構を持ってるみたいだけど、特に理由なくEsprimaにした。

JavascriptのASTの構造はestreeという標準があるらしい。

github.com

けど、それを読むより実際にソースコードから生成されるASTを見たほうが早いなってことで以下で試す。

http://esprima.org/demo/parse.html

こいつに

let express = require('express');

みたいなのを食わせると

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "express"
                    },
                    "init": {
                        "type": "CallExpression",
                        "callee": {
                            "type": "Identifier",
                            "name": "require"
                        },
                        "arguments": [
                            {
                                "type": "Literal",
                                "value": "express",
                                "raw": "'express'"
                            }
                        ]
                    }
                }
            ],
            "kind": "let"
        }
    ],
    "sourceType": "script"
}

みたいな木構造にバラしてくれる。 逆にこいつを、対応したコード生成機に食わせればソースコードが生成されるってわけよ。

github.com

これを使えば、カッコとかカンマとかシングルクォートとか改行とか気にせずに、オブジェクトをガツガツ組み立てていけば思うままのソースを生成できる。

これを世に出してGithubのStarを稼ぐんだ、という野望を胸に書くコードは、心なしかいつもよりギラギラして見えた。