rddd 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +86 -11
- data/documentation/rddd.png +0 -0
- data/lib/rddd/entity.rb +2 -2
- data/lib/rddd/service_bus.rb +1 -1
- data/lib/rddd/service_factory.rb +1 -1
- data/lib/rddd/version.rb +1 -1
- data/spec/integration_spec.rb +1 -1
- data/spec/lib/service_bus_spec.rb +3 -3
- metadata +2 -1
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,28 +8,103 @@ Intention of rddd is to provide basic skeleton for DDD ruby application. Its fra
|
|
8
8
|
## Key goals
|
9
9
|
|
10
10
|
* Provide basic DDD elements
|
11
|
-
* Support separation of domain from delivery mechanism (
|
11
|
+
* Support separation of domain from delivery mechanism (mostly web framework such Rails or Sinatra)
|
12
12
|
* Support separation of domain from persistancy mechanism
|
13
13
|
|
14
|
-
## Basic
|
14
|
+
## Basic architecture
|
15
15
|
|
16
|
-
|
16
|
+
![Architecture overview](https://github.com/petrjanda/rddd/blob/master/documentation/rddd.png?raw=true)
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
* Aggregate roots - entities roots to setup consistency boundaries
|
21
|
-
* Repositories - abstraction over persistancy providing collections of aggregate roots
|
22
|
-
|
23
|
-
Alongside core DDD object types, there is couple supporting ones, mostly factories.
|
18
|
+
There are two major entry points to the domain layer from the delivery mechanism. Service bus, for a command execution and
|
19
|
+
Presenter factory, to build up the presented business data (views / reports).
|
24
20
|
|
25
21
|
### Service bus
|
26
22
|
|
27
23
|
To further enhance the separation of delivery mechanism and domain from each other, every call to the domain service is done through the ```Service bus```. The key design goal is to decouple concrete service implementation from the non-domain code, so they never have to be directly instantiated outside the domain itself. Instead, service bus defines simple protocol for any object, which can call its ```execute``` method with service name and parameters. The instantiation of the service object then becomes implementation detail of domain code, thus leaves the flexibility for alternative solutions within domain.
|
28
24
|
|
29
|
-
|
25
|
+
In Rails application, it might look like:
|
26
|
+
|
27
|
+
class ProjectsController < ApplicationController
|
28
|
+
include ServiceBus
|
29
|
+
|
30
|
+
def create
|
31
|
+
execute(:create_project, params) do |errors|
|
32
|
+
render :new, :errors => errors
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
redirect_to projects_path, :notice => 'Project was successfully created!'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
### Presenter factory
|
41
|
+
|
42
|
+
We dont wanna DM (Delivery mechanism) know too much about domain implementation internals. Neither about specific presenter classes. We apply same approach as for Service bus and define simple interface to load a specific view.
|
43
|
+
|
44
|
+
In Rails application, it might be used as:
|
45
|
+
|
46
|
+
class ProjectsController < ApplicationController
|
47
|
+
def index
|
48
|
+
PresenterFactory.build(:projects_by_account, :account_id => params[:account_id])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
### Services
|
53
|
+
|
54
|
+
Service is the object to represent a single use case. Its responsibility is to orchestrate the cooperation of multiple aggregate roots (and entities), in a given order defined by use case.
|
55
|
+
|
56
|
+
Service takes a list of attributes, which are necessary to execute the given use case. At the end nothing is returned, so service represent the command to the domain and doesn't return any data back. Therefore, client code should construct and pass all the data for the given use case and keep them, so it doesn't have to use presenters to load the result of the operation back.
|
57
|
+
|
58
|
+
### Presenters
|
59
|
+
|
60
|
+
Presenter is the view to the domain data, which is typically aggregation over multiple aggregate roots and entities. In other
|
61
|
+
language presenter is report. In Rddd, views output plain Ruby hashes, thus no domain object is leaking outside the domain
|
62
|
+
itself. The key design goal was to dont let framework later call any additional adhoc methods. Thats why framework doesn't interact with view object directly and pure Hash is returned back.
|
63
|
+
|
64
|
+
### Aggregate root, entity, repository
|
65
|
+
|
66
|
+
TBA
|
67
|
+
|
68
|
+
## Planned features
|
69
|
+
|
70
|
+
* Asynchronous notifications from services - Services might be executed synchronous but also asynchronous way. Simple extension of Service bus would do the trick (add ```execute_async``` method). Its a common case that client code might
|
71
|
+
be waiting for the result from background job execution so it can talk back to user. There is a plan to add ```Notifier``` interface, which would be available during service execution. This interface should get concrete implementation within delivery mechanism (websockets, ...).
|
72
|
+
|
73
|
+
## Project file structure
|
30
74
|
|
31
75
|
Recommented project file structure:
|
32
76
|
|
33
77
|
app/entities
|
34
78
|
app/repositories
|
35
|
-
app/services
|
79
|
+
app/services
|
80
|
+
|
81
|
+
## Author(s)
|
82
|
+
|
83
|
+
* Petr Janda ([petr@ngneers.com](mailto:petr@ngneers.com))
|
84
|
+
|
85
|
+
Wanna participate? Drop me a line.
|
86
|
+
|
87
|
+
## License
|
88
|
+
|
89
|
+
Copyright (c) 2012 Petr Janda
|
90
|
+
|
91
|
+
MIT License
|
92
|
+
|
93
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
94
|
+
a copy of this software and associated documentation files (the
|
95
|
+
"Software"), to deal in the Software without restriction, including
|
96
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
97
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
98
|
+
permit persons to whom the Software is furnished to do so, subject to
|
99
|
+
the following conditions:
|
100
|
+
|
101
|
+
The above copyright notice and this permission notice shall be
|
102
|
+
included in all copies or substantial portions of the Software.
|
103
|
+
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
105
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
106
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
107
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
108
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
109
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
110
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Binary file
|
data/lib/rddd/entity.rb
CHANGED
data/lib/rddd/service_bus.rb
CHANGED
@@ -40,7 +40,7 @@ module Rddd
|
|
40
40
|
# @param {Hash} Attributes to be passed to the service call.
|
41
41
|
# @param {Block} Optional error callback block.
|
42
42
|
#
|
43
|
-
def
|
43
|
+
def execute_service(service_name, attributes = {})
|
44
44
|
raise InvalidService unless service = build_service(service_name, attributes)
|
45
45
|
|
46
46
|
unless service.valid?
|
data/lib/rddd/service_factory.rb
CHANGED
data/lib/rddd/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -8,8 +8,8 @@ describe Rddd::ServiceBus do
|
|
8
8
|
stub('controller').tap { |controller| controller.extend Rddd::ServiceBus }
|
9
9
|
end
|
10
10
|
|
11
|
-
describe '.
|
12
|
-
subject { controller.
|
11
|
+
describe '.execute_service' do
|
12
|
+
subject { controller.execute_service(:foo, attributes) }
|
13
13
|
|
14
14
|
let(:service) { stub('service', :valid? => true, :execute => nil) }
|
15
15
|
|
@@ -57,7 +57,7 @@ describe Rddd::ServiceBus do
|
|
57
57
|
Rddd::ServiceFactory.expects(:build).with(:foo, attributes).returns(service)
|
58
58
|
service.expects(:execute).never
|
59
59
|
|
60
|
-
controller.
|
60
|
+
controller.execute_service(:foo, attributes, &error_block)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rddd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- LICENSE.txt
|
27
27
|
- README.md
|
28
28
|
- Rakefile
|
29
|
+
- documentation/rddd.png
|
29
30
|
- lib/rddd.rb
|
30
31
|
- lib/rddd/aggregate_root.rb
|
31
32
|
- lib/rddd/aggregate_root_finders.rb
|