<?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: Tô Minh Thành</title>
    <description>The latest articles on DEV Community by Tô Minh Thành (@minhthanh3145).</description>
    <link>https://dev.to/minhthanh3145</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%2F180040%2F7587ad95-7f92-4512-941e-e5b8ad70ef01.jpeg</url>
      <title>DEV Community: Tô Minh Thành</title>
      <link>https://dev.to/minhthanh3145</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/minhthanh3145"/>
    <language>en</language>
    <item>
      <title>Get everyone out of the building - or how Product Managers are like Fire Fighters</title>
      <dc:creator>Tô Minh Thành</dc:creator>
      <pubDate>Sat, 01 Jan 2022 09:20:38 +0000</pubDate>
      <link>https://dev.to/minhthanh3145/get-everyone-out-of-the-building-or-how-product-managers-are-like-fire-fighters-5fdm</link>
      <guid>https://dev.to/minhthanh3145/get-everyone-out-of-the-building-or-how-product-managers-are-like-fire-fighters-5fdm</guid>
      <description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;

&lt;p&gt;It has been (almost) a year since I've become a product manager. The journey has been nothing short of fun and excitement. I learned a lot of things along the way, and I also shared many of them (on &lt;a href="https://dafuqis-that.com/2021/10/13/how-product-development-frameworks-work-together-to-enable-actions/"&gt;Product Strategy&lt;/a&gt; and &lt;a href="https://dafuqis-that.com/2021/10/13/how-product-development-frameworks-work-together-to-enable-actions/"&gt;Product Development Frameworks&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Last week, I was reflecting on what are the most important ideas that will become my closing remark on 2021 with respect to my professional life. Some ideas came to mind, and I've been trying to flesh them out and combine them into something that sounds profound (lol). Though, I must say I'm quite amused by what I've come up with, regardless of how profound it actually is.&lt;/p&gt;

&lt;p&gt;Hopefully, by the end of this blog post, you would share some of my amusement.&lt;/p&gt;

&lt;h2 id="a-naive-application-of-get-out-of-the-building-is-subtly-problematic"&gt;A naive application of "Get out of the building" is subtly problematic&lt;/h2&gt;

&lt;p&gt;One of the ideas I've taken seriously this year is "Get out of the building". I had to shift from building software according to requirements to determining what is the most important thing to build. This means to get out of my own head, get in touch with customers and try to understand their problems as clearly as I can.&lt;/p&gt;

&lt;p&gt;But that's not the main idea I want to talk about. In fact, I want to warn you against a naive application of this advice. If we naively try to apply "Get out of the building", we may end up with a paradigm that isn't wrong in any obvious way. It doesn't result in dismal failures, but it also doesn't lead to a sustainable impact either.&lt;/p&gt;

&lt;p&gt;In this paradigm, product managers "get out of the building" and go talk to customers to understand their needs and pain points. Then they come up with an idea about a solution. Then they work with designers to create mockups, and work with business analysts to create detailed requirements. These artifacts then are handed off to engineers who will build the software. There are testers who make sure that all the requirements are strictly adhered to. We may also incorporate usability testing, as well as gathering feedbacks to validate our solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpCr6QYR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2021/12/screen-shot-2021-12-31-at-17.12.52.png%3Fw%3D996" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpCr6QYR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2021/12/screen-shot-2021-12-31-at-17.12.52.png%3Fw%3D996" alt="" width="880" height="905"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While  it isn't wrong in any obvious way, there are two problems with this paradigm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A naive application of "Get out of the building" overestimates the ability of an individual to solve wicked problems.&lt;/li&gt;
&lt;li&gt;A naive application of "Get out of the building" creates an alignment problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id="it-overestimates-the-ability-of-an-individual-to-solve-wicked-problems"&gt;It overestimates the ability of an individual to solve wicked problems&lt;/h3&gt;

&lt;p&gt;One problem is that it overestimates the ability of a product manager (or any individual for that matter) to be able to identify the right user problem, come up with the right idea for a solution that addresses both customer and business problems, &lt;em&gt;without&lt;/em&gt; invoking a wide range of expertise that's most likely only possible by involving others early on.&lt;/p&gt;

&lt;p&gt;Of course, a good product manger must have sophisticated mental models about the business as well as the users. But even then, choosing which problems to pursue, deciding which ideas are testable, usable, lovable are wicked problems that require more than one person.&lt;/p&gt;

&lt;p&gt;For example, if you want to build a delightful product, you must have a delightful user experience. While PMs need to know about UX, it's not exactly our expertise. On the other hand, designers know a lot of things about UX, but they can't exercise their expertise optimally if they're working on prescribed solution ideas.&lt;/p&gt;

&lt;h3 id="it-creates-an-alignment-problem"&gt;It creates an alignment problem.&lt;/h3&gt;

&lt;p&gt;It also leads to an alignment problem, because we're cutting everyone else from accessing the understanding acquired from talking to customers. As a consequence, it isn't clear how our work affects our customers, or whether what we do is worth doing at all.&lt;/p&gt;

&lt;p&gt;There probably are engineers who only enjoy solving technical problems and don't care much about anything else, but it's safe to assume that most people are more motivated to work when they understand the bigger picture of which user understanding forms an important part. Otherwise, it is very easy to feel disconnected and disempowered, especially when we're doing hard things such as product.&lt;/p&gt;

&lt;p&gt;Having a team that's not properly aligned doesn't have immediate consequence, but silent disagreements, lack of a reason to do their best work, and other subtle side effects will ultimately manifest in very real ways.&lt;/p&gt;

&lt;h3 id="it-prevents-everyone-else-from-building-up-shared-user-understanding"&gt;It prevents everyone else from building up shared user understanding&lt;/h3&gt;

&lt;p&gt;By assigning the responsibility of talking to users to PMs only, we're preventing everyone else from building up user understanding themselves. It may work for a short period of time, but such a configuration is fragile in the long run. What happens if the product manager leaves? The user understanding in that person's head will also be gone. It's a single point of failure system that becomes stale or chaotic whenever failure occurs at the critical point. The cost of hiring and training new product managers to obtain the equivalent level of understanding is sometimes prohibitively expensive, especially if your product exists in a niche category.&lt;/p&gt;

&lt;h2 id="taking-the-idea-of-building-shared-understanding-seriously"&gt;Taking the idea of "Building shared understanding" seriously&lt;/h2&gt;

&lt;p&gt;A naive application of "Get out of the building" is subtly problematic. One such problem is the alignment problem that results from a lack of shared understanding. The idea of building shared understand isn't new, but I think it hasn't been taken seriously enough. Cedric at &lt;a rel="noreferrer noopener" href="https://commoncog.com/blog/"&gt;Commonplace&lt;/a&gt; wrote a wonderful blog post on &lt;a rel="noreferrer noopener" href="https://commoncog.com/blog/take-a-simple-idea-and-take-it-seriously/"&gt;taking a simple idea and take it seriously&lt;/a&gt; . When we have an idea that's simple and useful, we should examine the second and third order implications before moving on.&lt;/p&gt;

&lt;p&gt;Building shared understanding requires you to shift your perspective from "how do I enable everyone to work as effectively as possible?" to "how do I empower everyone to participate and co-create the picture that we're building towards". &lt;/p&gt;

&lt;p&gt;Implementing this would run into practical constraints real quick, but it's important to fix the idea and work around the constraints, rather than distorting the idea itself.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Taking the idea of building shared understand seriously means encouraging everyone to participate in discovery and shaping work.&lt;/li&gt;
&lt;li&gt;Taking the idea of building shared understanding seriously means looking requirements as stories that we build, understand and agree collaboratively.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id="seriously-encouraging-everyone-to-participate-in-discovery-and-shaping-work"&gt;Seriously encouraging everyone to participate in discovery and shaping work&lt;/h3&gt;

&lt;p&gt;In a big team, not everyone can and should be involved in everything. But if you take this idea seriously enough, you will split the team into smaller squads, each responsible for a business objective. Everyone within the squad must be encouraged to participate in discovery sessions from which customer problems are identified and prioritized against their business objective. Everyone within the squad must be encouraged to participate in shaping the solutions that they will deliver. Participation isn't a "nice to have" thing, we must go out of our way to encourage and enforce it whenever possible.&lt;/p&gt;

&lt;h3 id="seriously-means-looking-requirements-as-stories-that-we-build-understand-and-agree-collaboratively"&gt;Seriously means looking requirements as stories that we build, understand and agree collaboratively&lt;/h3&gt;

&lt;p&gt;It also requires you to stop looking at requirements as something that need to be strictly followed, and start looking at them as "stories" that we collaboratively build, understand and agree upon. It's the story conversations which produces user stories that matter the most, not the &lt;em&gt;user stories&lt;/em&gt; themselves, which are merely the outputs. &lt;/p&gt;

&lt;p&gt;Shared documents aren't shared understanding. Effective story conversations build shared understanding, and a user story acts as a placeholder for conversations. &lt;/p&gt;

&lt;p&gt;This idea is built into the user story itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Card&lt;/strong&gt;. A written description of the story used for planning and as a reminder (originally written on paper note cards).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversation&lt;/strong&gt;. Conversations about the story to flesh out the details. Development team and customers should discuss details only when details become important.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirmation&lt;/strong&gt;. Tests that convey and document details to determine when a story is complete. Test descriptions are meant to be short and incomplete. They are to convey information so that the developers will know when they are done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LLb03jRL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2021/12/screen-shot-2021-12-12-at-15.16.21.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LLb03jRL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2021/12/screen-shot-2021-12-12-at-15.16.21.png%3Fw%3D1024" alt="" width="880" height="505"&gt;&lt;/a&gt;From User Story Mapping - Jeff Patton&lt;/p&gt;

&lt;p&gt;It's actually difficult to look at things this way, especially if you're used to certain rigid ways of working. It's much easier to treat requirements as something that shouldn't be questioned, because questioning may open the door to a world of unknown, which is frightening. It also requires product managers to stop focusing on writing elaborate and detailed requirements, and start involving people in the conversations that are messy and potentially full of dissent.&lt;/p&gt;

&lt;h2 id="trying-to-impose-order-on-a-complex-domain-doesn-t-great"&gt;Trying to impose order on a complex domain doesn't great&lt;/h2&gt;

&lt;p&gt;I suspect the underlying reason is that it's just easier to impose order on a complex situation than facing it head on. This also aligns with The Cynefin Framework. Here's an excerpt on the characteristic of the complex domain, as characterized by The Cynefin Framework (emphasis mine):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the domain of complexity, where patterns emerge through interaction of sub-systems. Emergent patterns can be perceived but not predicted, and understanding only happens in retrospect. The range is defined by a number of key metrics, but the outcome may lie anywhere. In this context, a leader should patiently allow the path forward to reveal itself rather than imposing a course of action. Create probes to make patterns more visible before taking any action. Then stabilize desired patterns and destabilize undesired ones. Leaders must allow patterns to emerge, detect them and then discern which one should be allowed to continue growing. In this domain, we should fail fast, learn fast, and fail safely.&lt;/p&gt;
&lt;p&gt;In this domain, the performing methodology is an evolutionary approach, where systems are developed while acknowledging that the user need is not fully understood. User needs and requirements are partially defined up-front, but then refined in each succeeding build. Customer feedback should be used to enhance the capabilities of a future version of the system.&lt;/p&gt;
&lt;p&gt;The dominant leadership style in this domain is adaptive leadership. A representative model of adaptive leadership methodology is the OODA loop (observation, orientation, decision and action). In exercising adaptive leadership, the goal is to make observing as objective as possible. Once observed, a leader must interpret the observed data from many perspectives. The decision and action should reflect the leaders' hypotheses about the problem.&lt;/p&gt;
&lt;p&gt;In this domain it's impossible to do detailed planning. Leaders should encourage open discussions, where people generate innovative ideas in order to overcome entrenched thinking. Authentic dissent and diversity are also encouraged to push the emergence of well-forged patterns. Leaders should watch for starting conditions and monitor the emergence of patterns.&lt;/p&gt;
&lt;p&gt;The primary risk in this domain is falling back to command-and-control style of management&lt;em&gt;. Desired results in complex domain are very difficult to be put forth, therefore resulting in impatience which cause leaders to fall back to inappropriate methods to demand safe fail. They may be too sensitive to failure which is require for experimentation. &lt;/em&gt;Leaders who try to impose order in a complex context will fail, while those who set the stage, step back a bit, allow patterns to emerge, and allow the desirable ones to grow will succeed&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;cite&gt;Fierro, Davide &amp;amp; Putino, Stefano &amp;amp; Tirone, Lucio. (2018). The Cynefin Framework and Technical Competencies: a New Guideline to Act in the Complexity. INCOSE International Symposium. 28. 532-552. 10.1002/j.2334-5837.2018.00498.x.&lt;br&gt;&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In conclusion, if we try to apply "get out of the building" in a naive way, we may run into at least two problems. I think incorporating the idea of "build shared understanding" would address both of them. By encouraging everyone to participate in the discovery and co-creation process, you no longer rely on a single individual to come up with solution ideas. It will vastly increase the chance that you're building the right thing. With everyone understanding the customer problems being solved, they are empowered and thus feel more responsible and connected to the work that they're doing.&lt;/p&gt;

&lt;p&gt;I realize that "get out of the building" is probably already an advice that's meant for everyone. But If I may rephrase the advice so that it incorporates a bit better the nuance that I've observed, I would call it &lt;strong&gt;&lt;em&gt;"Get everyone out of the building"&lt;/em&gt;&lt;/strong&gt;, which sounds like something that a Fire Fighter would say. Perhaps in this sense (and in many other senses in which both roles have to fight different kinds of fire), Product Managers are just like Fire Fighters.&lt;/p&gt;

&lt;p&gt;Well, that's it! I hope everyone has a great 2022.&lt;/p&gt;

</description>
      <category>product</category>
      <category>management</category>
      <category>career</category>
    </item>
    <item>
      <title>Why I built Another Writing Application</title>
      <dc:creator>Tô Minh Thành</dc:creator>
      <pubDate>Wed, 27 May 2020 19:16:59 +0000</pubDate>
      <link>https://dev.to/minhthanh3145/why-i-built-another-writing-application-3dno</link>
      <guid>https://dev.to/minhthanh3145/why-i-built-another-writing-application-3dno</guid>
      <description>&lt;h1&gt;
  
  
  Another Writing Application
&lt;/h1&gt;

&lt;p&gt;Originally posted &lt;a href="https://dafuqisthatblog.wordpress.com/2020/05/27/why-i-built-another-writing-application/" rel="noopener noreferrer"&gt;here in my blog&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Another writing application ? What for ?&lt;/li&gt;
&lt;li&gt;
Features

&lt;ul&gt;
&lt;li&gt;Add Source&lt;/li&gt;
&lt;li&gt;Search&lt;/li&gt;
&lt;li&gt;Export Data&lt;/li&gt;
&lt;li&gt;Changing location of sidebar&lt;/li&gt;
&lt;li&gt;Preview Markdown&lt;/li&gt;
&lt;li&gt;Feedback&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Technology stack:&lt;/li&gt;

&lt;li&gt;Timline and tasks&lt;/li&gt;

&lt;li&gt;

Deployment

&lt;ul&gt;
&lt;li&gt;Frontend&lt;/li&gt;
&lt;li&gt;Netlifly (Initial choice and final choice)&lt;/li&gt;
&lt;li&gt;Github page (Dropped due to weird styling thing)&lt;/li&gt;
&lt;li&gt;Backend&lt;/li&gt;
&lt;li&gt;Heroku (Initial choice)&lt;/li&gt;
&lt;li&gt;Openode (Final choice)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Final words&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;Why though ?&lt;/h2&gt;

&lt;p&gt;I think the ability to find insights give individuals unique competitive advantages. As someone who wants to thrive in this world, I decided that I want to obtain insights, at least in software development (which is what I do for a living).&lt;/p&gt;

&lt;p&gt;To find insights, you need to think effectively. To think effectively, you must make your thinking tangible, so that you can look and see what's ineffective. As far as I know, writings are the only tangible outcomes of thinking. Therefore I write a lot. However, writing is so difficult that, not all of my high-quality writings get published, and not all of my published writings are of high quality.&lt;/p&gt;

&lt;p&gt;When I write, I tend to read a lot of sources, oscillating between them as needed to compare and contrast ideas. After having some interesting thoughts, I will write them down. But such thoughts are often ostensible, or they hint at possibly new ways of interpreting existing information. So I switch back to the sources to reconcile the new thoughts with the sources. &lt;/p&gt;

&lt;p&gt;Sometimes the sources talk about multiple subjects, but I am only interested in one or just some keywords, I need to switch between them to look for the keywords and then read the surrounding text block. When you are pulling information from a lot of places, such switching increases cognitive load significantly, which reduces the processing power you can spend on actual thinking.&lt;/p&gt;

&lt;p&gt;I thought about it, and I think what is lacking is a workspace where I can search for keywords from relevant sources and write my thoughts, without having to leave the tab. &lt;em&gt;Another Writing Application&lt;/em&gt; is designed to be such a workspace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.32.29-pm-2.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.32.29-pm-2.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main features of Another Writing Application is Search Focus mode for retrieving sources containing specific terms. You can read the surrounding text blocks in Search Focus mode, or you can switch to Whole Text mode to read the entire thing if you like. Additionally, you can write your thoughts and have them autosaved, all without ever leaving the workspace.&lt;/p&gt;

&lt;p&gt;Another Writing Application isn't a note-taking tool. For taking notes, I used &lt;a href="https://roamresearch.com/" rel="noopener noreferrer"&gt;Roam Research&lt;/a&gt; obsessively. However, Roam is a note-taking tool, and it's not a writing workspace that serves the purpose of gathering sources and experiment with thoughts. On the opposite, you have to be mindful what to install into Roam, because it is designed to build a long-lasting repository , if you're following the &lt;a href="https://writingcooperative.com/zettelkasten-how-one-german-scholar-was-so-freakishly-productive-997e4e0ca125" rel="noopener noreferrer"&gt;Zettlkasten method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another Writing Application&lt;/strong&gt; is built as a place where you can dump your disorganized thoughts, organize them and then dump the organized thought into Roam or other places. In fact, I wrote this article using &lt;em&gt;AWA&lt;/em&gt;, with 7 references. It is not intended to replace anything, just an attempt in making writing, and consequently thinking, more convenient.&lt;/p&gt;

&lt;p&gt;Therefore, gathering sources, read, search for and experimental writing, all in the same place, is what &lt;strong&gt;Another Writing Application&lt;/strong&gt; is for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The application is publicly available &lt;a href="https://another-writing-application.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Features&lt;/h2&gt;

&lt;h3&gt;Add Source&lt;/h3&gt;

&lt;p&gt;When you add an URL to &lt;em&gt;AWA&lt;/em&gt;, it calls the server to extract content using &lt;a href="https://github.com/postlight/mercury-parser" rel="noopener noreferrer"&gt;Mercury Parser&lt;/a&gt; and insert that content into your local storage. The backend doesn't store anything, it just returns the extracted content. As you read your sources for the first time, drop the URL into this and continue reading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.17.25-pm.png%3Fw%3D952" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.17.25-pm.png%3Fw%3D952" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Search&lt;/h3&gt;

&lt;p&gt;When you have an interesting narrative, write it down. If you hit a term that summarizes a broad topic which you're trying to articulate, search for that term.&lt;/p&gt;

&lt;p&gt;By default, &lt;strong&gt;search-focus mode&lt;/strong&gt; is used. Search-focus mode separates a given source into paragraph blocks, and only display the blocks that contain the searched term. You can expand other blocks to see the surrounding context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.30.00-pm.png%3Fw%3D830" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.30.00-pm.png%3Fw%3D830" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want even more broader context of the searched result, switch to &lt;strong&gt;whole-text mode&lt;/strong&gt; to see the entire text of the source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.30.03-pm-1.png%3Fw%3D830" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-11.30.03-pm-1.png%3Fw%3D830" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Export Data&lt;/h3&gt;

&lt;p&gt;You can export the data in &lt;code&gt;json&lt;/code&gt; format. The exported file contains additional metadata extracted using Mercury Parser. Your writing will always has the ID &lt;code&gt;curren_note&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.13.40-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.13.40-am.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Changing location of sidebar&lt;/h3&gt;

&lt;p&gt;Some enjoys the sidebar on the right (like Roam).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.02-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.02-am.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But some would enjoy the sidebar on the left. You can change it either way. Please let me know which one you prefer more.&lt;/p&gt;

&lt;h3&gt;Preview Markdown&lt;/h3&gt;

&lt;p&gt;Using &lt;a href="https://github.com/markedjs/marked" rel="noopener noreferrer"&gt;Marked&lt;/a&gt; to produce a HTML string from your writing and display it in the modal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.12-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.12-am.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Feedback&lt;/h4&gt;

&lt;p&gt;See anything you don't like ? Please feedback so that I can improve it. I use &lt;a href="https://www.smtpjs.com/" rel="noopener noreferrer"&gt;SmtpJs&lt;/a&gt; to send the email, using my own email, so it is anonymous.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.17-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.14.17-am.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The application is publicly available &lt;a href="https://another-writing-application.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Technology stack:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: NodeJS, Express, &lt;a href="https://github.com/postlight/mercury-parser" rel="noopener noreferrer"&gt;Mercury Parser&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: &lt;a href="https://github.com/jorgebucaran/hyperapp" rel="noopener noreferrer"&gt;Hyperapp&lt;/a&gt;, Bootstrap, &lt;a href="https://github.com/spencermountain/compromise" rel="noopener noreferrer"&gt;Compromise&lt;/a&gt;, &lt;a href="https://github.com/pouchdb/pouchdb" rel="noopener noreferrer"&gt;PouchDB&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I love Hyperapp by the way. It’s a minimalist approach to building web application. The concepts that you need to learn are way less than React and other front-end frameworks.&lt;/p&gt;

&lt;h2&gt;Timline and tasks&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://agenda.com/" rel="noopener noreferrer"&gt;Agenda&lt;/a&gt; to keep my to-do and agenda. The entire process took me 6 days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-5.07.49-pm.png%3Fw%3D818" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-27-at-5.07.49-pm.png%3Fw%3D818" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are bug fixes and features that I don't explicitly add to the list, because I was in the flow.&lt;/p&gt;

&lt;h2&gt;Deployment&lt;/h2&gt;

&lt;h3&gt;Frontend&lt;/h3&gt;

&lt;h4&gt;Netlify (Initial choice and final choice)&lt;/h4&gt;

&lt;p&gt;I chose Netlify as a static hosting solution because its &lt;a href="https://www.netlify.com/tos/" rel="noopener noreferrer"&gt;free tier&lt;/a&gt; seems sufficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.16.10-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdafuqisthatblog.files.wordpress.com%2F2020%2F05%2Fscreen-shot-2020-05-28-at-1.16.10-am.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Github page (Dropped due to weird styling thing)&lt;/h4&gt;

&lt;p&gt;Somehow, my website on Github page is not styled exactly as what I see in my local development, while the version hosted on Netlify looks exactly the same.&lt;/p&gt;

&lt;h3&gt;Backend&lt;/h3&gt;

&lt;h4&gt;Heroku (Initial choice)&lt;/h4&gt;

&lt;p&gt;My backend is just a NodeJS application with Express, Cors (for local use) and &lt;a href="https://github.com/postlight/mercury-parser" rel="noopener noreferrer"&gt;Mercury Parser&lt;/a&gt; as dependencies.&lt;/p&gt;

&lt;p&gt;Initially, I deployed the backend to Heroku. The deployment was really simple, which was good. However, &lt;a href="https://medium.com/@AndreyAzimov/how-free-heroku-really-works-and-how-to-get-maximum-from-it-daa53f2b3c57" rel="noopener noreferrer"&gt;Heroku hibernates your app once in a while, and your app must sleep a certain amount of time within 3 days&lt;/a&gt;. In short, availability wasn't guaranteed. Even though this is an open-sourced project and monetization isn't the goal, I want it to be available. The unreliability of Heroku was a big demotivator for me, so I looked for an alternative.&lt;/p&gt;

&lt;p&gt;I looked into Netlifly cloud functions. However, there was &lt;a href="https://www.netlify.com/products/functions/" rel="noopener noreferrer"&gt;a limitation on the number of requests and number of running time&lt;/a&gt;. Then I thought that "free server hosting" was too broad a search phrase. My backend is a simple NodeJS-Express application. With that in mind, I looked into "free nodejs app hosting", and after a bit of browsing, I stumbled across openode. It offers a free-tier for open-sourced projects. A quick google search did not reveal any limitation about availability, as least not so much that people would make such complaints available on Google search. I decided to go with openode.&lt;/p&gt;

&lt;h4&gt;Openode (Final choice)&lt;/h4&gt;

&lt;p&gt;One thing I enjoyed about openode is that the deployment process is available through a commandline tool. Not too much up-front knowledge to be learnt for most NodeJS app developers. However, it wasn't without friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The application is publicly available &lt;a href="https://another-writing-application.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Final words&lt;/h2&gt;

&lt;p&gt;Building this application has really been an interesting challenge to me. I have had the opportunity to increase my problem solving, prototyping, time management skills, as well as how to use deliver an application from inception to delivery.&lt;/p&gt;

&lt;p&gt;Let me know if you have any feedback !&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>node</category>
      <category>writing</category>
      <category>hyperapp</category>
    </item>
    <item>
      <title>The Visitation of Visitor Pattern: How it makes your software more useful</title>
      <dc:creator>Tô Minh Thành</dc:creator>
      <pubDate>Sun, 26 Apr 2020 05:37:00 +0000</pubDate>
      <link>https://dev.to/minhthanh3145/the-visitation-of-visitor-pattern-how-it-makes-your-software-more-useful-4flb</link>
      <guid>https://dev.to/minhthanh3145/the-visitation-of-visitor-pattern-how-it-makes-your-software-more-useful-4flb</guid>
      <description>&lt;p&gt;&lt;a href="https://dafuqisthatblog.wordpress.com/2020/04/25/the-visitation-of-visitor-pattern/"&gt;Original post here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The visitor pattern is a behavior design pattern, which means it's a way for objects to interact in order to solve a problem. The problem for the visitor pattern is to add functionalities to a class hierarchy without having to modify every single class for every single functionality. This sounds abstract, but I will try to be more concrete as we proceed.&lt;/p&gt;

&lt;p&gt;The constraint that you may not modify code of any class within the hierarchy, like the case of third-party library classes, yet still allow for additional functionalities that are relevant to the classes to be added, is actually a constraint frequently met by library designers.&lt;/p&gt;

&lt;p&gt;In this post, my goal is to perhaps make sense of the&lt;/p&gt;

&lt;h2&gt;
  
  
  The platitudinous Problem
&lt;/h2&gt;

&lt;p&gt;The problem we will use for this post is, without a doubt, very platitudinous: How to design a hierarchy of objects to represent shapes with certain computable aspects like area and volume.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qI7K_XGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/download-1.png%3Fw%3D180" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qI7K_XGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/download-1.png%3Fw%3D180" alt="" width="180" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did someone say my name ? Also, shapes ? Again ?&lt;/p&gt;

&lt;p&gt;I often find such problems to be too simple and therefore delude the purpose of design patterns. However, a real world example would perhaps contain too many extra functional and non-functional requirements that would also delude the focus on design patterns. On rare occasions, platitudes may be re-interpreted in ways that are helpful and delightful. Not saying that this post is definitely either of these things, but hopefully it would be.&lt;/p&gt;

&lt;p&gt;Let's start even smaller. On the computable aspects, let's say you're not mathematically gifted. You only know properties of individual shapes (rectangles, circles, etc) and the formula to calculate their area only if they are described in a requirement. Also, your team unfortunately works in a way that all relevant requirements don't come to you at the same time, but scattered through time and space and are influenced by multiple parties. Now that sounds more realistic.&lt;/p&gt;

&lt;p&gt;So as you are looking melancholically at your female co-worker while leaning against something, the first requirements comes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pd6RIFXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/undraw_creative_team_r90h.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pd6RIFXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/undraw_creative_team_r90h.png%3Fw%3D1024" alt="" width="880" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://undraw.co/thankful"&gt;https://undraw.co/thankful&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is to calculate the area of the shapes using their respective attributes and formula.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solution Without visitor pattern
&lt;/h2&gt;

&lt;p&gt;So a no-brainer solution is, well, a no-brainer. Ignore the &lt;code&gt;static&lt;/code&gt;, I find them rather annoying, but for the sake of having a &lt;code&gt;main&lt;/code&gt; function I will be tolerant.&lt;/p&gt;

&lt;p&gt;The solution is just literally a hierarchy of shapes in the most obvious way imaginable, and the computations, which are represented by literal values (I aint mathematically gifted y'all), are put into the appropriate classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;WithoutVisitorPattern&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&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;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&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="mi"&gt;0&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;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&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="mi"&gt;1&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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&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="mi"&gt;2&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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&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="mi"&gt;3&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&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="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape2&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;calculateShapeArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shapes&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculateShapeArea&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&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;result&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="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getArea&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;result&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;And frankly, it works well. With the current scope of requirements, any more complexity would be unnecessary. Minimalism is a respectable pursuit.&lt;/p&gt;

&lt;p&gt;But life isn't that simple. After a while, your team decide to distribute the above code into production. This can either mean this code live in an official release of your application, or live inside a version of a library that your clients will use. Let's be dramatic and assume the second scenario. You distribute your library as a &lt;code&gt;JAR&lt;/code&gt; file to your clients. Your clients use this library to calculate the area of the shapes to do some, uh, mathematical mission-critical stuffs.&lt;/p&gt;

&lt;p&gt;But as they use it, their mathematics extend to well beyond area of shapes, and thus they demand that your library accommodates their new requirement - which is to calculate volume of the shapes. Okay, so with the above solution, in order to accommodate a new method called &lt;code&gt;getVolume&lt;/code&gt; for every shape, you must add the signature to the base class, and then for every subclass, you also need to add the signature &lt;code&gt;getVolume&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because your team supports an extensive library for shapes, there are more than 23 shapes in the hierarchy. 23 is my current age by the way. Anyway, you would need to add 23 &lt;code&gt;getVolume&lt;/code&gt; methods into each of these 23 classes. Did I mention 23 is my age ? Okay enough with these.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the problem matters ?
&lt;/h2&gt;

&lt;p&gt;You may be thinking: "I see that this is the problem that you mentioned earlier: To add additional functionalities relevant to the class hierarchy without modifying the class hierarchy. But hey, you have to add 23 different &lt;code&gt;getVolume&lt;/code&gt; methods either way, because the formula for each of these 23 shapes is different from each other, so what's the harm in placing these methods in the class hierarchy itself, compared to an alternative. Sure, it'd be more elegant and also adhere to the so-called &lt;a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle"&gt;Open-Closed Principle&lt;/a&gt;. But, the first one is subjective, the second one sounds like &lt;a href="https://en.wikipedia.org/wiki/Authority_bias"&gt;Authority Bias&lt;/a&gt; to me. "&lt;/p&gt;

&lt;p&gt;Okay, maybe you won't be thinking exactly that, but something like that is a reasonable objection. However, one of the important characteristics of good software designs is to accommodate changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Because other software depend on your software
&lt;/h3&gt;

&lt;p&gt;Another software team is working on a different mathematics project and they found your software to be very useful, but lacking some shapes that are particular to their projects. So they use the &lt;code&gt;JAR&lt;/code&gt; file you distribute, extend the subclass &lt;code&gt;Shape&lt;/code&gt; and implement another 23 shapes that work for them.&lt;/p&gt;

&lt;p&gt;Now the requirement for volume of shapes comes, among other requirements such as bug fixes and optimizations. You simply add 23 &lt;code&gt;getVolume&lt;/code&gt; methods to each of the class in the hierarchy and release the new version of the library with attractive bug fixes and optimizations. However, because the software team above also extends from your base class, they would also need to add &lt;code&gt;getVolume&lt;/code&gt; into their 23 shapes in order to use the new version. The risk tends to pose difficulty in justifying the library upgrade, so likely they won't use the new version(s). For you, this means that people are not receiving values from your new releases. What's the point of software if it's not to continue to provide values ?&lt;/p&gt;

&lt;p&gt;This gets worse when it cascades to further software teams that depend on the software team above, and I think this is enough to tell you that your design, as it currently stands, does not accommodate changes very efficiently. This problem suggests that another solution is needed to keep the propagation of change to be minimal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Because software ceases to evolve
&lt;/h3&gt;

&lt;p&gt;It is not an exception that software components cease to evolve. They may stop because the budget runs out so no one is maintaining the library anymore. They may stop because of a natural disaster that kills everyone who works on that library specifically. Whatever the cause is, a consequence is that you and your team, as the library developers, can no longer accommodate new changes to the library. That responsibility unfortunately will fall into other software teams who extend your library. However, just because your library is not maintained doesn't mean it is not useful anymore.&lt;/p&gt;

&lt;p&gt;So when your project is no longer maintained, new functionalities can no longer be added into the hierarchy inside your library. The software team who decides to use your library to reap its existing benefits must create a new class hierarchy that use your class hierarchy to add functionalities. There is no other way. This, unfortunately, would mean that new functionalities would have to be used differently than old functionalities, which confuse new members of the team, which adds more to the cost. It's also annoying to explain that we have to code this way because of, quote, unquote, legacy code.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solution that solves the problem
&lt;/h2&gt;

&lt;p&gt;So after we have seen that adding functionalities by directly modifying code of the hierarchy is not a design that would facilitate useful, long-lasting software libraries.&lt;/p&gt;

&lt;p&gt;So what's the solution ? It is to do what future software teams would have to do if they no longer can modify your class hierarchy. Create another class hierarchy and make it do the computations, instead of having the computations inside the Shape hierarchy.&lt;/p&gt;

&lt;p&gt;From the above solution without visitor pattern, if we go along with the idea of delegating the computations to another hierarchy, we would end up with something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;EvolutionToVisitorPattern&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;class&lt;/span&gt; &lt;span class="nc"&gt;AreaCalculator&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;getAreaOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;0&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;getAreaOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;1&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;getAreaOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;2&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;getAreaOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;3&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;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;areaCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAreaOf&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;areaCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAreaOf&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;areaCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAreaOf&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;areaCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAreaOf&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="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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&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="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape2&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;calculateShapeAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shapes&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculateShapeAttribute&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;AreaCalculator&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;result&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="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;areaCalculator&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;result&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;This solution creates a class called &lt;code&gt;AreaCalculator&lt;/code&gt; which implements the computation to get area of the shapes. Each call to &lt;code&gt;getArea&lt;/code&gt; is now given an instance of &lt;code&gt;AreaCalculator&lt;/code&gt; and simply delegate to &lt;code&gt;AreaCalculator&lt;/code&gt; to compute and return the area.&lt;/p&gt;

&lt;p&gt;At first glance, the obvious problem seems to be code duplication. If we look at the patterns of text in the child classes, it's not unreasonable to think they're duplication, and instead we can just modify the base class to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;abstract&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;areaCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAreaOf&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="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;However, that won't work, because &lt;code&gt;this&lt;/code&gt; is of type &lt;code&gt;Shape&lt;/code&gt; which the &lt;code&gt;AreaCalculator&lt;/code&gt; does not have a method that accepts. To fix this, we may want to modify &lt;code&gt;AreaCalculator&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;int&lt;/span&gt; &lt;span class="nf"&gt;getAreaOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&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;shape&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&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;aPrivateMethodToCalculatAreaForRectangle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&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;shape&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Shape1&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="c1"&gt;// 21 more to go :(&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this defeats the purpose. Suppose that another software team want to extend &lt;code&gt;AreaCalculator&lt;/code&gt; into their own class because they want to optimize the current calculation of area for &lt;code&gt;Rectangle&lt;/code&gt;. Too bad, they can't do it because finding the right shape and delegating to the right private method happens within the same function. Therefore doing it this way would prevent customization of existing functionalities.&lt;/p&gt;

&lt;p&gt;So we want to maintain the solution as it is, because then another software team only need to extends &lt;code&gt;AreaCalculator&lt;/code&gt; and override &lt;code&gt;public int getAreaOf(Rectangle shape)&lt;/code&gt; to provide their own customized implementation.&lt;/p&gt;

&lt;p&gt;The second aching problem is that, each method is receiving an &lt;code&gt;AreaCalculator&lt;/code&gt; instance, this seems unnecessary, can we just inject the instance into the class constructor and then re-use it. So, start with the base class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;abstract&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Shape&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;calculator&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;calculator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculator&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaCalculator&lt;/span&gt; &lt;span class="n"&gt;areaCalculator&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;Wait a minute, there are red marks !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bakg0hKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/screen-shot-2020-04-26-at-1.56.19-am.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bakg0hKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dafuqisthatblog.files.wordpress.com/2020/04/screen-shot-2020-04-26-at-1.56.19-am.png%3Fw%3D1024" alt="" width="880" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turns out that, we have to add a constructor for all classes extending &lt;code&gt;Shape&lt;/code&gt; in order to do it this way. Suddenly, it doesn't seem to worth the efforts anymore. With every instance of &lt;code&gt;AreaCalculator&lt;/code&gt; you save from a method, the same instance must go into the constructor. However, saying that it takes the same efforts for both approaches does not give us information to choose one over another.&lt;/p&gt;

&lt;p&gt;A practical reason would be that, if we decide to give an instance &lt;code&gt;AreaCalculator&lt;/code&gt; to all shapes in the constructor, it implies that we &lt;strong&gt;have to make an instance of &lt;code&gt;AreaCalculator&lt;/code&gt;&lt;/strong&gt; before we can use any shape. The construction of an &lt;code&gt;AreaCalculator&lt;/code&gt; instance that must do intense computations in an optimized way would be costly. When such an &lt;code&gt;AreaCalculator&lt;/code&gt; instance is constructed, an implementation that maximizes optimization would have to read CPU resources, retrieving information from other parts of the application in order to determine the most efficient area computation strategy.&lt;/p&gt;

&lt;p&gt;On the other hand, our &lt;code&gt;Shape&lt;/code&gt; subclasses represent lightweight objects that contain information about the shapes at hand. We even delegate computations to another class. If we have to make an instance of &lt;code&gt;AreaCalculator&lt;/code&gt; before every shape is created, it turns out to be sub-optimal, because we are creating a very costly object that we don't use yet. We can't make the assumption that the area computation would occur right after these shapes are created. Therefore, delaying the construction of &lt;code&gt;AreaCalculator&lt;/code&gt; right to the moment when the shapes need it, is the optimal strategy. For this reason, we maintain our solution as it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solution with visitor pattern
&lt;/h2&gt;

&lt;p&gt;With all that said, the visitor pattern is actually half-way achieved. In order to support a volume computation, we can just create the method &lt;code&gt;getVolume&lt;/code&gt; for each of the class in the class hierarchy and delegate the logic to a &lt;code&gt;VolumeCalculator&lt;/code&gt;. However, we can notice that &lt;code&gt;AreaCalculator&lt;/code&gt; and &lt;code&gt;VolumeCalculator&lt;/code&gt; actually shares the same signatures, and they are used in the same way by the subclasses of &lt;code&gt;Shape&lt;/code&gt;, so they can be grouped together into a new inheritance hierarchy. This new hierarchy has the base class &lt;code&gt;Calculator&lt;/code&gt; which has a method &lt;code&gt;calculate&lt;/code&gt; that is used by &lt;code&gt;getArea&lt;/code&gt; and &lt;code&gt;getVolume&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So now, &lt;code&gt;getVolume&lt;/code&gt; and &lt;code&gt;getArea&lt;/code&gt; has the same signature and logic: Receiving a &lt;code&gt;Calculator&lt;/code&gt; instance, call &lt;code&gt;Calculator.calculate(this)&lt;/code&gt; and return the result, therefore they are practically just one method in the class &lt;code&gt;Shape&lt;/code&gt; hierarchy. Let's this method be called &lt;code&gt;getComputedValueFrom(Calculator)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now your &lt;code&gt;Shape&lt;/code&gt; use &lt;code&gt;Calculator&lt;/code&gt; as something that it merely passes &lt;code&gt;this&lt;/code&gt; to and receive a value, it's not strictly just about computation anymore, because we can perform additional logic and algorithm inside &lt;code&gt;Calculator.calculate&lt;/code&gt; as well. Whenever we see an abstraction that does multiple things, it's a good idea to name it something generic so that its subclass can take on concrete meanings. With this principle, we replace &lt;code&gt;Calculator&lt;/code&gt; by &lt;code&gt;Visitor&lt;/code&gt;, &lt;code&gt;getComputedValueFrom&lt;/code&gt; with &lt;code&gt;accept&lt;/code&gt;, and &lt;code&gt;calculate&lt;/code&gt; method with &lt;code&gt;visit&lt;/code&gt;. Voila. You end up with the visitor pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;WithVisitorPattern&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShapeVisitor&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="n"&gt;shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="n"&gt;shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="n"&gt;shape&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;class&lt;/span&gt; &lt;span class="nc"&gt;AreaShapeVisitor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt;  &lt;span class="nc"&gt;ShapeVisitor&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;0&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;1&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;2&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="n"&gt;shape&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="mi"&gt;3&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;class&lt;/span&gt; &lt;span class="nc"&gt;VolumeShapeVisitor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ShapeVisitor&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="n"&gt;shape&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="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="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;shape&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="n"&gt;shape&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&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;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="n"&gt;shape&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visit&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visit&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visit&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="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;class&lt;/span&gt; &lt;span class="nc"&gt;Shape2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&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;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visit&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="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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&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="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape1&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;shapes&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Shape2&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;VolumeShapeVisitor&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;calculateShapeAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shapes&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="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculateShapeAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShapeVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&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;Shape&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&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;result&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="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&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;result&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;I am not gonna comment on why we name things like &lt;code&gt;Visitor&lt;/code&gt; and &lt;code&gt;visit&lt;/code&gt;, because to be honest I haven't thought of a reasonable explanation. But nevertheless, our derivation of this pattern so far has not touched upon such concepts, so I don't think these are necessary.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>java</category>
      <category>p</category>
    </item>
    <item>
      <title>Equation of software design</title>
      <dc:creator>Tô Minh Thành</dc:creator>
      <pubDate>Mon, 06 Apr 2020 16:43:41 +0000</pubDate>
      <link>https://dev.to/minhthanh3145/equation-of-software-design-1n02</link>
      <guid>https://dev.to/minhthanh3145/equation-of-software-design-1n02</guid>
      <description>&lt;p&gt;I recently read the book &lt;a href="https://www.amazon.com/Code-Simplicity-Fundamentals-Max-Kanat-Alexander-ebook/dp/B007NZU848"&gt;Code Simplicity&lt;/a&gt; and I thought some ideas are interesting. The below is my effort to summarize and re-state some of the ideas that I have processed from the book. This is taken from my &lt;a href="https://dafuqisthatblog.wordpress.com/2019/10/29/software-design-equation-of-software-design/"&gt;personal blog&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The fundamental problem in software design
&lt;/h3&gt;

&lt;p&gt;How do I make decisions about my software ? &lt;/p&gt;

&lt;p&gt;More specifically, faced with multiple possibilities, we must decide on a course of action. That is obvious enough, otherwise we won’t get to anywhere. Making a choice is the only way to move from where we currently are. But the question of how to make such a decision is an elusive one.&lt;/p&gt;

&lt;p&gt;When we speak of decisions about the software, what we really speak about is the decision to change. Implementing a new feature in a software changes the software, refactoring code changes the software. Every meaningful action in software development can be characterized as an attempt to change the software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Equation of Software Design
&lt;/h3&gt;

&lt;p&gt;With that in mind, a decision about software can be thought of as:&lt;/p&gt;

&lt;p&gt;D = V/E&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;D stands for Desirability of a change. How much do we want to make this particular change to the software.&lt;/li&gt;
&lt;li&gt;V stands for Value of a change. The goal of software designs is to help people, so Value will be measured in terms of how much it helps people.&lt;/li&gt;
&lt;li&gt;E stands for Effort necessary to make this change. This usually can be estimated in terms of days or weeks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Value
&lt;/h4&gt;

&lt;p&gt;With values, we can think about value in terms of probability or potential.&lt;/p&gt;

&lt;p&gt;For example, if your software does not allow connection through proxy, then a small number of enterprise users would not be able to use this, as the security requirement of enterprises is usually strict. Therefore the feature which allows your users to connect to the software using proxy is valuable because it has high potential value, despite affecting a small group of user.&lt;/p&gt;

&lt;p&gt;Another example would be a feature to add a handy tool item on the UI for an action that is very commonly performed by your users. This feature is valuable because it affects a lot of users, despite the fact that they can all probably do without.&lt;/p&gt;

&lt;p&gt;On the other hand, if you add a lot of items on the UI for actions that only get used once in a while, it really doesn’t help much, and nobody uses it. That’s not a valuable feature both in term of probability and potential.&lt;/p&gt;

&lt;h4&gt;
  
  
  Effort
&lt;/h4&gt;

&lt;p&gt;Efforts are tricky, because we’ve been told that there are ways to estimate the efforts in terms of man-power, or man-day, man-month, man-year. In reality, putting even an approximately close number of estimation is difficult enough.&lt;/p&gt;

&lt;p&gt;Such a task is often left to more senior developers, who have experienced through inaccurate estimations and made adjustments to their internal models.&lt;/p&gt;

&lt;p&gt;It helps to take into accounts factors not directly related to software development, such as the efforts to communicate, write documentation, testing activities, coordinations with sales/marketing teams.&lt;/p&gt;

&lt;p&gt;In short, every single piece of time connected with a change is part of the effort cost&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing time to the equation
&lt;/h3&gt;

&lt;p&gt;The equation, in its current form, has not yet taken into account the time dimension of software. Values and efforts are not only relevant in the present, but also in the long run.&lt;/p&gt;

&lt;p&gt;Values can actually increase overtime, as a single feature you rolled out becomes a unique point of attraction that set you apart from other tools. When your software gets mature enough, this distinction then becomes a valuable selling point, which is more valuable than it was rolled out.&lt;/p&gt;

&lt;p&gt;On the other hand, values can also decrease overtime. If you decide to integrate your software with a third-party library, then there’s an inherent risk that the third-party library becomes buggy and the effect ripples into your software. There’s nothing you can do about it because it’s a third-party, users don’t care if if it’s a third-party because it’s a feature of your software. As a result, they may be demotivated to proceed with using your software. It can be the case that such integration was decided to put into production to ride a trend. Such would be the case where values decreased overtime.&lt;/p&gt;

&lt;p&gt;Likewise, efforts involved in software development most often appear as the maintenance efforts. A feature that affects multiple parts of your code base is harder to maintain in the future by ourselves, and by other developers.&lt;/p&gt;

&lt;p&gt;Put it together, more realistically, our equation should look like:&lt;/p&gt;

&lt;p&gt;D = (Vp + Vf) / (Ei + Em)&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vp is the value of the feature at the present&lt;/li&gt;
&lt;li&gt;Vf is the value of the feature in the future&lt;/li&gt;
&lt;li&gt;Ei is the implementation effort of this feature&lt;/li&gt;
&lt;li&gt;Em is the maintenance effort of this feature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The desirability of a change is directly proportional to the value now plus the future value, and inversely proportional to the effort of implementation plus the effort of maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducing the equation
&lt;/h3&gt;

&lt;p&gt;If you’re mathematically inclined, then perhaps it would occur intuitively to you that, because we introduced a time dimension into the equation, we will reduce the equation by simply observing over a long period of time.&lt;/p&gt;

&lt;p&gt;Because the present value and efforts of implementation for a feature is always constant, and that the future value and maintenance efforts change overtime, when we take the limit of the equation with time variable approaching infinity, the constants will be faded out. Now we have:&lt;/p&gt;

&lt;p&gt;D = Vf / Em&lt;/p&gt;

&lt;p&gt;In general, software systems evolve in a way such that the present value and effort of implementation almost always becomes insignificant in comparison with the future value and effort of maintenance over a long period of time.&lt;/p&gt;

&lt;p&gt;Features that are more valuable in the future are more desirable, and features that require less maintenance efforts in the future are also more desirable. However, if we are forced to choose, then we should always go with one that results in less maintenance efforts.&lt;/p&gt;

&lt;p&gt;The rationale is simple, if a change gets easier and easier to maintain, then its desirability actually increases overtime, regardless of how much future value it’s gonna bring about (as long as it’s not negative). If instead, we choose the feature which has larger future values, then if the maintenance efforts exceed that values then the desirability decreases.&lt;/p&gt;

&lt;p&gt;It’s a more complex problem, which we sometimes have to solve. Another instinct is to reduce the implementation efforts of a feature. Put it bluntly, the instinct is to implement the feature as quickly as possible using all means necessary. As we can see from the equation, the implementation efforts dissipate over the long haul. &lt;/p&gt;

&lt;p&gt;That is why, one of the most important things to take from this equation of software design: It is more important to reduce the effort of maintenance than it is to reduce the effort of implementation.&lt;/p&gt;

</description>
      <category>design</category>
      <category>architecture</category>
      <category>book</category>
    </item>
    <item>
      <title>Katalon Notes plug-in</title>
      <dc:creator>Tô Minh Thành</dc:creator>
      <pubDate>Fri, 12 Jul 2019 18:06:48 +0000</pubDate>
      <link>https://dev.to/minhthanh3145/katalon-notes-plug-in-3i2b</link>
      <guid>https://dev.to/minhthanh3145/katalon-notes-plug-in-3i2b</guid>
      <description>&lt;h2&gt;
  
  
  On taking notes
&lt;/h2&gt;

&lt;p&gt;I have been fascinated with personal development for a while. This fascination has led to many exciting adventures with ups-and-downs, and I have learned several invaluable lessons. One of which is the act of taking notes. I take notes when reading books, I take notes to record trivial facts for work that I don't have to use regularly but may have to look up later. Aside from taking notes, task management is also essential so that my life isn't disorganized and time for personal development isn't taken away unnecessarily. &lt;/p&gt;

&lt;p&gt;But back to taking notes, the act of taking note overtime amounts to the act of building a knowledge base. The knowledge base I have obtained basically spans across my entire life and it has helped me live a better life, all originates from taking notes. However, it is not always perceived as valuable by many people, due to many reasons, one of which is that they haven't found the need to form such habits yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  On what I did with this obsession
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To facilitate this habit of taking notes within the context of Katalon Studio&lt;/strong&gt;, I decided to implement a simple note-taking plug-in called &lt;strong&gt;Katalon Notes&lt;/strong&gt;. The link to the plug-in is at the end of this post. I personally use &lt;a href="https://github.com/zadam/trilium"&gt;Trillium Notes&lt;/a&gt; which is a Electron-based note taking application, as a central tool to take notes. The obsessive usage of this tool inspired me heavily in designing and implementing Katalon Notes.&lt;/p&gt;

&lt;p&gt;The altruistic motivation is that it would, first and foremost, provide heavy Katalon users who also happen to share my interest a way to incorporate their productive habits into Katalon Studio (thus using Katalon Studio more LOL). Second, not that anybody asked for it, but my thought is it would be a great idea for people on your team to take notes collectively. To facilitate this, Katalon Notes &lt;strong&gt;saves notes into a local database in project folder&lt;/strong&gt; so that when you commit your code, you can also commit the database file and the notes will be shared.&lt;/p&gt;

&lt;p&gt;It is important for a note-taking application to &lt;strong&gt;save changes automatically&lt;/strong&gt; and Katalon Notes provides this feature. You maybe wondering why such a specific feature is desirable ? Because the act of taking notes, when it's most meaningful, consists of going over your old notes on a particular topic, retrieve knowledge and build new synthesized knowledge on top of that. To be able to do that without being instilled the fear of losing what's half-written is such a blessing that should may as well be a common sense.&lt;/p&gt;

&lt;p&gt;Currently, Katalon Notes &lt;strong&gt;supports Markdown syntax&lt;/strong&gt; so that your notes can have a styling structure. A limitation is that &lt;strong&gt;no image can be displayed yet,&lt;/strong&gt; but &lt;strong&gt;I plan to implement it&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QHYjQ2-J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/mwudx2krrk2q7jzgs0ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QHYjQ2-J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/mwudx2krrk2q7jzgs0ay.png" alt="" width="880" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selfishly,
&lt;/h2&gt;

&lt;p&gt;Designing and implementing Katalon Notes has been a fun technical challenge for me, and it will continually be that way due to many possibilities for features. I found myself pondering over design decisions, code refactoring decision and decisions that I regularly have to make in my work, accompanied with a sense of full ownership that comes with a personal project. I'd probably blog my thoughts somewhere as writing is another one of my habits. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where you can try it out
&lt;/h2&gt;

&lt;p&gt;So, enough with the talking, even I got sick of myself, here's the link:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://store.katalon.com/product/105/Katalon-Notes"&gt;https://store.katalon.com/product/105/Katalon-Notes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project is open-sourced here:&lt;br&gt;
&lt;a href="https://github.com/minhthanh3145/katalon-notes"&gt;https://github.com/minhthanh3145/katalon-notes&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Katalon Studio
&lt;/h2&gt;

&lt;p&gt;Katalon is an automated software testing company/product that I currently work at/on.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
