DEV Community

Cover image for Java Agile Development: Data management with Java domain models
Hunter Johnson for Educative

Posted on • Originally published at

Java Agile Development: Data management with Java domain models

Agile Java weaves all test-driven development, object-oriented design, and software architecture into a single, clean approach for building robust and highly scalable software systems.

Today, you will learn how to implement different relational models using the Spring framework. We’ll show you how to use a test-driven and agile development approach. These popular methodologies help us design and develop robust and manageable applications.

Here’s what we’ll cover today:

What is agile development?

Agile Development

Agile development is a new methodology taking the industry by storm. This software development methodology allows us to build a program incrementally with short iterations over 1 to 4 weeks. The incremental procedure helps align the development process with business needs.

Agile development is an iterative methodology for software development that focuses on creating adaptive products. Projects take multiple iterations that each builds on the previous iteration and gradually approach the final product.

Agile methodologies also prioritize close, in-person collaboration between development teams and business teams at all stages. Developers reassess business requirements and development practices at the end of each iteration. The findings are used to adapt the product in the next iteration. Agile also welcomes new feature ideas that can be added at any iteration, even in the late stages.

Traditional development only accounts for business requirements at the beginning of the process, which means that the product may no longer be optimal or meet business needs at the end of the development cycle.

What is test-driven development?

Test-driven development (TDD) is a key development technique that makes agile development possible. TDD focuses on gradual development by creating and testing small pieces of code during development. If all small pieces of code pass their tests, the project is ready to ship.

TDD perfectly compliments agile development because it ensures each feature works before moving on to the next. Developers can then combine all working features at the end of an agile iteration to form a working project component.

Test-driven development

The TDD process has 4 steps:

  1. Write test code that checks for a small desired feature.
  2. Run the test. This should fail because no code has been added yet. If it passes, return to step 1.
  3. Add only enough code to implement the desired feature.
  4. Run the test again. If it passes, move on to another feature. If the test fails, revisit step 3.

With TDD, we can take small measurable steps toward completing a larger project. Rather than feeling overwhelmed by the large task "create a web app", you can break it down into small steps like "create a sign-in button", "display the newest content", etc.

TDD is also helpful for debugging. Each cycle of the TDD process involves less code than a traditional coding process. It's much easier to check a 10-line feature for bugs than a full 1,000 line project.

When using agile and test-driven development, it's best practice to model solutions using domain models. This will help everyone on the team understand the architecture of the program and how their components will be connected in the final product. Below, we'll explain what a domain model is and give you some examples of how to represent these models in your code.

Domain models for Java data management

Software architecture refers to the fundamental structure of a programming solution. This architecture is often created early in the development process. It serves as a plan for how the program pieces should be designed and interact with each other.

Think of domain Modeling as a way to describe the real-world entities of your program and the relationships between them.

Agile developers favor domain modeling for its real-world applications and team-based planning. Domain modeling is a conceptual model that tracks both the behavior and data of a project segment. Each of these segments are called "domains" and represent spheres of real-world knowledge or behaviors within the code.

These domains are then connected to all other relevant domains in the model. Once completed, the domain model allows developers to track what behaviors they need to include and what interactions each team will plan for.

Agile domains

Domains are usually represented as rectangles connected to other linked domains through a network of arrows. In Java, domains are represented through classes.

Agile developers use this model because it allows all project members to understand the purpose and connection of each project component. The domain model also keeps code out of the planning process. Instead, developers only start considering code once it's time to write the domain function. This allows developers to program each domain to fit all previously created project parts and apply more current information gathered throughout the project cycle.

Overview: Development process of a domain model

There are many types of domain models:

  • Standalone Entity
  • One-to-one unidirectional
  • One-to-one bidirectional
  • One-to-one self-referencing
  • One-to-many unidirectional
  • One-to-many bidirectional
  • One-to-many self-referencing
  • Many-to-Many Unidirectional
  • Many-to-many bidirectional
  • Many-to-many bidirectional with join-attribute
  • Many-to-many self-referencing
  • Many-to-many self-referencing with join-attribute
  • Single table inheritance
  • Concrete table inheritance
  • Class table inheritance

Each domain has different strengths and weaknesses and is suited for specific types of projects. The five most common domain models are standalone entities, one-to-one unidirectional, one-to-one self-referencing, one-to-many bidirectional, and many-to-many.

Understanding Domain Model Names:

The first section of most domain names refers to how many entities are linked to each other and if there is a parent entity, like with "one-to…" relationships. The second part explains the direction of link access. In unidirectional, access only goes one way, whereas bidirectional goes both ways.

Each model requires the same 7 general steps to create. Let’s dive into them.

  1. Data transfer object: Develop an object that acts as a map between the user interface and the data access object tier. The internal database design should not be disclosed to the user interface.
  2. Mock service: Develop a mock service that saves the data to an in-memory database.
  3. Mock user interface: Develop a mock user interface to demonstrate how we can integrate with the mock service. This allows the UI team to cooperate with the service development team by showing how the UI interacts with the service.
  4. Resource tier: Create a resource software layer to contain program entities. Entities are managed by Hibernate implementation.
  5. Data access tier: Create a data access software layer that provides simplified access to entities. This is handled by Spring.
  6. Business service tier: Create a business service software layer that manages data access subsystems and allows applications to call the data access tier. Must contain a mapper to transition data access objects to entities.
  7. Presentation tier: Create a presentation software layer that uses JSON REST-based Spring controllers to expose services to users.

Each of these steps requires slightly different code implementations depending on the chosen domain model type. Later in the article, we'll explore how the creation of a data transfer object differs for the top 5 domain models.

How to configure your workspace

To successfully run Java domain models, you'll need 5 tools. If you don't want to download anything right now, feel free to skip to our example section featuring embedded code.

The tools you'll need are:

  • Eclipse IDE for Java EE Developers
  • JDK 1.7
  • Apache Maven
  • MySql DB Server
  • Apache Tomcat

You'll also need source code zip from our Spring-Hibernate book on Github.


You'll then need to unzip these files and import them into your Eclipse as a Maven project.


After choosing the Existing Maven Projects option, select the folder where you have unzipped the downloaded file and choose the directory containing the POM as shown below.


From here, use MySQL to create a new schema named spring in the MySQL Workbench.

Next, open Tomcat and install a v7.0 server. Then, click Add Library -> JRE System -> Library -> Alternate JRE -> Installed JREs. Set this as your default then click Finish.

Finally, add the Spring OODD project to the Tomcat configuration. Once started, Tomcat will load the index page from web.xml.

Congratulations, you now have the workspace to implement Java domain models!

Next, we will discuss five common domain models and teach you how to create a data transfer object for each.

Standalone Entity

This model features a single entity with no relationships. It is used to demo individual entities before adding them to relationship models. Developers use a standalone entity to look at the individual components of a Spring application and understand the role they play.

For example, we can look at an entity Product with a String field, name.


Entity vs Class

A class is a technical representation of a collection of related data. An entity is a collection of data that represents a real-world object or function. In Java, classes that represent real-world concepts or behaviors are entities.

Develop a Data Transfer Object: Standalone Entity

To create a Data Transfer Object for a Standalone Entity, create a class with the following code:

public class ProductDto implements Serializable {
  private static final long serialVersionUID = 1L; private Integer id;
  private String name;

  // getters and setters 
Enter fullscreen mode Exit fullscreen mode

Here the implements keyword maps this object to the user interface. Each variable is private to avoid disclosing the database design to the user interface.

One-to-One Unidirectional Relationship

One-to-one unidirectional models involve two individual entities where data and service can move in only one direction. Once data is sent to the child object, it cannot refer back to the parent, as there is no link to the parent within the child.


For example, imagine we have a bookstore shipping program represented by a one-to-one unidirectional model with two entities, Book and Shipping. The Book entity has an identifier and a String name field, Similarly, the Shipping entity has an identifier and a String city field. An instance of Shipping must be present in an instance of Book. The Book is the owning side of the relationship. It may traverse Shipping, but Shipping cannot traverse Book.

This is used for situations where the first stage of a process does not need to know the outcome of the second stage. For example, the Book entity above does not need to know what's happening in the Shipping entity, like what city the book is going to. The Book entity simply needs to know that a certain book was passed to Shipping so it can be removed from inventory.

Develop a Data Transfer Object: One-to-one Unidirectional Relationship

To create a Data Transfer Object in a One-to-one unidirectional relationship, you'll use the following BookDto class:

public class BookDto { 
  private Integer id; 
  private String name; 
  private String city;

  // getters and setters 
Enter fullscreen mode Exit fullscreen mode

Again, we encapsulate the entity design using private variables to prevent the client or UI from viewing unneeded information.
The data transfer object contains an identifier of the Book object, a name, and a city field. However, it does not have the identifier for the Shipping Entity. While Book and Shipping are related in the service, the user sees only the Book object via the data transfer object.

This architecture will help your user interface team down the line, as they do not have to manage the Shipping entity identifier and can just call the service as one object.

One-to-one self-referencing relationship

In a one-to-one self-referencing relationship, an entity is linked to one other instance of the same class. Because it is one-to-one, an instance cannot link to more than one other instance. However, not all instances in this model need to have relationships.


For example, imagine a relationship between a Student entity and a mentor who is also an instance of Student. Each Student entity has an identifier and a String name field. The Student entity can have an optional mentor who is also a Student. This association is declared in the first instance of Student, not within the mentor Student.

This is best used when there are relationships between instances of the same class that are too similar to need a separate class. This also makes it ideal for situations where relationships are optional, not standard.

Develop a Data Transfer Object: One-to-one Self referencing relationship

For a one-to-one self-referencing relationship, our data transfer object will look like:

public class StudentDto {
    private Integer id;
    private String name;
    private String mentorName;

    // getters and setters

Enter fullscreen mode Exit fullscreen mode

Notice that we have the id, name, and mentorName but do not include the mentor object identification.

The data transfer object does not have the identifier of the Student mentor object because the UI team will not need to see the internal design of our relationship system. We only include a single mentorName, as each Student can only have a single mentor.

One-to-many bidirectional relationship

A one-to-many bidirectional relationship exists when a parent entity is associated with any number of instances of a child entity, and each child entity contains a link back to the parent entity. Communication can go either from parent to child or from a child instance to the parent because both sides must have links to the other.


For example, consider a program that lists the features of an item with two entities Item and Feature. The Item entity has an identifier and a String type name field. The Feature entity also has an identifier and a String type number field. Each instance of Item must contain a link to at least one. Similarly, each instance of Feature must link to one instance of Item.

As the relationship is bidirectional, all instances of either Item or Feature can access any instance linked to it.

This is best used when you want to reuse child instances across multiple parents in complex relationship networks. In our example above, a parent instance of Item may link to the child feature Waterproof, but waterproof also links to many other instances of Item. What's more, our Item can link to as many features needed to describe it.

Develop a Data Transfer Object: One-to-many bidirectional relationship

For a one-to-many bidirectional relationship, our data transfer object will look like:

public class ItemDto {
    private Integer id;
    private String name;
    private List<String> featureList;

   // getters and setters
Enter fullscreen mode Exit fullscreen mode

The Item data transfer object has an identifier, name of the Item, and a list of the String Feature names. Using a list for the Feature names allows us to link multiple Feature objects to our one Item.

We exclude the identifier for the Feature object in the data transfer object to simplify the API call for the UI team. Not only does this keep the database design secure, but it also saves the UI team the trouble of managing the identifiers of each child object.

Many-to-many unidirectional relationship

In a many-to-many unidirectional relationship, a parent instance is linked to any number of child instances and child instances can be linked to any number of parent instances. Parent instances can access its child instances. However, the child instance is not allowed to access its parent.


For example, imagine you're creating a simple social media program that allows a parent entity, User, to link with a child entity, Group. The User entity has an identifier and a String type name field. The Group entity also has an identifier and String type name field.

Every many-to-many relationship has a parent. In this example, the User is the parent. Each instance of User is linked to at least one instance of the Group. Many instances of User can be linked to the same instance of Group.

An instance of User can access data within all linked Group instances, however, Group instances cannot access data within the User instance.

This is best used to securely create complex networks where some data is public, and some are sensitive.

Develop a Data Transfer Object: Many-to-many unidirectional relationship

For the many-to-many unidirectional relationship, we need to create three data transfer objects.

public class UserDto {
    private Integer id;
    private String name;

    // getters and setters

public class GroupDto {
    private Integer id;
    private String name;

    // getters and setters

public class UserGroupDto {
    private UserDto userDto;
    private GroupDto groupDto;

    // getters and setters
Enter fullscreen mode Exit fullscreen mode

The UserDto data transfer object has an identifier and the name of the user. Similarly, the GroupDto object has an identifier and the name of the group. The third object, UserGroupDto, is a join object and connects UserDto and GroupDto. UserGroupDto, has an instance of UserDto and GroupDto within and can be used to call both transfer objects together.

What to learn next

Congratulations! You've taken your first step toward implementing each of the top 5 domain models used in agile architectural planning.

From here, you're ready to explore the 10 more advanced domain models. You can also work beyond the initial data transfer object step covered to create your own fully functional architecture.

Educative's course Software Architecture in Java: Design & Development covers all 15 domain models used in modern programming and teaches you how to implement each in your own programs. By the end of the course, you'll be able to apply each domain model to your work and have learned agile best practices to aid both your development and UI teams.

Happy learning!

Continue reading about Java, Spring, and Software Architecture on Educative

Start a discussion

Why do you like using Agile? Was this article helpful? Let us know in the comments below!

Top comments (0)