<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roman Sery</title>
    <description>The latest articles on DEV Community by Roman Sery (@romansery).</description>
    <link>https://dev.to/romansery</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F314788%2Ff257a376-c0ee-4e51-b922-f21822d7b50a.png</url>
      <title>DEV Community: Roman Sery</title>
      <link>https://dev.to/romansery</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/romansery"/>
    <language>en</language>
    <item>
      <title>Themeable React Monopoly board</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Thu, 10 Sep 2020 23:35:51 +0000</pubDate>
      <link>https://dev.to/romansery/themeable-react-monopoly-board-3d84</link>
      <guid>https://dev.to/romansery/themeable-react-monopoly-board-3d84</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UTdMpRBc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/09/monopoly_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UTdMpRBc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/09/monopoly_screenshot.png" alt="Game board"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been working on a Monopoly game with a customized rule set and more gameplay options for players to try different strategies. I feel the standard rules make the game mostly based on luck.&lt;/p&gt;

&lt;p&gt;It’s been a lot of fun so far mostly because it’s different from the stuff I usually work on and I’ve been learning a lot. Specifically React, CSS grid/flex, NodeJS, Express, Socket.IO, and more. &lt;em&gt;I think the biggest challenge is getting the networking code to work right and to deal with slow/lagging connections, disconnects, and so on.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Live Demo
&lt;/h1&gt;

&lt;p&gt;I want to share some early React/CSS code for displaying the game board, &lt;a href="https://romansery.github.io/react-monopoly-board/"&gt;you can see it here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also find the &lt;a href="https://github.com/RomanSery/react-monopoly-board"&gt;full source here&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Planned game features
&lt;/h1&gt;

&lt;p&gt;One of the features of the game will allow players to create and save their own themes. Other players will be able to select from a list of existing themes. The demo is NYC-themed and you will be able to create your own by giving custom names to the squares.&lt;/p&gt;

&lt;p&gt;Instead of having the player that lands on a square immediately purchase it, there will be a new auction system. There will also be more trading and negotiation possibilities between players including loans and rent forgiveness. &lt;/p&gt;

&lt;p&gt;If you’re familiar with RPG video games, there will be some elements of that as well. Similar to collecting $200 when you pass GO, each player will also receive ability points they can put into a variety of categories.&lt;/p&gt;

&lt;h1&gt;
  
  
  About the code
&lt;/h1&gt;

&lt;p&gt;The GameBoard component renders a set of GameSquare components. Each square is assigned an id that used to lookup configuration data. SquareConfigData configures various properties for each square such as color, position, type, and group.&lt;/p&gt;

&lt;p&gt;The components in the squares folder are different display implementations that are used by the different square types. &lt;/p&gt;

&lt;p&gt;To change the theme data, just change the names in NyThemeData.&lt;/p&gt;

</description>
      <category>react</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Please dont use client-specific release branches</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Fri, 28 Aug 2020 20:14:05 +0000</pubDate>
      <link>https://dev.to/romansery/please-dont-use-client-specific-release-branches-3oeg</link>
      <guid>https://dev.to/romansery/please-dont-use-client-specific-release-branches-3oeg</guid>
      <description>&lt;p&gt;Recently there was a debate about using client-specific release branches in an attempt to protect them from change. A little background, the software is used by multiple clients. Each client might have a different release deployed to production and new releases of the software are developed every 2 weeks.&lt;/p&gt;

&lt;p&gt;There was an idea about using client-specific releases with the intent of isolating them from change to somehow protect those clients from bugs. Let’s take a look at the two approaches.&lt;/p&gt;

&lt;h1&gt;
  
  
  All clients use the same release branches – Unidirectional updates
&lt;/h1&gt;

&lt;p&gt;Not having client-specific branches is very nice. Any changes you make in one release branch is merged into all subsequent branches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bk-vs2nP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/08/releases.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bk-vs2nP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/08/releases.png" alt="good flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let’s say you make a change in 1.0, it gets merged all the way up to 1.3. If one client is using 1.1 and another 1.3, it doesn’t cause any problems. They will all eventually get all bug fixes/updates. &lt;/p&gt;

&lt;p&gt;As long as the direction of updates always flows in one direction you’ll be very happy. You will have very few merge conflicts if all changes are merged in a timely manner.&lt;/p&gt;

&lt;h1&gt;
  
  
  Client-specific branches – Bidirectional updates
&lt;/h1&gt;

&lt;p&gt;Now let’s look at the mess that’s created with client-specific branches. Let’s say clients FAS and MST use their own branches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BTpst76z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/08/releases2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BTpst76z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/08/releases2.png" alt="bad flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are three majors problems with this approach because we are introducing bidirectional update flows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Now the process of making changes to 1.0 involves merging into 1.0.FAS and later, into 1.2.MST. The other scenario is when FAS requests changes, you need to merge 1.0.FAS into 1.0 and then do your regular merging. &lt;strong&gt;This causes a lot of extra work and results in more merge conflicts.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As soon as FAS switches to using 1.0.FAS, &lt;strong&gt;they will stop receiving all bugfixes/improvements that are applied to 1.0.&lt;/strong&gt; In the effort to isolate FAS from change, it now exists outside of the standard flow of updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now we are making it very difficult for developers to do refactorings/re-structuring of code because it will be extremely difficult to merge. Suppose a developer has worked on significant re-structuring for 1.2. It was merged into 1.3. However, after a few days of being happy, MST now wants changes. Unfortunately, it’s well behind 1.2 and has stopped receiving all updates. You can make the changes directly to 1.2.MST, but in order to merge those into 1.2 and all subsequent branches will be very difficult if not impossible.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Code improvements matter
&lt;/h1&gt;

&lt;p&gt;Another troubling concept came out of these discussions related to #3 above. It seems some people have the notion that code improvements, whether it’s performance improvements or code structure improvements, don’t matter. Clients don’t see code improvements and usually don’t notice performance improvements, therefore they don’t matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This idea is absurd and very dangerous.&lt;/strong&gt; First of all, the goal of performance improvements is for the client not to notice them. As the number of concurrent users/traffic increases, clients should see no change in performance. The only way to accomplish that is to prioritize regularly looking for bottlenecks and other areas of improvement. &lt;strong&gt;Clients will most certainly notice performance degradation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While it’s true that clients usually don’t see the actual code improvements directly, they experience the many benefits of them. If code improvements are regularly prioritized, they experience less future bugs, greater developer productivity, a software product that is easier to change, and more confidence in implementing new significant features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So please never make the mistake of thinking client satisfaction and regular prioritized code improvements don’t go hand in hand.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Launching LetsDefinitely.com – A dating website, feedback wanted</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Mon, 03 Aug 2020 12:29:58 +0000</pubDate>
      <link>https://dev.to/romansery/launching-letsdefinitely-com-a-dating-website-feedback-wanted-201i</link>
      <guid>https://dev.to/romansery/launching-letsdefinitely-com-a-dating-website-feedback-wanted-201i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vPT-_Cp0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ft81g8weow3e2kwzxrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vPT-_Cp0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ft81g8weow3e2kwzxrt.png" alt="LetsDefinitely.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m excited to announce the launch of &lt;a href="https://www.letsdefinitely.com/"&gt;LetsDefinitely.com&lt;/a&gt;, a dating site that I have wanted to make for a while now. Its design is closely based on the teachings of someone I respect; dating and relationship expert &lt;a href="https://understandingrelationships.com/"&gt;Corey Wayne&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The core concept of making definite plans, by setting a specific date, time, and place to meet leads to more kept dates and less frustrating situations of being stood up. When two people make definite plans it shows they respect and value each other’s time and are looking forward to seeing each other.&lt;/p&gt;

&lt;h1&gt;
  
  
  Highlights
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Inviting users on dates
&lt;/h3&gt;

&lt;p&gt;When someone catches your interest and you would like to possibly set up a date, you will send them a message along with what you will like to do on the date, where, and when. &lt;strong&gt;Don’t worry about scheduling just yet&lt;/strong&gt;, this is designed to show that you are serious about meeting and not a time-waster. Once the other person responds and is interested you can iron out the details of the exact date and time.&lt;/p&gt;

&lt;p&gt;Once you’ve both accepted the date, make every effort to show up. Making definite plans means there is no need for confirmations and no flaky responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Messaging before the date
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Are you tired of endless messaging that leads nowhere?&lt;/strong&gt; We still allow a limited number of messages to be exchanged between you two to get to know a bit about the other person before the date. As well as to help you decide if you want the date! Studies have shown that too much virtual communication before a date leads to less fulfilling dates. People present themselves the best in person, so let them do it. Virtual messaging is unnatural and can lead to misunderstandings.&lt;/p&gt;

&lt;h3&gt;
  
  
  After the date
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Should I call after the date? Does she want another date? Does he want to see me again?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These kinds of questions cause unnecessary confusion. After the date, both of you will be asked to give your feedback on a 2nd date. No more guesswork! If you like, you can go into detail, but it isn’t necessary. You can simply indicate if you would like another date.&lt;br&gt;
Tech&lt;/p&gt;

&lt;p&gt;If you’re reading this you probably at least have some interest in the code. Backend is written in Java using Spring Boot. I use SendGrid for sending emails and Google Firebase for image storage. I use AWS beanstalk for hosting and a MySQL RDS instance for the database.&lt;/p&gt;

&lt;p&gt;The frontend uses Bootstrap, Jquery (gasp), and Thymleaf.&lt;/p&gt;

&lt;p&gt;If you’re interested in any specific part of the code or specific features, please comment below.&lt;br&gt;
Feedback&lt;/p&gt;

&lt;p&gt;I would welcome any feedback and suggestions you might have for me, so please &lt;a href="https://www.letsdefinitely.com/"&gt;check it out!&lt;/a&gt; Thanks.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>java</category>
    </item>
    <item>
      <title>Customizing your codebase per customer: Part 2 – Conditions</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Sun, 26 Apr 2020 17:21:25 +0000</pubDate>
      <link>https://dev.to/romansery/customizing-your-codebase-per-customer-part-2-conditions-4180</link>
      <guid>https://dev.to/romansery/customizing-your-codebase-per-customer-part-2-conditions-4180</guid>
      <description>&lt;p&gt;In &lt;a href="https://www.coderdreams.com/customizing-your-codebase-for-each-customer-using-enumerations/"&gt;part 1, we discussed using a “SiteConfig” enumeration&lt;/a&gt; to easily allow toggling features on or off depending on the needs of the specific customer/client. The enumeration would contain different items usually representing a boolean value for toggling features of the site.&lt;/p&gt;

&lt;p&gt;That approach is fine for some purposes but is a bit limited and inflexible when you need more complex variations among customers. It might not just be a matter of toggling features. It’s very likely that for some areas of functionality, their requirements will vary greatly among different customers.&lt;/p&gt;

&lt;p&gt;Let’s look at a more flexible solution using Spring framework conditional service classes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Defining a CustomerType
&lt;/h1&gt;

&lt;p&gt;The first thing we will do is define an enumeration containing all of our customers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;CustomerType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;FB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;GOOGLE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;MSFT&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, using &lt;em&gt;CustomerType&lt;/em&gt;, let’s create a helper class that will define customer conditions. &lt;strong&gt;A customer condition is used to tell Spring which version of our service class to use depending on the current customer.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomerConditions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FbCondition&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Condition&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConditionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedTypeMetadata&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;isMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoogleCondition&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Condition&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConditionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedTypeMetadata&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;isMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GOOGLE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;


    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerType&lt;/span&gt; &lt;span class="n"&gt;customerType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ConditionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEnvironment&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCustomer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;customerType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Creating our service classes
&lt;/h1&gt;

&lt;p&gt;Our service classes will contain all the business logic for our application (in theory!). What we would like to do is have a single class that will contain the default functionality and separate customer-specific classes which can override some or all of the defaults.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SiteFunctions&lt;/strong&gt; - Our default functionality/logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FbSiteFunctions&lt;/strong&gt; - Will contain overrides for one of our wonderful customers Facebook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GoogleSiteFunctions&lt;/strong&gt; - Overrides for another great customer, Google.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this simple example, we will only have a single overridable function that will determine if a user account can be deleted. It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;SiteFunctions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;canDeleteUserAccounts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//by default only allow deleting user accounts if inactive&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="o"&gt;;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt; &lt;span class="nd"&gt;@Conditional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FbCondition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FbSiteFunctions&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SiteFunctions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;canDeleteUserAccounts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//FB wants to be able to delete accounts regardless of status&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt; &lt;span class="nd"&gt;@Conditional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GoogleCondition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoogleSiteFunctions&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SiteFunctions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;canDeleteUserAccounts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Google doesnt want to ever delete user accounts&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice in the two highlighted lines, we are using the helper conditions we talked about earlier. &lt;strong&gt;When doing dependency injection, this will tell Spring to pick the correct implementation of SiteFunctions depending on the current customer.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How to use in our web app
&lt;/h1&gt;

&lt;p&gt;Now we have everything we need to use this in our web app. Let’s create a simple test page which will be given a User object and determine if it can be deleted. &lt;strong&gt;Notice that it doesn’t need to have any awareness for which customer this code is being executed:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomerTestPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WebPage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@SpringBean&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;SiteFunctions&lt;/span&gt; &lt;span class="n"&gt;siteFunctions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CustomerTestPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;        
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setActive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setMarkup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Markup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Can delete user: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;siteFunctions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canDeleteUserAccounts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The key is to always reference our default &lt;em&gt;SiteFunctions&lt;/em&gt; interface as opposed to the customer-specific overrides. Spring will take care of making sure the correct implementation is injected via the &lt;em&gt;@SpringBean annotation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this case, the above code would return false because our default functionality says that an active user cannot be deleted. However, If we execute this application with the customer JVM parameter set to “FB”, it will return true.&lt;/p&gt;

&lt;p&gt;The full &lt;a href="https://github.com/RomanSery/codesnippets/blob/master/src/main/java/org/coderdreams/conditions/CustomerConditions.java"&gt;source code can be found on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>design</category>
    </item>
    <item>
      <title>Why you should favor composition over inheritance</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Tue, 10 Mar 2020 15:12:11 +0000</pubDate>
      <link>https://dev.to/romansery/why-you-should-favor-composition-over-inheritance-57m6</link>
      <guid>https://dev.to/romansery/why-you-should-favor-composition-over-inheritance-57m6</guid>
      <description>&lt;p&gt;Composition has always had some advantages over inheritance.  Creating deep inheritance hierarchies leads to brittle/inflexible code when you are trying to make changes deep in the hierarchy.&lt;/p&gt;

&lt;p&gt;There have been two key improvements made to interfaces in Java 8 and above, that make the argument for composition even stronger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default methods&lt;/strong&gt; - This allows you to define methods with a default implementation inside of interfaces.  Classes that implement the interface can choose to override default methods or keep them as is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private/Static methods&lt;/strong&gt; - In this way, it becomes easier to write default functionality for an interface using private helper methods that should not be exposed as part of the interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at an example where we can use composition along with the new functionality of interfaces.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building a Human with composition
&lt;/h1&gt;

&lt;p&gt;Let's create a class that will represent a biological human.  We can imagine that a human being is composed of many different systems that work together in order for the human to function.  There's the skeletal system, cardiovascular system, immune system, nervous system, and so on.&lt;/p&gt;

&lt;p&gt;In this oversimplified example, we can think of each system as being an interface.  Our human class will implement each of these interfaces:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z4O0x7Cr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/03/composition.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z4O0x7Cr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/03/composition.png" alt="Class diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great!  &lt;strong&gt;Now, what if we want to create a new biological organism that shares a lot of traits with humans, but doesn't have a skeletal system?&lt;/strong&gt;  This illustrates the major advantage of composition.  We can do this by simply creating a new class that implements only 2 out of the 3 systems:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AZ1d7if8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/03/composition_contortionist.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AZ1d7if8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.coderdreams.com/wp-content/uploads/2020/03/composition_contortionist.png" alt="Class diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using default and private methods
&lt;/h1&gt;

&lt;p&gt;Now we can write a simple skeletal system interface and see how a human might implement it.  We will demonstrate private and default interface methods, as well as interface fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;SkeletalSystem&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bone&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Joint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;joints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getSex&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addBone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bones&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;recalculateJointHealth&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addJoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Joint&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;joints&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;recalculateJointHealth&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getBoneMass&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bones&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Bone:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getMass&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;recalculateJointHealth&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Joint&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;joints&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//... do something&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Bone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getMass&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setMass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Joint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Joint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;b1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;b2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="nf"&gt;getB1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setB1&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;b1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="nf"&gt;getB2&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setB2&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;b2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getStrength&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setStrength&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strength&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For brevity, SkeletalSystem is presented as a fully self-contained interface.  It defines the Bone and Joint classes and collections for storing them.  There are default methods for adding bones and joints, as well as private helper methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Human&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SkeletalSystem&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Human&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;lfemur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LFemur"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Bone&lt;/span&gt; &lt;span class="n"&gt;lHip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lHip"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;addBone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lfemur&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;addBone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lHip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;addJoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Joint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lfemur&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lHip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getBoneMass&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getHeight&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getWeight&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setWeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getSex&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our Human class defines it's own data fields and uses the SkeletalSystem to add some bones and joints.  We could also create helper methods that could initialize the SkeletalSystem using a standard human bone structure.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this example will help you choose composition over inheritance when it's appropriate.  Rember this basic rule when deciding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose inheritance when modeling a &lt;strong&gt;"is-a"&lt;/strong&gt; relationship.

&lt;ul&gt;
&lt;li&gt;A senior citizen is a citizen.&lt;/li&gt;
&lt;li&gt;A standing desk is a desk.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Choose composition when modeling a &lt;strong&gt;"has-a"&lt;/strong&gt; relationship.

&lt;ul&gt;
&lt;li&gt;A human has a skeletal system, cardiovascular system, etc.&lt;/li&gt;
&lt;li&gt;A car has an engine, a transmission, gas tank, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>oop</category>
    </item>
    <item>
      <title>Creating a release info dashboard</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Thu, 13 Feb 2020 23:03:44 +0000</pubDate>
      <link>https://dev.to/romansery/creating-a-release-info-dashboard-ji7</link>
      <guid>https://dev.to/romansery/creating-a-release-info-dashboard-ji7</guid>
      <description>&lt;p&gt;Hopefully, you are in the position of having an online software product/website with multiple clients. The problem you run into when deploying to multiple clients and environments is keeping track of which release is where. Let’s also assume that you have testing, stage, and production environments for each client; that quickly becomes a headache.&lt;/p&gt;

&lt;p&gt;In this post, we look at how to create a simple dashboard for displaying this info. There are three basic steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the git-commit-id-plugin maven plugin in your project to output the brach and commit information to a file.&lt;/li&gt;
&lt;li&gt;Create an HTTP endpoint for retrieving the deployed branch.&lt;/li&gt;
&lt;li&gt;Create a page that will invoke these endpoints and display them in a table.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Creating git properties&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step is to make our project create a file with the git repository info at build time. To accomplish this, we will use the &lt;a href="https://github.com/git-commit-id/git-commit-id-maven-plugin"&gt;git-commit-id-plugin&lt;/a&gt; plugin. Let’s add the plugin in our pom.xml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;pl.project13.maven&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;git-commit-id-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;get-the-git-infos&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;revision&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;initialize&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;generateGitPropertiesFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/generateGitPropertiesFile&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;generateGitPropertiesFilename&amp;gt;&lt;/span&gt;${project.build.outputDirectory}/git.properties&lt;span class="nt"&gt;&amp;lt;/generateGitPropertiesFilename&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;commitIdGenerationMode&amp;gt;&lt;/span&gt;full&lt;span class="nt"&gt;&amp;lt;/commitIdGenerationMode&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;format&amp;gt;&lt;/span&gt;properties&lt;span class="nt"&gt;&amp;lt;/format&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we do a maven build, a file named git.properties will be created that will have all of the information about the branch, build, and last commit info.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next step is to expose an HTTP endpoint in our application that will use git.properties to return the current git branch. We will use &lt;a href="https://github.com/wicketstuff/core/tree/master/wicketstuff-restannotations-parent"&gt;Wicket-rest annotations&lt;/a&gt; which is a great library for creating REST endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VersionDetailsEndpoints&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractRestResource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JsonWebSerialDeserial&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;VersionDetailsEndpoints&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonWebSerialDeserial&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JacksonObjectSerialDeserial&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@MethodMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;details&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;getCurrentWebResponse&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Origin"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ApplicationDetailsService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBranch&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/RomanSery/codesnippets/blob/master/src/main/java/org/coderdreams/service/ApplicationDetailsService.java"&gt;ApplicationDetailsService&lt;/a&gt; is a simple utility class that reads and parses the generated git.properties file from our maven build process. We also set the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSMissingAllowOrigin"&gt;CORS header&lt;/a&gt; to allow invoking this endpoint using Javascript from a different domain as will be necessary for the last step.&lt;/p&gt;

&lt;p&gt;We register it in our WebApplication init() method by mounting a resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;mountResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/releaseinfo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResourceReference&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/releaseinfo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;            
    &lt;span class="nc"&gt;VersionDetailsEndpoints&lt;/span&gt; &lt;span class="n"&gt;versionDetailsEndpoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VersionDetailsEndpoints&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;IResource&lt;/span&gt; &lt;span class="nf"&gt;getResource&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Injector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;versionDetailsEndpoints&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;versionDetailsEndpoints&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Creating the dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now the fun part! We will use the Javascript fetch API to iterate a map of clients and URL’s, invoking the /releaseinfo endpoint for each and populate a table with the results. The below code will go into the HEAD section of our HTML page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;urlMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nx"&gt;urlMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ABC Corp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test.abc.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stage.abc.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;urlMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oracle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test.oracle-coderdreams.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stage.oracle-coderdreams.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oracle-coderdreams.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;urlMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Microsoft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test.ms.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stage.ms.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ms-coderdreams.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;urlMap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ /g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#releasesTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;tr id="&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;urlMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tdNum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/releaseinfo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;getReleaseBranch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; td:nth-child(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tdNum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; td:nth-child(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tdNum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; td:nth-child(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tdNum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-danger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getReleaseBranch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We need to make sure that the fetch call does not hit the browser cache which is done by passing the “no-store” argument. If we fail to get a response from the endpoint we highlight that in the table as an error. &lt;/p&gt;

&lt;p&gt;You can also add other useful info to this dashboard such as database connectivity, the status of some ‘health’ check, number of active users; use your imagination!&lt;/p&gt;

&lt;p&gt;The full dashboard code along with the HTML can be found on &lt;a href="https://github.com/RomanSery/codesnippets/blob/master/src/main/java/org/coderdreams/webapp/release_info.html"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>git</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Five reasons you should use Apache Wicket</title>
      <dc:creator>Roman Sery</dc:creator>
      <pubDate>Mon, 03 Feb 2020 02:16:49 +0000</pubDate>
      <link>https://dev.to/romansery/five-reasons-you-should-use-apache-wicket-1lij</link>
      <guid>https://dev.to/romansery/five-reasons-you-should-use-apache-wicket-1lij</guid>
      <description>&lt;p&gt;Apache Wicket is a java-based web development framework.  I feel it doesn't get as much attention as it deserves.  I've been using Wicket professionally for real-world projects for the past 6 years and love it! &lt;/p&gt;

&lt;p&gt;In this post, let's look at five reasons why you should consider using it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Simple state management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The development experience writing Wicket apps is very similar to desktop development.  At times you can almost forget about the stateless nature of HTTP.  This is because in Wicket the web page and all of it's components (buttons, text fields, etc) are Java objects that maintain their own state.  The state of the components gets serialized into the user's session, and deserialized at the appropriate times.&lt;/p&gt;

&lt;p&gt;In simpler terms, suppose you have a form with fields that a user would fill out and submit.  In a Wicket app, this form, it's fields, and the submit button are all components(Java objects) that are created and added to the web page.  When the submit button is clicked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We automatically have access to the user input, usually as fields of a POJO.&lt;/li&gt;
&lt;li&gt;We don't have to connect the HTTP POST request to the GET request.&lt;/li&gt;
&lt;li&gt;We also do not need to think about populating the form fields with the submitted values.  This is done through &lt;a href="https://www.coderdreams.com/understanding-wicket-models/"&gt;Models&lt;/a&gt; which are a core Wicket concept.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Standard HTML integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;HTML in Wicket doesn't require any special tags unlike some other frameworks.  In fact you can take any existing HTML and integrate it with your Wicket app with almost no changes.  There is only one attribute that is needed to connect HTML tags to Wicket components: &lt;strong&gt;wicket:id&lt;/strong&gt;  Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;wicket:id=&lt;/span&gt;&lt;span class="s"&gt;"userName"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Roman&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Label&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"userName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;wicket:id&lt;/em&gt; "userName" is used to connect the HTML element with the Wicket component. The Wicket Label component will get the user name and render a &lt;em&gt;div&lt;/em&gt; tag.  It's okay if this doesn't totally make sense right now.  It becomes second nature and intuitive when you start playing around with it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wicket components are first-class citizens and can encapsulate their own HTML markup/CSS/JS just like in some popular frameworks such as React.  Allowing us to create highly-reusable code.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. No Javascript needed (mostly)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Okay obviously, you will end up writing JS code at some point.  However the AJAX support provided by Wicket means you don't need to write your own JS code for most common tasks.  Behind the scenes, Wicket uses JQuery and automatically generates the JS code into the web page.&lt;/p&gt;

&lt;p&gt;Let's take a simple example of a page with a dropdown and various other components that depend on the selection of that dropdown.  When the selection changes, we need to update these various other components on the page.  &lt;strong&gt;This actually doesn't require any Javascript code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This makes Wicket ideal for building complex interfaces with convoluted business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Event/messaging system&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Wicket events are a way for components and pages to communicate with each other.  Using this feature we can create &lt;strong&gt;very complex, yet decoupled, component structures&lt;/strong&gt;.  A component can broadcast a message without needing to know who will receive the message.  When a component is interested in a particular type of message, it can simply register to be notified when that message is broadcast.&lt;/p&gt;

&lt;p&gt;A component might broadcast a critical update event with payload to all other components on the page in this manner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getPage&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Broadcast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BREADTH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CriticalUpdate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And if some component is interested in receiving &lt;em&gt;CriticalUpdate's&lt;/em&gt;, it would register like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPayload&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;CriticalUpdate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;CriticalUpdate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPayload&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
      &lt;span class="c1"&gt;//do something with the msg&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5. Unit testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The component/stateful nature of Wicket means that we can write unit tests for the front-end just like we would write them for the service layer, or our data access layer.  Wicket provides helpful utilities to make writing unit tests simple.&lt;/p&gt;

&lt;p&gt;Let's take an example of a simple scenario that might not be so straight forward to test in other frameworks.  We have a web page with a CRUD interface:  a table with baby names and delete buttons.  A form with a text field and button for adding new rows to the table.&lt;/p&gt;

&lt;p&gt;We can write a test that will render the page, simulate a user filling out and submitting the form, ensuring the table is updated correctly, simulate the user pressing the delete button, and so on. &lt;strong&gt;This can all be accomplished using pure Java code and JUnit without resorting to Selenium, Puppeteer or similar libraries.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Fully open source&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Ok I did say five reasons, but here's a bonus: Wicket is fully open source and the code is designed to be easily extendable/customizable.  Whenever you run into a scenario where the default behavior or functionality doesn't quite meet your needs, it's as simple as overriding a few methods, or extending a class to make it work exactly as you need!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I hope you've heard enough to give Wicket a try.  If you're curious to learn more:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wicket.apache.org/learn/"&gt;Head over to the official site which contains great documentation &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Take a look the &lt;a href="http://examples8x.wicket.apache.org/index.html"&gt;example code&lt;/a&gt; which provides code for many common web dev scenarios.&lt;/li&gt;
&lt;li&gt; Take a look at &lt;a href="http://examples8x.wicket.apache.org/index.html"&gt;my blog CoderDreams&lt;/a&gt; where I regularly post about Wicket and other web development topics.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>java</category>
    </item>
  </channel>
</rss>
