DDD

こんにちは、僕です。 実はチーム内で技術ブログを書きあおうと始まったこの企画なのですが、既に8記事書いているにも関わらず「技術ブログ」としては認められずに困っています。

DDDとは何か

さて、皆さんから「Layered Architectureは理解出来たがDDDが良くわからない」という質問を多く頂きました。 DDDって何だか気になりますよね。そこで早速DDDについて解説してゆきたいと思います。

結論から述べると、DDDとは Domain Driven Designの略だそうです。僕もさっき知りました。 では Domainとは何なのか。皆さんも御存知の通り、google.com, yahoo.co.jp的なアレです。

つまり、これら Domain(ドメイン)をベースに設計(デザイン)すれば DDDは完成です。

DDDの何が良いのか

Domainをベースに設計しているのだから、その設計は世界中で重複することなく独自のものになります。 その代わりに独自ドメインを取るのだからお金も掛かってしまいます。DDDはタダではないのです。

  • DDDは有償である

そこで、DDDの総本山とも言うべきお名前.comに立ち寄ってお安いDomainを探すことから始めましょう。

https://www.onamae.com/

現時点でドメインの登録料を確認すると以下の様になっています。

com: 1160円 jp: 2840円 net: 1160円 biz: 299円 info: 99円 work: 1円 xyz: 30円

DDDは .workドメインが最適

どうやらコスト面から技術選定すると、DDDには workが良い様です。コスト面を疎かにするエンジニアは一流とはいえませんよね。なので DDDには workを用います。

Kotlinの場合は、ドメインを逆さにしたものをパッケージ名にしますので、パッケージ名に取得したドメインを記載します。例えば取得したドメインが xxx.workであればimport work.xxx...形式となります。

結論

結論としては 独自ドメインで始まるパッケージ構成で設計されたシステムが DDD準拠。特に work.xxx...で始まるプログラムはコストを意識した DDD準拠と言えそうです。

では、ごきげんよう

Kotlinで Layered Architecture

概要

Layered Architectureとは、よく分かりませんが、DDD的なアレです。 詳細は DDDに聞いて下さい。

実装方法

要するに Layerを作成すれば良い訳です。Layerとは層です。地層とか断層とかいうアレです。 層を使ったアーキテクチャが Layeredアーキテクチャという理解で間違いないでしょう。

そのアーキテクチャを適用して、鏡餅を描画するプログラムを書いてみました。 引数の数値を変えると段数も変わるようにしてあります。

operator fun String.times(n: Int): String = (1..n).fold("", {a, _ -> a + this})
fun String.padBoth(n: Int, padChar: String = " "): String = (padChar * n) + this + (padChar * n)

data class Mochi(private val layer: Int = 1) {

    override fun toString(): String {
        val base = "${"◯".padBoth(layer)}$LINE_SEP"
        return (1 until layer).fold(base, {a, n ->
            "$a${ ("(" + ("__" * n) + ")").padBoth(layer - n)}$LINE_SEP"
        })
    }

    companion object {
        val LINE_SEP: String = System.lineSeparator()
    }
}
fun main(args: Array<String>) {
    println(Mochi(3))
    println(Mochi(5))
}
   ◯   
  (__)  
 (____) 

     ◯     
    (__)    
   (____)   
  (______)  
 (________) 

Layered アーキテクチャが理解できたでしょうか? では、ごきげんよう

バナナチップス

電車止まってるやん 

ダラダラ仕事して帰宅しようとしたら人身事故が発生して帰るに帰れない僕です。頭にきたのでブログを書くズラ。

えーと何だっけ、こんなコードでしたよね。

val aIsB = {a: String -> {b: String -> "${a}${b}" }}
val bananaIs = aIsB("バナナ")

println(bananaIs("うまい"))
println(bananaIs("にがい"))
println(bananaIs("あまずっぱい"))
println(bananaIs("げろまずい"))

はい、完璧です。 しかし意識の高い人に言わせるとコードに重複が多いらしい。 重複なんて多いほうが記憶に残って良い筈ですが、意識の高い人はその辺の意識が低いんでしょう。

重複を許さないという考え方はDRY原則と呼ばれいるそうです。 何が乾いているんだか分かりませんが、乾かせばいいということでしょうか。

カラッカラやねん

因みにバナナが乾くとバナナチップスになります。バナナチップスは美味いです。 「バナナチップスの様に旨味を出したいから乾かすんだよ」と説明してくれれば理解もできますが、 DRY信者は説明能力的にはアレなんでしょう。

という訳で、重複を減らしてゆきます。 どうやってやれば良いか分からないので、先日の分かってそうな人を脅してに協力を仰いで書いてもらいました。

val aIsB = {a: String -> {b: String -> "${a}${b}" }}
val bananaIs = aIsB("バナナ")

listOf("うまい","にがい","あまずっぱい","げろまずい")
        .map(bananaIs)
        .forEach(::println)

どうやって動いているのかは分かりませんが、コードの量は減りました。 仕組みもよく分からないので一見さんがコードを見てもわけが分かりません。 そういう意味でセキュリティ的には良さそうです。

バナナはうまい
バナナはにがい
バナナはあまずっぱい
バナナはげろまずい

で、結果を出力してみたけど変わりません。
結論:意識が高くてもアウトプットは変わらない

今宵はこのへんでよかろうかい。ではごきげんよう

バナナの味で関数を味わう

こんにちは、Kotlinとバナナで関数を学ぶ時間がやってきました。 司会の僕です。

さて、先日こんなクソコードを書きました。

var sIsC = {s: String, c: String -> "${s}${c}"}

println(sIsC("スイカ", "うまい"))
println(sIsC("ゴリラ", "にがい"))

この関数を使うと主語も述語も変更できてしまいます。 しかし、当面バナナの味わいだけに着目してみると俄然うっとおしくなります。

println(sIsC("バナナ", "うまい"))
println(sIsC("バナナ", "にがい"))
println(sIsC("バナナ", "あまずっぱい"))
println(sIsC("バナナ", "げろまずい"))

バナナバナナうるせぇよ。とそういう沸点の低い貴方はどうすればいいのか? 僕はよくわからなかったので知ってる人に聞きました。

知らないことは他人に聞くに限ります。 そして出来るのであれば、その場でやってもらうのがベストです。 聞いてしまうと理解しないといけませんが、やってもらえば理解する手間が省けます。

我々、怠け者にとって魚の釣り方なんてどうでもいいのです。魚をよこせ。

という訳で、脅して頼み込んで書いてもらったのが次のコードです。

val aIsB = {a: String -> {b: String -> "${a}${b}" }}
val bananaIs = aIsB("バナナ")

println(bananaIs("うまい"))
println(bananaIs("にがい"))
println(bananaIs("あまずっぱい"))
println(bananaIs("げろまずい"))
バナナはうまい
バナナはにがい
バナナはあまずっぱい
バナナはげろまずい

まぁ色々あったけど実行結果は変わりませんね。要するにどっちでも良かったって事です。

関数はバナナだけなのか

Not only バナナ

こんにちは、今までバナナを元に色々と説明をしてきましたが、バナナに偏り過ぎな気がしてきました。 世の中の人全員がバナナに興味があるというのは僕の思い込みかも知れません。

そうと決まれば話は早く、バナナ以外も受け付けるコードに直さないといきません。善は急げです。 元々バナナ限定だったものを更新します。

var banana = {x: String -> "バナナは$x"}
var sIsC = {s: String, c: String -> "${s}${c}"}

println(sIsC("スイカ", "うまい"))
println(sIsC("ゴリラ", "にがい"))

But also スイカ と ゴリラ

これを実行してみると。。

スイカはうまい
ゴリラはにがい

おおぉ、上手く出力されました。 バナナに限った話ではなく、何の味でも躊躇なく表現することが可能になりました。

加えてゴリラの味が苦いこともわかりました。テクノロジーの力って凄いですね。 ではまた次回、ごきげんよう

関数

先程知人からの指摘がありました。
曰く「変数、定数と明確な説明があるのに、関数の説明が無いのはブログとして勿体ない」

なるほど、そのとおりです。僕もウッカリしていました。

最近は関数型プログラミングという流派も存在すると聞きます。察するに関数だけを使ってプログラムを書くという流派なのでしょう。変わった輩です。

とはいえ技術ブログとしては関数を疎かにする訳にはいかんでしょう。なので説明します。

関数の宣言はこんな感じでやります。

val banana = { x:String -> "バナナは$x" }

そんで使う時はこんな感じです

println(banana("うまい"))
println(banana("まずい"))

出力としてはこうなります。

バナナはうまい
バナナはまずい

関数を使うことで、バナナがうまいのかまずいのかを後から決められる様になりました。宣言時の決断は不要です。

要するに関数とは即決力に欠ける人々が使う即断回避ソリューションの様です。

なるほど、また理解が深まりましたね。

コンパイルエラーって何?

ブログがバズって困ってますが、頑張って続きを書いています。

前回の記事にコンパイルエラーが発生したと書きましたが、コンパイルエラーって何でしょうか? 自分でも良く分かっていなかったので、詳しい人に話を聞いてみました。

有識者のお話

結論から言うと、コンパイルエラーとはコンパイル時のエラーだそうです。 そしてコレが起こると先に進まないらしいです。

そして新事実が発覚しました。どうやら valコンパイルエラーを起こすためのものではなく、定数を宣言するものらしいです。 定数というのは、一度値を設定すると後から変更できないという恐ろしい仕組みです。

恐怖のKotlin

つまりvalは後戻り出来ない緊張感を醸し出したい時に使うもの。僕はそう理解しました。 コンパイルエラーも怖いですが、定数も怖い。前にも進めないし後戻りもできない。 Kotlinの闇は深そうです。

さっそく暗中模索ですが、これからも頑張ってブログを書いていこうと思います。

では、ごきげんよう