Creating a Domain Model rapidly with Java and Spring Boot
Tags: java, spring
Published: 2019-07-18 07:02:52

---
title: Creating a Domain Model rapidly with Java and Spring Boot
published: true
description: In this short article, we are creating a domain model for a simple application. All the examples are in Java language. We use Spring Boot to accelerate the application startup. 
tags: Java, Spring
cover_image: https://thepracticaldev.s3.amazonaws.com/i/nqhni36nv8u1na2azhv1.png
---


**Overview**

In this short article, we are creating a domain model for a simple application. We illustrate how we are creating the classes/objects of the model, based on the application business description. We insist just on the entities that are part of the model. 

Here we talk about domain modeling in the case of a Web application with a client-server architecture where we have Java on the server-side (backend). All the examples are in Java language. We use Spring Boot to accelerate the application startup.

**Start the implementation**

Tools we are using:

- [Java 8 JDK from AdoptOpenJDK](https://adoptopenjdk.net/) installed with [SdkMan](https://sdkman.io/)
- [SpringBoot](https://spring.io/projects/spring-boot) - just for starting rapidly an app with integrated build using [Spring Starter](https://start.spring.io/)
- [Maven](https://maven.apache.org/) - used internally for build
- [JUnit](https://mvnrepository.com/artifact/junit/junit) - used for playing with the domain
- [Intellij Idea](https://www.jetbrains.com/idea/) - for code editing (you can use [VS Code](https://code.visualstudio.com/) or [Sublime](https://www.sublimetext.com/))

If you are on Windows OS then the Java JDK 8 can be installed manually and also Maven can be installed manually. Spring Initializr -[https://start.spring.io](https://start.spring.io) can be used to download the Spring Boot starter app. But on MAC OS and Linux, the fastest way is to use the terminal commands as you can see after.

Starting our app (we name it **cindykat** - a name very close to **syndicate**) and running it is is just like this:

    # install SDKMAN
    curl -s "https://get.sdkman.io" | bash
    # install JDK
    sdk install 8.0.212.j9-adpt
    # create app
    curl https://start.spring.io/starter.zip -d name=CindyKat -d groupId=com.colaru -d artifactIf=cindykat -d packageName=com.colaru.cindykat -d dependencies=web -d javaVersion=8 -o cindykat-springboot.zip
    # unzip, then run it
    unzip cindykat-springboot.zip -d cindykat-springboot
    cd cindykat-springboot && ./mvnw spring-boot:run

Now our app is up and running on 8080 - it is a web application! No need for a web app - is ok to have something up and running.

![](https://thepracticaldev.s3.amazonaws.com/i/t02cv9gfijdson5jyya0.png)

We have this project structure:

![](https://thepracticaldev.s3.amazonaws.com/i/we6h0n6qvufymv0avawx.png)

**What is the application domain?**

The domain model is the place in our code, where we are modelling the business of our app. Usually, an application model has to be a direct reflection of the business it implements. Our code has to be a story of the reality we are modelling. And we have to use a ubiquitous language used by all people working on the project. 

That's no need to introduce other abstractions different than what we have in the reality we are modelling. The nouns and verbs from the business have to appear in the name of our classes, fields, methods. When we introduce other things - we can be suspected of over-engineering.

![Domain model](https://thepracticaldev.s3.amazonaws.com/i/s5xur8r8awydi8dttbs3.png)
Image source: [https://www.slideshare.net/Dennis_Traub/dotnetcologne2013-ddd](https://www.slideshare.net/Dennis_Traub/dotnetcologne2013-ddd)

Why is the model so important? Because all the rest of the application will be in contact with the model. It is hard to have separate packages of DTOs or WS REST resources or persistence entities because of the marshalling/un-marshalling complications. We will be forced to do this if we don't want to expose the internal model outside the system. So we will use the model in all the layers of the application. You can be sure that the UI, persistence, reporting, WS, messaging integrations, all are using the domain model classes.

And the model can become more an more complicated over time (hundreds of classes). And what is in the model will evolve and will influence the entire application. This is the hardest part to be understood in any app by a new development team joiner. Here is not something like a library or framework reused in other applications, but here is something specific to a business. And the businesses can be very, very complicated. 

**The DDD book**

There are a few ways of starting a Java Web application:

- Backend first - play with the Java domain using tests to create a domain model that is the core of the server-side
- Frontend first - start with UX/UI with HTML/ CSS/ JavaScript and create some mockups that will illustrate the user interaction - you can play with a domain model in  JSON or Typescript here also

It is common to have a team that is working in the frontend, and a different team that is working in the backend and the contract between them is a Swagger/Open API spec.

The first approach, modelling the domain, is the subject of this article. And is the subject also of a very well known book: [Domain-Driven Design](https://dddcommunity.org/book/evans_2003/) by Eric Evans. In this book, more topics are introduced apart from the graph entities described in this article.

![](https://thepracticaldev.s3.amazonaws.com/i/yo6e7bamp6rdc61bvomk.png)

Image from [Domain Driven Design Quickly](https://www.infoq.com/minibooks/domain-driven-design-quickly/#minibookDownload,%20/minibooks/domain-driven-design-quickly/#minibookDownload/) book

**Our application business explained**

The application we want to implement is an analytics system for the data provided by [Google Trending Searches](https://trends.google.com/trends/trendingsearches/daily?geo=US) - The history of searches from Google Search reported per day and country by Google. We want to import some data from Google Trends, then store it in our system and make it possible to analyse it, show it in a different form, etc.

![](https://thepracticaldev.s3.amazonaws.com/i/rmivpmsneidd0zubyxjw.png)

In this case, it will be simple to model our domain used in our analytics system. Because we are distingue our entities from the format used to get the searches data. See this Google Trends **Atom Syndication Format** XML snippet:

    		<item>
    			<title>Women's World Cup 2019</title>
    			<ht:approx_traffic>1,000,000+</ht:approx_traffic>
    			<description>2019 Women, Women World Cup, WWC</description>
    			<link>https://trends.google.com/trends/trendingsearches/daily?geo=US#Women's%20World%20Cup%202019</link>
    			<pubDate>Mon, 10 Jun 2019 22:00:00 -0700</pubDate>
    			<ht:picture>https://t2.gstatic.com/images?q=tbn:ANd9GcTW4UzPHNC9qjHRxBr6kCUEns71l8XK6HYcmLpJbhlfZWUbeBQPiia1GDzN3Ehl7nfD-HPbgnG_</ht:picture>
    			<ht:picture_source>CBSSports.com</ht:picture_source>
    			<ht:news_item>
    				<ht:news_item_title>&lt;b&gt;2019 Women&amp;#39;s World Cup&lt;/b&gt; scores, highlights: Canada squeaks by, Japan underwhelms, Argentina gets historic point</ht:news_item_title>
    				<ht:news_item_snippet>Day 4 of the &lt;b&gt;2019&lt;/b&gt; FIFA &lt;b&gt;Women&amp;#39;s World Cup&lt;/b&gt; in France featured a two-game slate with two potential contenders opening their campaigns against slightly inferior opponents. When the dust settled, neither team looked particularly sharp as only one goal was&amp;nbsp;...</ht:news_item_snippet>
    				<ht:news_item_url>https://www.cbssports.com/soccer/world-cup/news/2019-womens-world-cup-scores-highlights-canada-squeaks-by-japan-underwhelms-argentina-gets-historic-point/</ht:news_item_url>
    				<ht:news_item_source>CBSSports.com</ht:news_item_source>
    			</ht:news_item>
    			<ht:news_item>
    				<ht:news_item_title>&lt;b&gt;2019 Women&amp;#39;s World Cup&lt;/b&gt; scores, highlights, recap: Japan underwhelms in opener as Argentina gets historic point</ht:news_item_title>
    				<ht:news_item_snippet>Day 4 of the &lt;b&gt;2019 World Cup&lt;/b&gt; has a small slate of action with just two games, but two contenders to win the tournament were scheduled to play their opener. After the first match, we may just be talking about one contender. With talented Canada set to play&amp;nbsp;...</ht:news_item_snippet>
    				<ht:news_item_url>https://www.cbssports.com/soccer/world-cup/news/2019-womens-world-cup-scores-highlights-recap-japan-underwhelms-in-opener-as-argentina-gets-historic-point/</ht:news_item_url>
    				<ht:news_item_source>CBSSports.com</ht:news_item_source>
    			</ht:news_item>
    		</item>

So it is simple! We have an **Item** which has a list of **NewsItem**. We separately have a **Source** entity that will be reused between **NewsItem**. Also, a **Country** is needed for the **Item** specify the country/language. That's all.

![](https://thepracticaldev.s3.amazonaws.com/i/zymr3toj8b4ktrxg4y4r.png)

**Creating the graph of entities**

The domain model will be a separate package in our application. We choose to create a sub-domain named **newsfeed** (complete name **com.colaru.cindykat.domain.newsfeed)** for naming the package because it is possible to have other aggregates (groups of entities) in the future. 

It is a good idea to create an entire module for the domain (in a multi-module Maven/Gradle project) because in this way we can create a dependency to it in any other modules of the application - all the other modules will use the domain model.

First, using the IDE, we will create an **Item** class, which is the primary entity (aggregate root in DDD terminology) and then the rest of the classes:

    package com.colaru.cindykat.domain.newsfeed;
    
    import java.util.Date;
    import java.util.List;
    
    public class Item {
    
        private String title;
        private List<Tag> description;
        private String link;
        private String picture;
    
        private Date pubDate;
        private String pubDateAsString;
    
        private String approxTraffic;
        private Long approxTrafficAsNumber;
    
        private List<NewsItem> items;
        private Country country;
    
        // generate getters/setters using the IDE
    }

    
    
    public class NewsItem {
        private String title;
        private String snippet;
        private String url;
        private Source source;
    }

    
    public class NewsItem {
        private String title;
        private String snippet;
        private String url;
        private Source source;
    }
    
    public class Country {
        private String name;
        private String countryCode;
        private String languageCode;
        private String flag;
    }
    
    public class Source {
        private String name;
        private String url;
    }
    
    public class Tag {
        private String name;
    }

In the end, we will have this graph of entities:

![Entities graph](https://thepracticaldev.s3.amazonaws.com/i/nqhni36nv8u1na2azhv1.png)

Now the project filesystem is like this:

![Project structure](https://thepracticaldev.s3.amazonaws.com/i/p40ikwb4k3vn1501m6da.png)

**Anemic Domain**

A common problem for a domain is an anti-pattern named [Anemic Domain by Martin Fowler](https://martinfowler.com/bliki/AnemicDomainModel.html) - the classes are having just state and not behaviour. We get from the real word only the **nouns** and not the **verbs**. In this case, the entities are **data structures** like in the functional programming language and not real **Java objects** as [Uncle Bob is describing in this article](https://blog.cleancoder.com/uncle-bob/2019/06/16/ObjectsAndDataStructures.html). And this is something normal because in general, the entities are our mappers to database tables used by an ORM persistence framework.

We expect that the **verbs** will be in the services layer of our application outside the domain. But in this case another discussion is starting: are this services part of the domain?

But also there it is no problem to introduce some logic directly in the entities - in this case, we have to be aware that we will have business logic in two places: services and in the domain model.

We will introduce some business methods in the **Item** entity (some convertors from String to Date and from String to Long):

    public class Item {
    		private Date pubDate;
        private String pubDateAsString;
        private String approxTraffic;
        private Long approxTrafficAsNumber;
    
        // other private fields
    
        public Date convertStringToDate(String pubDateAsString) throws ParseException {
            SimpleDateFormat parser = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z"); // Wed, 21 Dec 2016 13:00:00 +0200
            return parser.parse(pubDateAsString);
        }
    
        public Long convertStringToLong(String approxTraffic) {
            return new Long(approxTraffic.toString().replaceAll(",", "").replace("+", ""));
        }
    }

**Testing the domain**

Even if the domain is simple, it is a good idea to start playing with it using and creating some tests using JUnit. First, we have to include the JUnit library as part of our Maven dependencies in pom.xml:

    	<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    	<dependency>
    		<groupId>org.junit.jupiter</groupId>
    		<artifactId>junit-jupiter-api</artifactId>
    		<version>5.3.2</version>
    		<scope>test</scope>
    	</dependency>

Now we can create a first test to play with our simple graph of objects and to verify some small functionalities. This is a first working skeleton good enough to start our TDD development guided by tests for the next features we will add to this app:

    class DomainModelTests {
    
    	private Item item;
    
    	@BeforeEach
    	void setUp() throws ParseException {
    		item = new Item();
    		item.setTitle("Women's World Cup 2019");
    
    		item.setLink("https://trends.google.com/trends/trendingsearches/daily?geo=US#Women's%20World%20Cup%202019");
    		item.setPicture("https://t2.gstatic.com/images?q=tbn:ANd9GcTW4UzPHNC9qjHRxBr6kCUEns71l8XK6HYcmLpJbhlfZWUbeBQPiia1GDzN3Ehl7nfD-HPbgnG_");
    
    		// tags
    		Tag tag = new Tag();
    		tag.setName("Word cup");
    		List<Tag> tags = new ArrayList<>();
    		tags.add(tag);
    		item.setDescription(tags);
    
    		NewsItem newsItem = new NewsItem();
    		// source
    		Source source = new Source();
    		source.setName("USA TODAY");
    		newsItem.setSource(source);
    		newsItem.setTitle("&lt;b&gt;2019 Women&amp;#39;s World Cup&lt;/b&gt; scores, highlights: Canada squeaks by, Japan underwhelms, Argentina gets historic point");
    		List<NewsItem> items = new ArrayList<>();
    		items.add(newsItem);
    		item.setItems(items);
    	}
    
    	@Test
    	void buildNewItemTest()  {
    		Assert.assertEquals(1, item.getItems().size());
    		Assert.assertEquals(1, item.getDescription().size());
    	}
    
    	@Test
    	void convertStringToLongTest() {
    		String approxTraffic = "900,000+";
    		item.setApproxTraffic(approxTraffic);
    		item.setApproxTrafficAsNumber(item.convertStringToLong(approxTraffic));
    		Assert.assertEquals(900000, item.getApproxTrafficAsNumber().longValue());
    	}
    
    	@Test
    	void convertStringToDateTest() {
    		String pubDateAsString = "Mon, 1 Jun 2020 09:00:00 -0700";
    		item.setPubDateAsString(pubDateAsString);
    		try {
    			item.setPubDate(item.convertStringToDate(pubDateAsString));
    		} catch (ParseException e) {
    			e.printStackTrace();
    		}
    		Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
    				.setFields(YEAR, 2020, DAY_OF_MONTH, 1, MONTH, 5, HOUR, 18, MINUTE, 0, SECOND, 0)
    				.build();
    
    		Assert.assertEquals(cal.getTime(), item.getPubDate());
    	}
    }

When we run all the test the bar is green (I write the test first, then the tested method, the test run is failing, I add the implementation, I run the test again, and now it is passing):

![](https://thepracticaldev.s3.amazonaws.com/i/rwxmsnd8qsw3b42m9t75.png)

**Conclusion**

In this article, we've exposed how we created a simple model for a small application.

As we can see, the domain model is the core part of the application. This classes that are composing the domain model are technology agnostic (concurrency, persistence is not in our interest now) - are describing just the reality of the business - nothing regarding the technologies used in the project.

**Git Repository**

We published the sources on GitHub:

    git clone https://github.com/colaru/cindykat-springboot.git
    cd cindykat-springboot
    mvn clean install // the tests will be executed successfully

---

**You can [follow me on Twitter](https://twitter.com/colaru) where I continue to document my journey.**

---


**Inspiration links for this article**

- Value objects vs entities: [https://enterprisecraftsmanship.com/2016/01/11/entity-vs-value-object-the-ultimate-list-of-differences/](https://enterprisecraftsmanship.com/2016/01/11/entity-vs-value-object-the-ultimate-list-of-differences/)
- Anemic domain: [https://martinfowler.com/bliki/AnemicDomainModel.html](https://martinfowler.com/bliki/AnemicDomainModel.html)
- Domain services: [https://stackoverflow.com/questions/2268699/domain-driven-design-domain-service-application-service](https://stackoverflow.com/questions/2268699/domain-driven-design-domain-service-application-service)
- Domain model: [https://martinfowler.com/eaaCatalog/domainModel.html](https://martinfowler.com/eaaCatalog/domainModel.html)
- Service layer: [https://martinfowler.com/eaaCatalog/serviceLayer.html](https://martinfowler.com/eaaCatalog/serviceLayer.html)
- Objects and data structures: [https://blog.cleancoder.com/uncle-bob/2019/06/16/ObjectsAndDataStructures.html](https://blog.cleancoder.com/uncle-bob/2019/06/16/ObjectsAndDataStructures.html)
- Domain Driven Design Book by Eric Evans: [https://dddcommunity.org/book/evans_2003/](https://dddcommunity.org/book/evans_2003/)
- Domain Driven Design Quickly book: [https://www.infoq.com/minibooks/domain-driven-design-quickly/#minibookDownload, /minibooks/domain-driven-design-quickly/#minibookDownload/](https://www.infoq.com/minibooks/domain-driven-design-quickly/#minibookDownload,%20/minibooks/domain-driven-design-quickly/#minibookDownload/)
- Data structures vs objects by Uncle Bob: [https://blog.cleancoder.com/uncle-bob/2019/06/16/ObjectsAndDataStructures.html](https://blog.cleancoder.com/uncle-bob/2019/06/16/ObjectsAndDataStructures.html)
- 10 Myths About Java in 2019: [https://developer.okta.com/blog/2019/07/15/java-myths-2019](https://developer.okta.com/blog/2019/07/15/java-myths-2019)
- Which Java SDK Should You Use: [https://developer.okta.com/blog/2019/01/16/which-java-sdk](https://developer.okta.com/blog/2019/01/16/which-java-sdk)