rddd 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rddd (0.1.1)
4
+ rddd (0.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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 (MVC framework)
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 elements
14
+ ## Basic architecture
15
15
 
16
- As defined in DDD itself, framework has couple basic object types:
16
+ ![Architecture overview](https://github.com/petrjanda/rddd/blob/master/documentation/rddd.png?raw=true)
17
17
 
18
- * Services - use cases
19
- * Entities - domain objects with identity
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
- ## Project structure
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
@@ -5,7 +5,7 @@ class Rddd::Entity
5
5
  @id = id
6
6
  end
7
7
 
8
- def ==(b)
9
- @id == b.id
8
+ def ==(other)
9
+ @id == other.id
10
10
  end
11
11
  end
@@ -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 execute(service_name, attributes = {})
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?
@@ -11,7 +11,7 @@ module Rddd
11
11
 
12
12
  def self.camel_case(string)
13
13
  return string if string !~ /_/ && string =~ /[A-Z]+.*/
14
- string.split('_').map{|e| e.capitalize}.join
14
+ string.split('_').map{|token| token.capitalize}.join
15
15
  end
16
16
  end
17
17
  end
@@ -1,3 +1,3 @@
1
1
  module Rddd
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -27,7 +27,7 @@ class ProjectsController
27
27
  include Rddd::ServiceBus
28
28
 
29
29
  def create(params)
30
- execute(:create_project, params)
30
+ execute_service(:create_project, params)
31
31
  end
32
32
  end
33
33
 
@@ -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 '.execute' do
12
- subject { controller.execute(:foo, attributes) }
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.execute(:foo, attributes, &error_block)
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.2
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