Magnolia Tech

いつもコードのことばかり考えている人のために。

ajitofmに出演した

ajito.fm

憧れのpodcastデビュー!

最初、もの凄い緊張してて全然喋れなかった。

色々話そうと思ったけど、あっという間の1時間でおそらく半分も喋れていない印象

もっと設計ナイトで喋ったようなことを喋ろうと思ったのに…

とはいえ、最後にYAPC::Tokyo 2019の告知ができたので、良かった

憧れの告知!

ただの飲み会でもshow noteを書くと良いな、と思った

Podcastを聴いている方だったら分かると思うんですけど、たいていのPodcastでは参加する人が事前にshow noteというものが用意されています。

例えば、ajitofmというPodcastのshow noteは以下のリンク先にあるように、箇条書きで用意されています。

ajito.fm

ネット上の辞書でもPodcastで話す内容を用意するもの、と紹介されていますね。

ejje.weblio.jp

こうゆうのが用意されていると、事前にどんな内容が話されるのか分かって良いですね(必ずしもshow noteが全部きれいに消化されるとは限らないんですけど)。


というわけで、先日Podcast収録でもないんですが、長時間話すのが初めて、というメンバで集まった時に、事前にshow noteを作っておいたら割と話すことに共通認識が事前に形成できて、非常に盛り上がった、ということがあり…


show noteをどんな風に用意したら良いか、その辺りの知見は下記のリンクが参考になります。

medium.com


というわけで、ただの飲み会でもshow noteを作っておくことで(特にそれまであまり話したことが無い人同士であれば)、盛り上がりのポイントが作れて良いのでは?という話でした。

「Java本格入門」を買ってきた

丁寧な言語入門書はたくさんあるけど、ちゃんと言語機能を学べる人向けに、モダンな書き方や、ツールチェーンをざっと説明してくれる書籍って貴重。「Java本格入門」は、例えばScalaを書くためにざっとJavaの機能を知りたい、なんて人に丁度良いのでは?と思った。

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

「みんなのGo言語」とか…

みんなのGo言語[現場で使える実践テクニック]

みんなのGo言語[現場で使える実践テクニック]

古くは「モダンPerl入門」もそんな雰囲気だった。

モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)

よちよち感ある入門書と、クックブック系、フレームワークの入門書、特定技術に特化したものを除くと、この手の「ベストプラクティスひとめぐり」みたいな本が欲しくなるんだよね。

2018年版・この処理Scalaでどう書く?…前半戦

ふと、この記事にあるようなこと、Scalaだったらどう書くかな?と思ってまとめてみました。途中で力尽きたので、まずは前半戦まで!

www.m3tech.blog

あの処理、Scalaでどう書く?

基本的にScalaの標準ライブラリでやる方法を紹介し、Javaの標準ライブラリを使う必要があるところはその旨書いてあります。

また、調べていくとScalaJavaの標準ライブラリではできないことも有ったので、そこには「標準ライブラリではできません」と書いておきます。標準ライブラリ以外でやれる方法が有ったら、ぜひ教えてください。

なお、標準ライブラリはScala 2.12、Java 11の機能に基づいています。

標準出力・標準エラー出力

どちらもScalascala.Consoleオブジェクトのprintlnメソッドを使います(パッケージ名のscalaは省略可なので、以降は省略します)。

println("HELLO") // 標準出力にメッセージ

Console.err.println("ERROR!") // 標準エラー出力にメッセージ

単にprintlnと書いた場合は、Console.out.printlnが呼び出されます。

なお、標準ライブラリにはログ出力ライブラリは用意されていません。

ファイル関係

基本的にScalaの標準ライブラリでは、ファイル関係のサポートがほぼ無いので、基本的にJavaの標準ライブラリを使います。

パスの操作

Java 7から追加されたjava.nio.file.Pathsクラスを使います。

import java.nio.file.Paths

val p = Paths.get("/foo/bar/baz.txt") // OSごとの実装を持つPathインタフェースが返される
p.getFileName // ファイル名「baz.txt」を保持するPathが返る
p.getParent // 親ディレクトリ「/foo/bar/」を保持するPathが返る

val dirpath = Paths.get("/foo/bar")
dirpath.resolve("baz.txt") // パスの連結 「/foo/bar/baz.txt」を保持するPath…引数は文字列でもPathでもOK

Pathは、toStringで文字列に戻せます。また、Java6以前に作られたライブラリはjava.io.Fileクラスを要求するものがありますが、toFilejava.io.Fileに変換できます。

import java.nio.file.Paths

val fullpath = Paths.get("/foo/bar/baz.txt")
fullpath.toString // 文字列として「/foo/bar/baz.txt」が返る
fullpath.toFile // java.io.Fileでラップされた「/foo/bar/baz.txt」が返る

チルダ環境変数が含まれるパスを扱う

ScalaJavaチルダ環境変数をパスに展開してくれる標準ライブラリは無いようです。

実現しているライブラリがあればぜひ教えてください。

ファイルの読み書き

テキストデータの読み込みにはScalascala.io.SourceオブジェクトのfromFileメソッドが便利です。

val source = io.Source.fromFile("foo.txt", "utf-8")
val lines = source.lines
lines.foreach(println) // 行単位で標準出力へ
source.close

fromFileメソッドは文字列でのパス名以外にもjava.io.Fileクラスのオブジェクトも指定可能です。また、scala.io.Sourceはデフォルトで文字コードとして"UTF-8"が使われるようになっていますが、明示的に指定した方が分かりやすいでしょう。

反対に書き込みについては、専用のライブラリは(なぜか)用意されていないので、Java 7で導入されたFiles.newBufferedReaderメソッドを使います。ただし、Scalaにはtry-with-resource構文が無いので自前でクローズします。

import java.nio.file.Paths
import java.nio.file.Files
import java.nio.charset.StandardCharsets

val path = Paths.get("foo.txt")
val writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)

try {
  writer.append("内容")
  writer.newLine
} finally {
  writer.close
} 

構造が簡単なうちは自前でcloseメソッドを呼び出すようなコードを書いていても大丈夫だと思いますが、コードの構造が大規模になってくるとcloseの呼び出しも複雑化してきます。このような場合、Javaであればtry-with-resource構文がありますし、C#にはusing構文があります。Scalaでも構文は用意されていませんが、コーディングテクニックとしての「ローンパターン(loan pattern)」と呼ばれるものがあります。ここでは説明は割愛しますが、調べてみると色々な書き方が有るようなので、試してみましょう。

行数を数える(wc -l)

特に専用の構文やライブラリが用意されているわけではないですが、先ほどのio.Sourceを使うとシンプルに書けます。

val source = io.Source.fromFile("foo.txt")
source.getLines.length

ファイルの列挙

Java7で導入されたFiles.newDirectoryStreamを使います。

import java.nio.file.Paths
import java.nio.file.Files

val files = Files.newDirectoryStream(Paths.get("."), "*.txt")

try {
  files.forEach(println)
} finally {
  files.close
}

ファイルの情報(存在確認・作成日時)

java.nio.file.Filesのメソッド群を使います。

import java.nio.file.Paths
import java.nio.file.Files

val f = Paths.get("foo.txt")
Files.exists(f) // 存在確認
Files.isRegularFile(f) // ファイル?
Files.isDirectory(f) // ディレクトリ?
Files.getLastModifiedTime(f) // 更新日時…戻り値の型がjava.nio.file.attribute.FileTimeであることに注意!

その他、ファイルシステム固有の属性(作成日時、アクセス日時)は、Files.getAttributeメソッドを使います。戻り値がobject型になってしまうので、キャストが必要な点が要注意です。

val createTime = Files.getAttribute(Paths.get("foo.txt"), "unix:creationTime").asInstanceOf[java.nio.file.attribute.FileTime]
val accessTime = Files.getAttribute(Paths.get("foo.txt"), "unix:lastAccessTime").asInstanceOf[java.nio.file.attribute.FileTime]

コピー・移動・削除

こちらもjava.nio.file.Filesのメソッド群を使います。

import java.nio.file.Paths
import java.nio.file.Files

Files.copy(Paths.get("foo.txt"), Paths.get("bar.txt")) // コピー
Files.delete(Paths.get("bar.txt")) // 削除
Files.move(Paths.get("foo.txt"), Paths.get("bar.txt")) // 移動

コピーや、移動はオプションとしてStandardCopyOptionが用意する定数を指定することができます。例えば、StandardCopyOption.REPLACE_EXISTINGを指定すると、すでにファイルが有っても上書きします。

import java.nio.file.Paths
import java.nio.file.Files
import java.nio.file.StandardCopyOption

Files.copy(Paths.get("foo.txt"), Paths.get("bar.txt")) // コピー
// foo.txtを書き換える処理
Files.copy(Paths.get("foo.txt"), Paths.get("bar.txt"), StandardCopyOption.REPLACE_EXISTING) // 2回目のコピーで上書き

と、ここまでで力尽きたので、続きは明日以降!

外部コマンド

単純に実行する

外部のコマンドを実行し、標準出力を受け取る:

環境変数やカレントディレクトリを変更する

リダイレクトを使う

パイプを使う

spawn → wait (外部コマンドを起動し、終了を待つ)

シェルを実行する【危険!!】

時刻関係

文字列関係

文字列への式埋め込み

ヒアドキュメント

コマンドライン引数

終了時の処理&シグナルをtrapする

HTTPリクエスト(curlwget の代替)

吉祥寺.pmへの参加者を募集しています

このブログは企業テックブログという訳でもないので、特にエンジニア募集とかないですけど、定期的に吉祥寺.pmというイベントをやっているので、良かったら参加してみてください。pmとはついていますが、Scalaトークも歓迎です!

kichijojipm.connpass.com

あと、良かったら、Twitterのアカウントもフォローしてください。設計のこととかツイートしています。

twitter.com

「いかにして問題をとくか」を読んでみよう

いかにして問題をとくか

いかにして問題をとくか

先日の設計Night 2018で発表したスライドの冒頭で「いかにして問題をとくか」に出てくる4つのステップを引用した。

  1. 問題を理解すること
  2. 計画をたてること
  3. 計画を実行すること
  4. ふり返ってみること

元々、表紙をめくった2ページがチートシートになっていて、ソフトウェア開発の進め方を考える上で非常に参考になる要素が全部ここに詰まっているといってもいいくらいの充実した内容が書かれている。この2ページのために1620円を払っても全然いい。

スライドでは最初のステップ「問題を理解すること」だけを使ったけど、当然残る3つのステップもソフトウェア開発においては大事な考え方が詰まっている。

計画をたてること

ここでいう「計画をたてる」とはスケジュールを引くことではない。ここでは類似の問題を探してきたり、問題をとくための条件を整理したりする過程をいっている。

特にチートシートの最後に書かれている「問題に含まれる本質的な概念はすべて考慮したか.」をことあるごとに唱えた方が良い。

計画を実行すること

単に実行するだけではなく、段階的に(形式的、または直感的に!)進めていき、それぞれの正しさを理解すること、更には正しさを証明できるか?と書かれている。

自分が理解できていることと、他人に向かって証明できることはまた異なるといっている。

現代的なソフトウェア開発ではテストを書くことは当たり前になってきたので、この辺りの記載は非常に納得感がある。テストは、その書かれている範囲においてプログラムが意図通りに実行されることの証明になる(バグのないことの証明ではない)。

ふり返ってみること

結果が正しいかを試すことができるか、同じ結果を違った仕方で導くことができるか、ということが書かれている。

KPTつかったりして、振り返りを日常的にやることが大事だ、という考え方が広まっているので、この辺も納得感がある。

おわりに

見開きのチートシート、第Ⅰ部「教室にて」、第Ⅱ部「いかにして問題をとくか」までが約40ページで、ここまでを読めばほぼこの本の主要なことは全部読むことができる。残る200ページは雑多なトピックが並んでいるので、拾い読みしておけばいい内容…決して全部読まなくてもいい。

「UMLモデリングのエッセンス」を読み直した

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

マーチン・ファウラーと言えば、「リファクタリング」を筆頭にさまざまな名著を書いている方だけど、「UMLモデリングのエッセンス」も実に良い。なんとなくだけど、出版からかなりの年月が経っているからか、はたまたタイトルからUMLの子細な解説書かと思われているのか、あまり最近話題に上ることが無い気がする。

「設計Night2018 powered by Classi」で登壇してきました

「設計Night2018 powered by Classi」というイベントで、「設計のための、問題の捉え方〜ドメイン知識の暗黙知形式知に〜」というタイトルで発表しました。

実際に発表したスライドは読み物として冗長過ぎたので、圧縮したまとめ版を作っていて、そちらへのリンクを張って起きました。

speakerdeck.com

スライド、まとめも長いんですけど、今回自分がまとめたかったのはこの一枚です。

今回の「設計Night2018 powered by Classi」というイベントは、今年のBuildersconで設計に関する最高の発表をされたしんぺいさんによる企画だったので、それは絶対に参加したい(自分も聞きたい)ということで、二つ返事で引き受けました。

connpass.com

イベントレポートの様子は当日のハッシュタグ#sekkei_n2018を追いかけるとご理解頂けるのではないでしょうか。

ちなみに、しんぺいさんの最高の発表内容は、下記のリンクから見ることができます、必見です。

開発現場で役立たせるための設計原則とパターン - builderscon tokyo 2018

話した内容の背景とか、補足とか

最初、引き受けたはいいけど「ドメイン知識の暗黙知形式知に」「暗黙知が問題の捉え方に移動した」について話して下さいと言われても、実際に何を話せば…とぐるぐる回ってしまったんですが、丁度2ヶ月ほど前に読み直していた「いかにして問題をとくか」に出てくる”条件はかき表すことができるか”という一文が自分の中で突然上手くハマってそこを出発点にしました。

いかにして問題をとくか

いかにして問題をとくか

(本文も学びが有りますが、エンジニアにとっては見開き2ページだけでも、開発のステップに関する学びがるので、お勧めです)

あとは、「ソフトウェアの設計における暗黙知あるある」と、以前から感銘を受けていたt_wadaさんのツイートを並べてみると、大筋ができました。

結局のところ、プログラミング言語の進化とか、開発ツールの進化って、いかに開発者が考えた意図を未来に残して、かつそれが上手く後世の人が活用できるか?…それが上手くできないと、ソフトウェアの設計が継続的に上手くできるなんて無いんだぁ!!!って話じゃないかなーって常々思っていたので、それが話せて良かったなって思いました。

あと、懇親会で「ペアプロって暗黙知に有効ですよね」って言ってもらって、「それは確かに!」って思ったので、結局のところ明確に言っているかどうかは別として、みんなが感じている問題の本質は割と同じところにあるんじゃないかと改めて思いました。

暗黙知の種類について

色々な暗黙知(と、形式知)に関する文献(野中郁次郎や、マイケル・ポランニーの有名な本とか)を読んだり、論文もいくつか読んでみたのですが、割と抽象度が高かったので、ソフトウェアの設計においての「あるある」をまとめていったら、最終的に「事実」「関係」「原則」の三つに行き当たりました。この辺のまとめ方は、ほかの視点も当然あると思うので、絶対ではないですが、実感として分かりやすいかなって思っています。

最後に「基準」も暗黙知だな、という話を触れたは、統計的手法を使って暗黙知形式知に変えていく活動って有るなーと思って、その辺を話したかったのですが、さすがに長くなってしまうので割愛しました。でも、マシンラーニングとかもそうですけど、あれって意識していない基準を明らかにしていく活動で、まさに今回のテーマにピッタリだなと思っています。ただ、この辺は自分で語れる要素があまり無いのでぜひ次の設計Nightが開催されたあかつきには誰か発表してほしいなぁと。

ケーススタディについて

ケーススタディに上げた年齢の話は、以前に「4月1日生まれは早生まれ、根拠は”年齢計算ニ関スル法律”」という話を聞いて、調べたことがあったので。

実は、自分は逆に一番最初に「これは2月29日生まれを個別に条件を書かなくてもいい、なんてエレガントなルールなんだ!」と驚いていて、でも「法律の趣旨はそうじゃない」らしく、「あぁ難しいなぁ」と思った思い出からです。そりゃそうですよね…2月29日生まれを特別扱いしないために全員一日前にするっていうと、そりゃ本末転倒ですし。趣旨を理解するのは難しい。

日付の計算という、みんなが分かっているようで、意外と知らなかったりする事例が見つかって良かったなぁって。

ちなみにあの実装が正しいのか?と言われると、これもまた微妙な気がしていて、現実に「2018年2月29日」は存在しないので、その存在しない日の前日って何だろう?みたいな気持ちにもなったりもしていて、果たして実際世の中ではどうやって実装されているんでしょうね。

なお、最初はPerlのTime::Pieceモジュールを使って書こうとしたところ、全然意図通りの挙動をしていなくて(ドキュメントも分かりづらい)、しばらくハマったので、結局Rubyで書きました。色々な言語の日付系のモジュール、なかなか挙動が分かりづらいですね。

スライドについて

4年もテックイベントを開催し続けているくせに、よく考えてみると人前で30分話すのが初めてで(吉祥寺.pmはおかげさまですぐに登壇者が埋まってしまうので…)、最初作ったスライドが140枚とかになってしまい、「果たしてこれは終わるのか…」という気持ちになりました。実際に少し最後を飛ばして28分だったので、もう少し余裕をもったページ数にすべきだったなって。

今更登壇初心者みたいな話になってアレですが、終わった後に一緒に登壇した@moznion氏にあのままアップしても伝わらないかも…とアドバイスを頂いたので、アップ用にまとめ直しました。

参考文献

今回のスライドを書くにあたって、初めて読んだ、又は久しぶりに読み直した本の数々です。どれも非常に学びのある本でした。

いかにして問題をとくか

いかにして問題をとくか

いかにして問題をとくか

知識創造企業

知識創造企業

知識創造企業

暗黙知の次元

暗黙知の次元 (ちくま学芸文庫)

暗黙知の次元 (ちくま学芸文庫)

ビジネスフレームワーク図鑑 すぐ使える問題解決・アイデア発想ツール70

ビジネスフレームワーク図鑑 すぐ使える問題解決・アイデア発想ツール70

ビジネスフレームワーク図鑑 すぐ使える問題解決・アイデア発想ツール70

UML モデリングのエッセンス

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

オブジェクト指向設計実践ガイド

エリック・エヴァンスのドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

実践ドメイン駆動設計

実践ドメイン駆動設計 (Object Oriented SELECTION)

実践ドメイン駆動設計 (Object Oriented SELECTION)

設計ナイトについて

ちなみに実は設計ナイトは今回が2回目の開催で、最初の開催のきっかけはこのツイートでした。

そして、ちょっと時間は空いてしまいましたが、今年の3月に「酔いどれ設計ナイト」と称して開催しました。

kichijojipm.connpass.com

この時も豪華な参加者の熱い設計トークが展開された訳ですが、居酒屋の片隅で開催していたイベントがこんな豪華なイベントになって帰ってくるとは…

おわりに

設計に関して話すイベント、マジで最高なのでみんながそれぞれの設計ナイトをやって欲しいですね。今回、50人の定員枠に250人以上の応募が有ったので、確実に需要は有ると思うんですよね。

そして、この勢いに乗って、今年の年末はぜひ「年忘れ!設計ナイト」をやりたいと思った次第です。 たぶん、ただの忘年会なんですけど(フラグ)。

最後に、こんな最高のイベントを用意してくださった、しんぺいさん、Classiさん、本当にありがとうございました!感謝しかないです!