From sketch to code

An overview of transforming UML class models into basic programming constructs in Ruby

Tish Chungoora
5 min readOct 16, 2019

Introduction

In previous jobs, I was operating at the requirements definition end of the Systems Development Life Cycle (SDLC). I used to work closely with business stakeholders to gather and transform requirements into specifications that the Development teams would use to develop software applications. Within actual organisational settings, as Software Engineers, these specifications tend to be articulated and embodied by individuals working in the capacity of Product Managers, Product Owners, Business Analysts, Solutions Architects or similar roles.

These software specifications are handed over to the Development teams in the form of requirements documents, user stories, wireframes, etc., but can also be supplied in the form of diagram artifacts expressed in graphical languages.

Enter UML

A popular graphical modelling language used for conceptualising system viewpoints is the Unified Modelling Language or UML for short. Probably the most popular system perspective that witnesses the use of UML is for class modelling. The diagram below illustrates a portion of a UML class model, identifying different classes (represented as rectangles) with interconnecting lines showing how they associate with each other.

An example of a UML class model
Example UML class model

So, as Software Engineers, we can expect similar artefacts to come our way to be ‘magically’ transformed into code! But how do we go about interpreting these diagrams? This is where this article comes in handy! Its purpose is to:

  • Provide an overview of how the basic structure of UML class models transforms into the fundamental constructs in object-oriented programming expressed in the Ruby language.
  • Help Software Engineers who are not familiar with UML class models to understand how to plan in UML before writing Ruby code or reverse engineer UML class models from pre-written Ruby code.

Building block: Classes

A class represents a ‘blueprint’ for designating a conceptual grouping of things that share similarities in terms of their characteristics and behaviour. For example, we can see a UML class Doctor which has a name attribute (see label A). Attributes in UML are listed in the middle portion of the class shape, where each is listed on a separate line.

Methods, on the other hand, are listed in the bottom section of the class shape (see label B). Here, for example, we have the initialize method which takes one name argument. We also have a class method all which returns all the instances of the class Doctor. Notice that in UML we underline class methods whereas instance methods are not underlined.

Transforming UML class shape and content into Ruby code
Class construct: UML to Ruby

Building block: Associations

Classes alone are not sufficient to model more complex semantics where we want to say, for example, instances of Doctor can be associated with instances of Patient through instances of Appointment. In other words, how do we capture the relationships that can exist across the instances of different classes? Well, UML offers us the ability to explicitly model associations that can carry multiplicity information as well as directionality, if needed.

The example shown next illustrates the classes Doctor, Patient and Appointment. Notice that there is a many-to-many association between the classes Doctor and Patient via the Appointment class. In UML, this ‘special-purpose’ class that models the relationship between two classes is known as an association class (typically referred to as a joiner class in Ruby).

Basic association class construct in UML
UML association class construct

A key principle observed while modelling this example is the whole idea of single source of truth where we want to make sure that instances of ‘Doctor’ can only ever pertain to the ‘Doctor’ class, while instances of ‘Patient’ only ever pertain to that class. As such, the association class ‘Appointment’ serves the purpose of allowing us to specify these relationships through instantiating ‘Appointment’.

Therefore, every time we want to associate some instance of Doctor to some instance of Patient, we can do so by calling the new_appointment method on either an instance of Doctor or Patient. In the process, a new Appointment object is created, storing the relationship that holds between these instances.

Below is the actual implementation of the three classes.

‘Doctor’ class expressed in Ruby
‘Patient’ class expressed in Ruby
‘Appointment’ class expressed in Ruby

Building block: Inheritance

Classes can be arranged in a tree-like structure called taxonomy, which imparts a special bond, known as inheritance, between a class and its subclass, i.e. a parent class and a child class. Inheritance allows a child class to be extended from its parent while inheriting the core attributes and behaviour of the parent class.

In UML, inheritance is more commonly known as ‘generalisation’ which is represented by a directed arrow from a child class to a parent class. The diagram below illustrates how to represent inheritance in UML. In this case, the parent class User has two child classes, namely Doctor and Patient. Indicating inheritance in Ruby is actually pretty straightforward, as depicted below.

Generalisation construct from UML to Ruby
Generalisation construct: UML to Ruby

Conclusion

This article has exposed the basics of UML modelling and how these fundamental structures can be interpreted by Software Engineers and transformed into Ruby code. Of course, there are loads of other UML constructs that exist as well as a whole host of ways of working with classes in Ruby. In a forthcoming blog, we’ll build on top of what we’ve seen here to expose some more advanced Ruby and UML constructs.

--

--

Tish Chungoora
Tish Chungoora

Written by Tish Chungoora

Knowledge Graph Consultant | Ph.D. | CSPO

Responses (3)