DDDっておいしいの?設計から実装まで
DDDってなに?
Domain-Driven Design
ドメイン駆動設計です。
Domainって?
google.co.jp
違います!
Domainとは
「知識、影響力、活動の一領域」
よくある参考
飛行機の運航制御のドメイン
「飛行機の運航制御には、出発地と目的地
は航路の始点と終点がある。
航路は出発地と発着地に関連する」
ユビキタス言語
このドメインから、
開発者とドメイン知識をもつ人(ユーザ、専門家等)
との間に共通言語を定義する
「始点(DeparturePoint)」
「終点(ArrivalPoint)」
「航路(Course)」
ユビキタス言語を使って会話してみる
ユビキタス言語を使うと
ドメインモデルと実装コードがきちんと対応付けられるようになる。
見えないものが見えてくる。
設計
ドメインモデルの設計を使うと
色々なところから呼ばれても、
常にドメイン層では同じことが行われるので、
関係なく使いまわせる。
Springでサンプル
レイヤー分割
こうやって切り分けることで、別にドメイン部分ではドメインのことだけ考えられる様にする。
サービスによってドメイン内部をブラックボックス化
サービスを介してモデルを使うことで、インターフェース側はモデルのことを
知らなくていい。
リポジトリをつかってデータベースとモデルを切り離す
DBの値とかどう入っているかはモデルは知らない。
リポジトリさんがんばれ!
ドメインモデルの実装を使うと
それぞれのレイヤーで依存していないので、
があればサーバー上から呼ばなくても値は担保できる。
結論:おいしいポイント
ユビキタス言語を使ったコードの現実化
専門家にしか見えないものが見えてくる
レイヤー分けされた設計による可用性
いろんな所から同じ処理を呼び出せる
レイヤー分けされた実装による安全性
テストが描きやすい
フレームワークの載せ替えも簡単
詳しく勉強される方はこちらで
ReactでStateとPropsをちゃんと使ってみる
前回の記事でReactが使える環境は作ったので、
まずはStateとPropsをちゃんと使ってリストを作ってみる。
ListBaseにStateを持たせて、
ListにPropsとして渡して、
ListRecordを描写してみようかなと。
StateとPropsについて
State
- そのコンポーネントが持っている状態
- mutable data (可変のデータ)
- maintained by component (コンポーネントによって保持)
- should be considered private (プライベートであるべき)
this.setState({state1: "value1",state2: "value2"});
のようにコンポーネント作成後任意のタイミングで入れられる。
初期値は
this.state = {state1: "value1",state2: "value2"}
こんな感じで入れてもいい。
Props
- 親コンポーネントから渡されたプロパティ
- immutable data (不変のデータ)
- passed in from parent (親から渡される)
- can be defaulted & validated (デフォルト値の設定と検証が可能)
<Component props1="value1" props2="value2">
のようにコンポーネント作成時に入れられる。
作ってみた
構成は前回と同じ。
こんな感じ。
最初の呼び出し元としてapp.jsxを作る。
前回はindex.html内でrenderを呼んでいたが、
app.jsx自体にやらせることにした。
app.jsx
なので、webpack.config.jsは、app.jsxをベースとしてapp.jsを作る様に
webpack.config.js
なので、index.htmlはapp.jsを呼び出すだけ。
index.html
ここからはさくっと。
呼び出されるListBaseコンポーネントはStateデータをコンストラクターで持ち、
として子コンポーネントに渡すだけ。
listbase.jsx
渡されたdataを、
Listコンポーネント内でループしてListRecordコンポーネントをdataの数だけ生成する。
listrecord.js
で、最終的にListRecordがPropsを描写する。
listrecord.jsx
npm run webpack -pして、
index.htmlを表示してみる!
1:tanaka
2:yoshida
おお!表示された。
PropsはImmutableなので、値を変える時はListBase自体で
setStateし直すということか。
それで、
keyを比較して変更のあったものを再描写してる感じかな。
(最初keyがなくて怒られた苦笑)
うん、なんとなくだけどわかってきた。
ES6で書くとfunction(){}とかなくてJSっぽくなくていい!
DebugしにくいからReactDevTool入れてちゃんとサーバー上で動かした方がいいな。
あとコンポーネントとして、
こうやってマイクロな感じで作ったコンポーネントを組み合わせて呼び出して、
全部JSじゃなくて必要なところだけコンポーネントを埋め込んでリッチにする方が、
DOM全部管理するより開発しやすいんじゃないかなーと思った。
ここまでやって、次はFluxとかでのデータフロー管理なわけかな。
ちょっとずつ進んでる感。
React+Babel+WebpackでHTMLにリストを書いてみた。
作ってみるもの
WebでReactの動的サイトを作るのを目標にとりあえず今回は、
React、Babel、Webpackを使って
普通のリストを作ることにしようかと。
もろもろのバージョンは下記
node:7.6.0
npm :4.4.4
React:15.4.2
Babel:6系
Webpack:2.2.1
Reactとは
Facebookが作っているJSのView部分だけのライブラリ
詳しくは本家を。
現在バージョンは15で、初期と大分変わっているので、記事を参考にする際はお気をつけください。
Babelとは
「BabelはブラウザにまだサポートされていないようなJavaScriptの次世代の標準機能を、現在のブラウザでも使えるようにするNode.js製のトランスパイラ。」
要はJSのコンパイラと考えていただければ。
ECMAScript(JavaScript の標準試用)準拠なのがいいところ。
Webpackとは
設定ファイルを書けば、依存関係を解消し、
ビルドしてくれるツール(つまりコンパイラ)です。
さっそく作ってみよう!
とりあえず今回は、
React、Babel、Webpackを使って
特に動かないリストを作ることにしようかと。
とりあえず動くものはFluxとか使ってからで。
まずは作業用ディレクトリでnpmで初期化して必要なものをインストール
※Babel6になりパッケージの分離が行われ、
必要なもののみインストールする必要あります。
このままじゃ使いづらいので
package.jsにwebpackコマンドを登録
これでnpm run webpackでwebpackが使えるようになります。
とはいえwebpackが何をするかの設定ファイルが必要なので、
下記を用意します。
※これもBabel6の影響でloaderがbabel-loaderになっています。
webpack.config.js
./publicに、entryでキーに指定した名前の[name].jsが書き出されます。
こうしておけば複数も可能です。
JSは今回はメインの呼び出しとリスト自体の2つ
app.js
list.js
こっちは今回は適当。
で、肝心のHTMLですが。
index.html
これだけ。
最後に
すると、publicディレクトリにapp.jsが出来ているので、
ブラウザからhtmlを開いてみると普通にリストが表示されます。
(ただのリストなので画像は貼りませんが苦笑)
まとめ
とりあえず入門したかなと。
ここから、FluxかRedux使ってデータ持たせたり、
ちゃんとコンポーネント設計したり、
axiosとか使ってAPI呼んでデータ取ってきたり。
お砂場はできれども道は遠き。
SpringのUTにDBSetupを使ってみたら良かった
はじまり
DBのテスト、できればきれいに書きたい。
ということで
- insert文とかベタ書き : なんか嫌だ
- DBUnit : 使ったことはあるけど、ファイル参照嫌だ
- オレオレUtil : 再利用性がない!
ということで、DBSetupというのを見つけた。
データは「流れるようなインタフェース(Fluent Interface)」で作成する。
この一文に惚れたからだ。
自分の環境
- spring-boot
- JPARepository
- JUnit4
これに合うようにやってみた。
テストされる側
単にデータを全部返すだけのメソッド
@Service
@Transactional
public class MyDataService {
@Autowired
MyDataRepository myDataRepository;
public List<MyData> findAll() {
return myDataRepository.findAll(new Sort(Sort.Direction.ASC, "id"));
}
}
使ってみた
とりあえずversion2.0をimport
pom.xml
<!-- https://mvnrepository.com/artifact/com.ninja-squad/DbSetup -->
<dependency>
<groupId>com.ninja-squad</groupId>
<artifactId>DbSetup</artifactId>
<version>2.0.0</version>
</dependency>
SpringBootはテスト時はtest/resources/application.propertiesがあったらそちらを読み込むので作成。
spring.datasource.url=jdbc:mysql://192.168.33.10/mytestdatabase
spring.datasource.username=testuser
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
これで通常環境は汚染されない。
DataSourceどうやってとってくるかで迷ったけど、普通に@Autowireで
DataSouce取ればテスト用のDataSouceが入ってた。
@RunWith(SpringRunner.class)
@SpringBootTest
この辺のDIのおかげかな。
あとは、データの定義、これがカッコイイ!!!
クラス内にデータがどうなっているか収まるのでDBUnitよりも読みやすい!!!
public static final Operation DELETE_ALL =
Operations.deleteAllFrom("mydata");
public static final Operation INSERT =
Operations.insertInto("mydata")
.columns("id", "name")
.values("1","Tanaka")
.values("2","Yoshida")
.values("3","Suzuki")
.build();
で、Beforeでデータをセットしてやると。
@Before
public void before(){
Destination dest = new DataSourceDestination(dataSource);
Operation ops = Operations.sequenceOf(DELETE_ALL, INSERT);
DbSetup dbSetup = new DbSetup(dest, ops);
dbSetup.launch();
}
sequenceOfで生成したOperationを繋げられるので楽!
あとは普通にテストすれば
@Autowired
MyDataService myDataService;
@Test
public void canFindAll() throws Exception {
List<MyData> myData = myDataService.findAll();
assertThat(myData.get(0).getId(),is(1));
assertThat(myData.get(0).getName(),is("Tanaka"));
}
オールグリーン!!!
まぁ、使ってみたかっただけのテストなんで、テスト自体は雑ですが。
なんて素敵なんだろう。この流れるようなインターフェース。
もうDBUnitのことなんて忘れよう!
DBのテストをこれで切り出して、
その部分がテストされていればあとはMockitoとかでMockすればいいし。
うん、なんか結局惚れた!
SpringBoot,Thymeleaf,JpaRepositoryで基本構成を作ってみた
あけましておめでとうございます!
SpringBoot、前から気になるなぁと思っていたので、
年末にちょこっと触ってみた。
SpringBootとはとかはハショリます。
今年は週1ぐらいでブログ書きたいなぁと。勉強するために!
とりあえずmavenで必要なものを突っ込んでみる
STS(簡単にSpringBootを開発するツール)もあるけど、
おもしろくないのでInteliJでmavenプロジェクトを作成して
必要なものだけ全部突っ込んでみる。
必要な物
- spring-boot-starter-parent: SpringBootのベース
- spring-boot-starter-web
- spring-boot-starter-thymeleaf: Thymeleafが使いたかった!
- spring-boot-starter-data-jpa: 結局裏ではhibernate使ってるけど
- mysql-connector-java: MySQLは適当にVagrantで建てた
- lombok: あるとJpaRepository使いやすかった
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
まずは起動用ファイル
SpringBootはサーバーを内包していて、mainから走らせれば起動するので、
これだけ書けばとりあえずサーバーが起動する。
なんとなく名前はBootにしてみた。起動しそうだからb
@SpringBootApplication
public class Boot {
public static void main(String[] args) {
SpringApplication.run(Boot.class, args);
}
}
Thymeleafを組み合わせてみる
resources/templatesにhtmlファイルを設置
index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>top page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
test
<p th:text="${msg}" />
</body>
</html>
コントローラーがその名前を返せばいいだけ。
今回はindex.htmlとしたのでこんな感じ。
@Controller
@RequestMapping("/")
public class IndexController {
public String index(Model model) {
model.addAttribute("msg","Hello Spring Boot");
return "index";
}
}
簡単すぎる!
これでBootを走らせるともうlocalhost:8080で見れる!
早すぎる!
Jpa Repositoryを使ってみる
まずは必要なデータベース!!!
データベース名:mydatabase
テーブル名:mytable
として作って適当にデータを突っ込んでみる。
次に
resources/application.properties
を作ってアクセスできる様に下記を記載する
spring.datasource.url=jdbc:mysql://192.168.33.10/mydatabase
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
がないと、
org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
で悩まされた。。。
あとは簡単!
Entityを用意する
@Entity
@Data
@Table(name = "mydata")
public class MyData {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;
}
JpaRepositoryのinterfaceを用意する。
だいたいのメソッドがデフォルトで用意されている。
@Repository
public interface MyDataRepository extends JpaRepository<MyData, Integer> {
}
Repositoryの実装としてServiceを作る。
AutowiredとかはSpring DIの基本なので説明飛ばします!
@Service
@Transactional
public class MyDataService {
@Autowired
MyDataRepository myDataRepository;
public List<MyData> findAll() {
return myDataRepository.findAll(new Sort(Sort.Direction.ASC, "id"));
}
}
最後にThymeleafに送っていたデータをDBからServiceを使って取得。
MyDataにtoStringが実装されてるから取得した値をそのまま出してみる。(雑)
@Controller
@RequestMapping("/")
public class IndexController {
@Autowired
MyDataService myDataService;
@RequestMapping(method = RequestMethod.GET)
public String index(Model model) {
List<MyData> myDataList = myDataService.findAll();
model.addAttribute("msg", myDataList.get(0));
return "index";
}
}
そして走らせる。
無事成功!
ほとんど引っかかるところはなく簡単にできたのがすごい!
環境構築もいらないし。
でも、楽だけど、中身をちゃんと知らないといけないなぁと思った。
まぁ、とりあえずベース環境として使って、
勉強しながら気分次第でmavenのimport方法変えていけばいいかなと。
YAGNIということで。
これをベースに何作るかは全然考えてない。。。
デブサミ関西2016に行ってきた
Developers Summit 2016 KANSAI #devsumi
デブサミ関西に行ってきたので感想をまとめ。
なぜか基調講演が1番おもしろかったのでとりあえずそれだけ紹介。
基調講演
鈴木雄介さん
グロースエクスパートナーズ執行役員
日本Javaユーザーグループ会長
クラウドって仮想サーバーのことだけじゃないよね
1.インフラの仮想化 IaaS
仮想インフラによってインフラを所有から利用へ。
2.ミドルウェアの仮想化 PaaS
AWS RDSみたいにミドルウェアもその部分だけを利用できる。
データベースサーバーを借りるのではなくデータベースサービスを借りる。
バックアップとかクラスタかも考えなくていいはず。
その為に積極的にプラットフォームの制約は受け入れる!
フレームワークのように、あと何年かするとそれが当たり前になると。
3.システム構成のコード化
ChefとかAnsibleみたいなの。
それら3つが揃って本当にクラウドだよねって話だった。
IaaSだけではクラウドと言えのるか?というのがおもしろかった。
企画→開発→運用 がクラウドの方が早い!
クラウドの進化の紹介
2001年:アジャイルソフトウェア開発宣言
「企画→開発」の効率化
2006年:クラウド
2009年:DevOps
「開発→運用」の効率化
データセンターの移行にスクラムを導入したところから。
変更と安定稼働は相反する
DevOpsというよりOpsをなくすって考えっていう話がおもしろいw
2010年:多様なリリース方法
ブルーグリーンデプロイメント
本番環境を2つ用意して切り替えるやり方。
カナリアリリース
一部のユーザーだけに特定のバージョンを提供する。
って、やってたけどそんな呼び方するって知らなかった。
2012年:カオスモンキー
NetFlixが使っている。
本番環境をランダムにダウンさせる製品。
インフラの自動化のテストをするため、
自動復旧を観測する。
まじか!データセンターまるごと落とすとかもするらしい。
2014年:マイクロサービスアーキテクチャ
大事だよなぁ。影響範囲を減らすの。
システム全体を単一の構成で作ると技術の切れ目でチームを構成しがち。
(コンウェイの法則)
それに対して、システムをサービス同士の連携で実現する。
サービスレベルでチームを構成する。
APIさえ変わらなければいい。
だからアジャイルがやりやすい。
あと、MSAに再構築は愚か!今から始められる。
少しずつ取り入れるのを始めるべきってのには共感した。
確かにちょっとずつ切り出していくのが1番良さそう。
そして、ここでドメインモデルが出てくる。
業務領域で分ける。正解はない。。。難しいよねDDD。
全てはアジャイルからはじまった。
「この年表のどの時点にみなさんはいますか?」
って言うのがカッコ良かった。
クラウド時代のデベロッパー
アプリとインフラは不可分に。両方コード化している。
何をコーディングして何をコーディングしないのか。
システム開発からサービス運営へ
企画→開発→運用の全てでエンジニア!!!
スペシャリスト:特定領域の専門家
ジェネラリスト:専門家を繋いで価値に繋げる
どちらを目指すか、戦略を考えて先へ進んで行かないといけない。
ビジネスの中心にエンジニアがある。
エンジニアにもコミュニケーション、プレゼン、チームビルディング能力が必要。
特にジェネラリストに必要。
個人でシステムをつくり上げるのは不可能に近い。
スキルを縦か横に拡げるという話だった。
この話にはすごい悩まされた。
自分のスキルはどっちかというといつも横に広がっていっているな。
どっちかというとジェネラリスト向きなんだろうなと思った。
しゃべるのも好きだし。その方向だとそういう方向にどう拡げるか
考えないとなー。
phpとslim3で汎用掲示板を作ってみた
ふとしたきっかけからphpのslim3を使って汎用掲示板を作ってみました。
ライセンス表記とか全然してないけどオープンソースなので、
プルリクもらえると嬉しいですw
Slim3について
Slim Framework - Slim Framework
ORマッパーとか機能は全然ついてなく、
後からComposerでvendorに追加していく感じ。
CakePHPみたいに規則も厳しくなく、設定ファイルも簡単なので、
いろいろ組み合わせて作っていくと案外いいかなと。
ただ、リクエストをさばくのがroutes.phpだけなので、
機能が増えるとこれがかさばって可読性下がりそう。
routes.phpから完全にそれぞれのページのパラメーター関係のロジックを
抜き出して、そこに全部渡せばすっきりするかな?
今回の構成について
- FrameWork
http://www.slimframework.com/ - bootstrap3
http://getbootstrap.com/components/ - DB
http://phpocean.com/tutorials/back-end/workouts-with-slim-3-database-with-pdo-and-eloquent/51 - VALIDATION
http://respect.github.io/Validation/docs/install.html - CSRF
http://log.deprode.net/logs/2015-10-01/
こんな感じで、バリデーションとCSRFはComposerでありものを突っ込んだ。
やっぱり車輪の再開発はしたくない。
で、routes.phpではそういったパラメーターの処理だけさせて、
あとはapp/src/usecaseの中のロジックでDBとかの処理をしている感じ。
これだけでローカル試せます
実はscotch-box(LAMPのvagrant box)を入れているので、
vagrantとvirtual boxがインストールしてあれば、
cloneしてvagrant up、
MySQLでddl.sqlのユーザー作成とテーブル作成をして、
Document Rootを/public(index.php)があるにすれば動くはず。
PHPで開発するならローカルのエディター使いながら随時確認できる
scotch-boxおすすめ!
Scotch Box ♥ A Vagrant LAMP Stack That Just Works
TODO:やりたい、やりたかったこと
- ほんとはDDDで作りたかったので、
時間があったらusecaseからmodelとrepositoryを切り出して、
もっと柔軟性を持たせたいかな。
- DIとnamespaceを適当にやってしまった所をちゃんと定義
したいかなと。
- エラーハンドリングとかトランザクションが適当なので、
もっとしっかりしたいなと。usecase内でトランザクションがはれる様なイメージ。
まとめ
Slim3自体は簡単かつすっきりとした小規模システムをつくりたい、
リクエストのハンドリングとテンプレートエンジンとかだけ使えれば十分。
あと、そういった作りにしておいてロジックを分離することで、
今後フレームワーク間の載せ替えや
バージョンアップも簡単になるんじゃないかなと。