I have the code as follow :
class Synchronization
def initialize
end
def perform
detect_outdated_documents
update_documents
end
private
attr_reader :documents
def detect_outdated_documents
@documents = DetectOutdatedDocument.new.perform
end
def update_documents
UpdateOutdatedDocument.new(documents).perform
end
@documents
is an array of Hashes I return from a method in DetectOutdatedDocument
.
I then use this array of Hash to initialize the UpdateOutdatedDocument
class and run the perform method.
Is something like this correct? Or should I use associations or something else?
I'm not a Ruby expert, but what I understand from your snippet given its syntax is:
Synchronization
: That's one UML classinitialize
, perform
, detect_outdated_documents
, and update_documents
, the two last being private. These would be 4 UML operations.initialize
is the constructor, and since it's empty, you have not mentioned it in your UML class diagram, and that's ok.@documents
. In UML, that would be a property, or a role of an association end.attr_reader
. But since it is in a private section, its visibility should be -
. This other answer explains how to work with getters and setters elegantly and accurately in UML (big thanks to @engineersmnky for the explanations on getters in Ruby, and for having corrected my initial misunderstanding in this regard)SomeClass.new
creates in Ruby a new object of class SomeClass
.UML class diagrams are based on well-defined types/classes. You would normally indicate associations, aggregations and compositions only with known classes with whom there’s for sure a stable relation. Ruby is dynamically typed, and all what is known for sure about an instance variable is that it's of type Object
, the highest generalization possible in Ruby.
Moreover, Ruby methods return the value of the latest statement/expression in its execution path. If you did not care about a return value of an object, you'd just mark it as being Object
(Thanks engineersmnky for the explanation).
Additional remarks:
void
type in UML (see also this SO question). An UML operation that does not return anything, would just be an operation with no return type indicated.Array
, Hash
, Object
, ...) would suppose the use of a language specific UML profile.Based on all this, and considering that an array is also an Object
, your code would lead to a very simple UML diagram, with 3 classes, that are all specializations of Object
, and a one-to-many association between Synchronization
and Object
, with the role @documents
at the Object
end.
The very general class diagram, may perhaps match very well the implementation. But it might not accurately represent the design.
It's your right to model in UML a design independently of the implementation. Hence, if the types of instance variables are known by design (e.g. you want it to be of some type and make sure via the initialization and the API design that the type will be enforced), you may well show this in your diagram even if it deviates from the code:
Object
return type. But it would be ok for you not to indicate any return type (the UML equivalent to void
) to express taht the return value is not important.DetectOutdatedDocument.new.perform
.DetectOutdatedDocument
objects, and we guess it's becaus of the possible values of @documents
. And the property is indicated as an array of objects. It's very misleading to have both on the diagram. So I recommend to remove the document
property. Instead, prefer a document
role at the association end on the side of DetectOutdatedDocument
. This would greatly clarify for the non-Ruby-native readers why there is a second class on the diagram. :-) (It took me a while)documents
has a public reader; so other objects could also be assigned to the same documents. Since Ruby seems to have reference semantic for objects, the copy would then refer to the same objects. That's shared aggregation (white diamond) at best. And since UML has not defined very well the aggregation semantic, you could even show a simple association.A last remark: from the code you show, we cannot confirm that there is an aggregation between UpdateOutdatedDocument
and DetectOutdatedDocument
. If you are sure there is such a relationship, you may keep it. But if it's only based on the snippet you showed us, remove the aggregation relation. You could at best show a usage dependency. But normally in UML you would not show such a dependency if it is about the body of a method, since the operation could be implemented very differently without being obliged to have this dependency.