<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Alen Kosanovic, Author at ShiftMag</title>
	<atom:link href="https://shiftmag.dev/author/alen-kosanovic/feed/" rel="self" type="application/rss+xml" />
	<link>https://shiftmag.dev/author/alen-kosanovic/</link>
	<description>Insightful engineering content &#38; community</description>
	<lastBuildDate>Thu, 17 Jul 2025 14:33:25 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.3</generator>

<image>
	<url>https://shiftmag.dev/wp-content/uploads/2024/08/cropped-ShiftMag-favicon-32x32.png</url>
	<title>Alen Kosanovic, Author at ShiftMag</title>
	<link>https://shiftmag.dev/author/alen-kosanovic/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>You&#8217;re not a senior engineer until you’ve worked on a legacy project</title>
		<link>https://shiftmag.dev/senior-software-engineer-legacy-code-4839/</link>
		
		<dc:creator><![CDATA[Alen Kosanovic]]></dc:creator>
		<pubDate>Mon, 27 Jan 2025 13:19:37 +0000</pubDate>
				<category><![CDATA[Career]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[legacy code]]></category>
		<category><![CDATA[legacy project]]></category>
		<category><![CDATA[software engineering]]></category>
		<guid isPermaLink="false">https://shiftmag.dev/?p=4839</guid>

					<description><![CDATA[<p>Everybody hates working on legacy projects, myself included. As fate would have it, one landed in my lap recently. </p>
<p>The post <a href="https://shiftmag.dev/senior-software-engineer-legacy-code-4839/">You&#8217;re not a senior engineer until you’ve worked on a legacy project</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></description>
										<content:encoded><![CDATA[<figure class="wp-block-post-featured-image"><img fetchpriority="high" decoding="async" width="1200" height="630" src="https://shiftmag.dev/wp-content/uploads/2025/01/legacy-code.png?x32039" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" style="object-fit:cover;" srcset="https://shiftmag.dev/wp-content/uploads/2025/01/legacy-code.png 1200w, https://shiftmag.dev/wp-content/uploads/2025/01/legacy-code-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2025/01/legacy-code-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2025/01/legacy-code-768x403.png 768w" sizes="(max-width: 1200px) 100vw, 1200px" /></figure>


<p class="wp-block-paragraph">Working on it didn’t make me hate legacy projects any less; it did help me get a deeper understanding of the processes and practices we use today. </p>



<p class="wp-block-paragraph">I am proud that I am a part of a team that uses <strong>most of the best practices:</strong>&nbsp;</p>



<ul class="wp-block-list">
<li>Writing clean code and automated tests&nbsp;</li>



<li>Participating in pull requests and tasks reviews&nbsp;</li>



<li>The app is in production within the same day of merging into the master branch&nbsp;</li>



<li>Agile is well-adopted&nbsp;</li>
</ul>



<p class="wp-block-paragraph"> It’s not perfect. Pull requests sometimes contain trivial suggestions and discussions. The ops team usually messes something up (or at least that’s what we devs like to think). Our product owner occasionally wants us to fast-track some ‘easy’ features… again. But all in all, things are pretty good.&nbsp;</p>



<h2 class="wp-block-heading"><span id="a-trip-to-the-ant-museum">A trip to the Ant museum&nbsp;</span></h2>



<p class="wp-block-paragraph">Since our team was performing well, our velocity was borrowed to another product, managed by another part of our company. We weren’t thrilled about it since the project <strong>uses an older version of Java, </strong>and the code wasn’t written the way we would do it. &nbsp;</p>



<p class="wp-block-paragraph">The job was to add a few metrics – simple ones, like whether the app is running and for how long, is it processing data (fast enough). The project itself was in maintenance mode, and no new features had been added in a while. Since we are accustomed to adding metrics, this should have been a piece of cake.&nbsp;</p>



<p class="wp-block-paragraph">Rolling up our sleeves, we first noticed that <strong>the project had been built using something very old - </strong><a href="https://en.wikipedia.org/wiki/Apache_Ant" target="_blank" rel="noreferrer noopener"><strong>Ant</strong></a><strong>  build files. </strong>They are big XML files that contain every piece of information on how to build the project in question. For example, you need to specify that the project needs to be compiled, tested, and packaged. All details like source, target, and resource location must be explicitly configured within those files. This used to be pretty common for many programming languages. You wrote a build file once, copied it on each new project, and then changed it until it worked for the new project. &nbsp;</p>



<p class="wp-block-paragraph">Here’s what an Ant build file for a Hello World project would look like:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="692" src="https://shiftmag.dev/wp-content/uploads/2025/01/Screenshot-2025-01-27-at-14.07.35-1024x692.png?x32039" alt="" class="wp-image-4842" srcset="https://shiftmag.dev/wp-content/uploads/2025/01/Screenshot-2025-01-27-at-14.07.35-1024x692.png 1024w, https://shiftmag.dev/wp-content/uploads/2025/01/Screenshot-2025-01-27-at-14.07.35-300x203.png 300w, https://shiftmag.dev/wp-content/uploads/2025/01/Screenshot-2025-01-27-at-14.07.35-768x519.png 768w, https://shiftmag.dev/wp-content/uploads/2025/01/Screenshot-2025-01-27-at-14.07.35.png 1888w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">There must be a more convenient way to manage that, right? Well, that’s why the idea of <a href="https://en.wikipedia.org/wiki/Convention_over_configuration" target="_blank" rel="noreferrer noopener">convention over configuration</a> came to life, suggesting that developers only need to specify unconventional aspects of the application.&nbsp;<strong>Modern build tools have adopted</strong> <strong>this paradigm by providing developers with defaults that can be overridden if needed.</strong> That’s why most java source files are in src/main/java source, while the compiled classes are in the target folder—no need to specify this over and over.&nbsp;</p>



<p class="wp-block-paragraph">That got us thinking about whether this approach would be helpful in our current projects. We had a huge application properties file, with most values having the same value (e.g., application port).&nbsp;<strong>Could we apply the same principle to our application properties?</strong>&nbsp;Most properties could have defaults, and our properties file wouldn’t be as large.&nbsp;</p>



<h2 class="wp-block-heading"><span id="things-we-take-for-granted">Things we take for granted</span></h2>



<p class="wp-block-paragraph">Back to our legacy project – we managed to build and package our application! The tedious part was behind us, and we could start coding. But&nbsp;<strong>how do we embed our metrics component into the legacy code base</strong>? We took this for granted because our application framework usually handled it. &nbsp;</p>



<p class="wp-block-paragraph">Now, what would be the best way to inject our metric components into various parts of the legacy code? Singletons! Well, it seemed the easiest way, at least, but the community considers them anti-patterns. Why? Isn’t our beloved XY framework relying on singletons? If not, what does it use? What is dependency injection? How does it function under the hood?&nbsp;</p>



<p class="wp-block-paragraph"><strong>These questions got us thinking about basic concepts that we took for granted</strong>. Using singletons wasn’t exactly a bad idea in this case since most of the code wasn’t covered with unit tests. Nevertheless, we couldn’t have a good night’s sleep unless the code was immaculate. We tried a different approach and ended up with decent and simple code – no singletons, no new abstractions.&nbsp;</p>



<h2 class="wp-block-heading"><span id="the-limited-role-of-developers">The limited role of developers&nbsp;</span></h2>



<p class="wp-block-paragraph">The only thing left was to deploy it so that we could test it. This was a problem, of course—in this case, we were not the ones deploying or testing it.&nbsp;<strong>Deploying had to be done by the ops team, and testing by the test team.</strong>&nbsp;Why couldn’t we, as developers, manage the whole feature from start to production instead of opening tickets and waiting for other teams before we could close our task?</p>



<p class="wp-block-paragraph">Firstly, we couldn’t avoid manual testing since much of the code wasn’t covered with tests. We also couldn’t deploy the application ourselves since the infrastructure didn’t allow us to. &nbsp;</p>



<p class="wp-block-paragraph">This had us thinking about the reasons behind&nbsp;<strong>the separation of duties</strong>&nbsp;and&nbsp;<strong>how our current approach is better</strong>. Seeing that our lead and cycle time on this project was significantly higher than usual (it took us weeks to deliver something we usually deliver in several days), the evidence was strongly in favor of that.</p>



<h2 class="wp-block-heading"><span id="learn-outdated-practices-to-understand-current-ones">Learn outdated practices to understand current ones</span></h2>



<p class="wp-block-paragraph">At the end of the <s>day</s> month, our metrics were up and running in production. My feelings about legacy projects haven’t changed – I still hate them, and I am not expecting you to hate them any less. &nbsp;</p>



<p class="wp-block-paragraph">We couldn’t change the project we were assigned to, and these were the cards that we were dealt. What we could <strong>change is our attitude towards the legacy project</strong>. Instead of feeling resigned, we saw it as <strong>a place to ask questions and learn.</strong> &nbsp;</p>



<p class="wp-block-paragraph">It taught us how things were done before and why they are done differently now. Instead of just knowing the best practices, we gained first-hand experience with the history behind them. &nbsp;</p>



<p class="wp-block-paragraph">Once you start having this deep-rooted knowledge, other developers will recognize this and trust your knowledge and expertise. If you want to be that person, you better be ready to dig into some legacy projects.&nbsp;</p>
<p>The post <a href="https://shiftmag.dev/senior-software-engineer-legacy-code-4839/">You&#8217;re not a senior engineer until you’ve worked on a legacy project</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Are your engineering “best practices” just developer dogmas?</title>
		<link>https://shiftmag.dev/software-engineering-best-practices-dogmas-1681/</link>
		
		<dc:creator><![CDATA[Alen Kosanovic]]></dc:creator>
		<pubDate>Wed, 11 Oct 2023 07:08:38 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[hype-driven development]]></category>
		<category><![CDATA[software engineering best practices]]></category>
		<guid isPermaLink="false">https://shiftmag.dev/?p=1681</guid>

					<description><![CDATA[<p>If you don't understand why a particular practice is used, you risk going down the lane of "hype-driven development".</p>
<p>The post <a href="https://shiftmag.dev/software-engineering-best-practices-dogmas-1681/">Are your engineering “best practices” just developer dogmas?</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></description>
										<content:encoded><![CDATA[<figure class="wp-block-post-featured-image"><img decoding="async" width="1200" height="630" src="https://shiftmag.dev/wp-content/uploads/2023/10/development-best-practices.png?x32039" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" style="object-fit:cover;" srcset="https://shiftmag.dev/wp-content/uploads/2023/10/development-best-practices.png 1200w, https://shiftmag.dev/wp-content/uploads/2023/10/development-best-practices-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2023/10/development-best-practices-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2023/10/development-best-practices-768x403.png 768w" sizes="(max-width: 1200px) 100vw, 1200px" /></figure>


<p class="wp-block-paragraph">My biggest dilemma when I started to program was this: How do I write things correctly?&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">Should a controller directly access the repository or use a service method as an intermediary? Where should we validate objects &#8211; within the Controller or the Service layer? Should repositories be placed in a repository package or a feature package?</p>



<p class="wp-block-paragraph">There are endless ways to write code, but <strong>there must be a right way</strong>. To settle the ongoing debates, I turned to established best practices. Best practices provide limitations to the endless landscape of programming options. It is a lot easier to answer the afore-posed questions when an authority suggests that:</p>



<ul class="wp-block-list">
<li>Controllers should typically avoid direct access to repositories, with a few exceptions.</li>



<li>Object validation is often best placed within a Controller.</li>



<li>Feature packages tend to be more practical than technical packages.</li>
</ul>



<p class="wp-block-paragraph">Embracing these best practices both streamlined my decision-making process and helped resolve disagreements with fellow developers. <strong>Why engage in heated debates about the superiority of feature packages when you can simply reference authoritative articles?</strong> When those references come from a reputable source like Wikipedia, the argument is immediately over, right?&nbsp;</p>



<p class="wp-block-paragraph">The problem arises when people take these practices for granted, and <strong>they turn into dogmas</strong> that never get questioned.</p>



<h2 class="wp-block-heading"><span id="the-problem-with-dogmas">The problem with dogmas</span></h2>



<p class="wp-block-paragraph"><strong>Best practices</strong> in software development are not static and <strong>can evolve.&nbsp;</strong></p>



<p class="wp-block-paragraph">Consider the evolution of database access patterns. When starting my development career, the best practice for accessing a repository (at least in Java) was through DAO objects, which is now considered outdated in favor of repositories. If we look at other <a href="https://martinfowler.com/eaaCatalog/index.html">data source architectural patterns</a>, we could add many more of these patterns to the equation. How do we know which one of these best practices is the best? The key lies in <strong>developing a deep understanding of these practices.</strong></p>



<p class="wp-block-paragraph">Without comprehending why a particular practice is considered good, you risk making bad decisions. Such decisions can lead you to &#8220;<strong>hype-driven development,</strong>&#8221; where you adopt the latest trends without fully understanding their implications. This can result in complex, service-oriented, NoSQL, Big Data monsters that nobody knows how to maintain anymore.</p>



<p class="wp-block-paragraph">Questioning everything, even the most widely accepted authorities, is a valuable approach. Instead of blindly following trends, consider the context and the trade-offs of each practice.</p>



<h2 class="wp-block-heading"><span id="you-need-an-igor-in-your-life">You need an Igor in your life</span></h2>



<p class="wp-block-paragraph">I had a colleague (let&#8217;s call him Igor), a skeptic by nature.</p>



<p class="wp-block-paragraph">He was unimpressed by dogmas, both in his professional and private life. He was<strong> an old-school developer who clung to his tried-and-true method</strong>s, largely unfazed by new ideas and trends in our field.&nbsp;</p>



<p class="wp-block-paragraph">Convincing Igor to accept a new coding practice was not an easy thing to do. It would even get terribly frustrating if you didn’t fully understand the practice yourself. Suppose Igor is dissatisfied with grouping packages by feature rather than by technology. Here is how a conversation with Igor might unfold when we don&#8217;t understand why we do things the way we do them:</p>



<ul class="wp-block-list">
<li><em>I don&#8217;t know why repositories are suddenly placed in packages named by entities.</em></li>



<li>Well, putting them in the repository package is not a good practice. It doesn&#8217;t foster Domain Driven Design.</li>



<li><em>What is this Domain Driven Design?</em></li>



<li>Well, it states that you should organize your code by domains, not technology. That domain thinking should drive how you design things.</li>



<li><em>And what&#8217;s wrong with the way we&#8217;ve been coding so far?</em></li>



<li>Well, the domain knowledge is not represented in the code.</li>



<li><em>You want to say that you understand the domain behind this software we are writing.</em></li>



<li>Not right now, but&#8230;</li>



<li><em>The analytics department just hands us use cases, and we code what we are given. Nobody asks us anything.</em></li>



<li>So you think you know better than all these people that have written this and have been adopting this?!</li>



<li><em>I don&#8217;t care what some fool has written. Today, they promote this as the best thing, tomorrow, it will be something else.</em></li>
</ul>



<p class="wp-block-paragraph">There is no way to win the argument this way, really. It immediately <strong>steers off to terminologies</strong> rather than answering the question and uses authorities instead of providing explanations. There is no real understanding behind these terminologies.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="538" src="https://shiftmag.dev/wp-content/uploads/2023/10/best-practice-1024x538.png?x32039" alt="" class="wp-image-1786" srcset="https://shiftmag.dev/wp-content/uploads/2023/10/best-practice-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2023/10/best-practice-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2023/10/best-practice-768x403.png 768w, https://shiftmag.dev/wp-content/uploads/2023/10/best-practice.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">What if we approached the same argument differently?</p>



<ul class="wp-block-list">
<li><em>I don&#8217;t know why repositories are suddenly placed in packages named by entities.</em></li>



<li>Why would you rather place them in a repository package?</li>



<li><em>Because you do not need to think much about where to put a class, it&#8217;s straightforward.</em></li>



<li>Let me ask you a question: do you spend more time reading or writing code?</li>



<li><em>Definitely reading, trying to understand what the heck is going on in there.</em></li>



<li>How many classes do you need to understand a certain use case?</li>



<li><em>Controller, service, repository, a couple of classes.</em></li>



<li>When using your IDE, would you rather have these classes close to each other or scattered across the project?</li>



<li><em>Close, I guess.</em></li>



<li>This is what &#8216;Package by Feature&#8217; is all about. The idea is that packages should contain related concepts that you would usually look at simultaneously. I&#8217;m pretty sure that when reading AccountService, the next class you are going to look at is AccountRepository and not CountryService, right?</li>



<li><em>Yeah, but it&#8217;s harder to think now which class goes where</em></li>



<li>Yeah, I agree it is harder, but remember you will read your code more than write it.</li>
</ul>



<p class="wp-block-paragraph">My encounters with Igor made me question, dissect, and refine my understanding of best practices. <strong>Each new concept had to withstand scrutiny and provide rock-solid answers to a stream of <em>whys</em>.</strong> Was it genuinely a best practice? Were there situations where it didn&#8217;t apply? This rigorous approach ultimately led me to a point where the questions became less necessary, and the knowledge became more ingrained.</p>



<h2 class="wp-block-heading"><span id="there-is-only-one-real-dogma">There is only one real dogma</span></h2>



<p class="wp-block-paragraph">Money.&nbsp;</p>



<p class="wp-block-paragraph">It serves as the ultimate driver behind our decisions and actions. To understand and deconstruct any dogma, you can employ a series of questions until we arrive at an answer that inevitably involves creating more value (money).</p>



<p class="wp-block-paragraph">Why should we write clean code – and what happens if we don&#8217;t?</p>



<ul class="wp-block-list">
<li>Bad code is harder to understand + harder to maintain = requires more money to change.</li>



<li>Applications that are hard to change eventually get dropped in favor of new ones (more money).</li>
</ul>



<p class="wp-block-paragraph">Why should we write tests? What happens if we don&#8217;t?</p>



<ul class="wp-block-list">
<li>We need to employ testers (which costs money) who need not only to test the new feature but also to test against regression.</li>



<li>Regression can be introduced that not even the tester can catch (which loses us money).</li>



<li>The feedback cycle between devs and the quality of the solution is increased. The developer needs to wait for the testers&#8217; approval (or disapproval) before merging the code. The feature is released later than sooner (losing more money).</li>



<li>Non-functional code changes are discouraged since they require extensive regression testing (and, therefore, cost more in man-hours). This means the software will soon become ugly, inheriting the same drawbacks as not writing clean code from above. </li>
</ul>



<p class="wp-block-paragraph">Engaging in these mental exercises can greatly assist in organizing and solidifying your knowledge. Once mastered, these conclusions can be used as corollaries for more complex questions.</p>



<p class="wp-block-paragraph">Why is the microservices architectural style popular?</p>



<p class="wp-block-paragraph">Why are applications favoring embedded Tomcat over traditional Tomcat?</p>



<p class="wp-block-paragraph">Why should product managers drive epics instead of developers?&nbsp;</p>



<h2 class="wp-block-heading"><span id="context-matters">Context matters</span></h2>



<p class="wp-block-paragraph">In addressing complex problems, a thorough exploration often requires <strong>delving into the historical context of best practices and considering various aspects that influenced their inception.</strong></p>



<ul class="wp-block-list">
<li>What specific problems did engineers face at that time?</li>



<li>Were resources readily available or constrained?</li>



<li>What tools were available at that time?</li>



<li>How were organizations structured?</li>



<li>Did developers take on testing and deployment?</li>



<li>Did they write SQL code?</li>



<li>Did they possess a deep understanding of the domain?</li>
</ul>



<p class="wp-block-paragraph">Take, for instance, the common practice of prefixing interface class names with the letter &#8216;I.&#8217; Some consider this a best practice, but why?</p>



<p class="wp-block-paragraph">It comes from a time when IDE-s were not that sophisticated, where developers needed to put prefixes in names to differentiate a regular class from an interface. There were also no &#8216;this&#8217; pointers, so class members were prefixed with &#8216;m&#8217;, while method parameters were prefixed with &#8216;p&#8217;.</p>



<p class="wp-block-paragraph">Good books will usually cover these topics, but it&#8217;s not something that an engineer will remember during their first reading. That&#8217;s why these practices need to be revisited until they click. You know it clicked if you could explain them to Igor.</p>



<h2 class="wp-block-heading"><span id="there-is-no-one-right-way">There is no one right way</span></h2>



<p class="wp-block-paragraph">Do note that both you and Igor might be right at the same time!</p>



<p class="wp-block-paragraph">In the conversation above, Igor stated that it&#8217;s harder to know where each class goes when packaging classes by feature. It requires people to define the boundaries of a feature.</p>



<p class="wp-block-paragraph">What if the feature undergoes a significant transformation, as it often happens? Adapting the packages becomes necessary, implying an evolutionary architecture. Do your team members possess the skills for such adaptability? You might not even be on the same project to enforce these practices in a month.</p>



<p class="wp-block-paragraph"><strong>Beyond understanding why something is good, researching why something is bad can be equally enlightening.</strong> A simple Google search for &#8216;why microservices suck&#8217; reveals how even established authorities don&#8217;t consider <a href="https://shiftmag.dev/on-everything-but-kubernetes-with-kelsey-hightower-463/" target="_blank" rel="noreferrer noopener">microservices a silver bullet</a>. For example, StackOverflow, a successful platform, operates as a <a href="https://nickcraver.com/blog/2016/02/17/stack-overflow-the-architecture-2016-edition/" target="_blank" rel="noreferrer noopener">monolithic application</a> on on-premise servers, defying the cloud-microservices paradigm. The point is not that microservices are inherently flawed but that deeper comprehension will always outperform blind adherence to trends.</p>



<p class="wp-block-paragraph">Building a deeper understanding can take various forms, but the core message I leave you with is simple. Never take things for granted and always ask:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="734" height="313" src="https://shiftmag.dev/wp-content/uploads/2023/10/image.png?x32039" alt="" class="wp-image-1683" srcset="https://shiftmag.dev/wp-content/uploads/2023/10/image.png 734w, https://shiftmag.dev/wp-content/uploads/2023/10/image-300x128.png 300w" sizes="auto, (max-width: 734px) 100vw, 734px" /></figure>
<p>The post <a href="https://shiftmag.dev/software-engineering-best-practices-dogmas-1681/">Are your engineering “best practices” just developer dogmas?</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>From file frustration to streamlined data exchange: Rethinking the approach</title>
		<link>https://shiftmag.dev/from-file-frustration-to-streamlined-data-exchange-999/</link>
		
		<dc:creator><![CDATA[Alen Kosanovic]]></dc:creator>
		<pubDate>Tue, 25 Jul 2023 17:29:06 +0000</pubDate>
				<category><![CDATA[Backend]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[anti-pattern]]></category>
		<category><![CDATA[CSV]]></category>
		<category><![CDATA[data exchange]]></category>
		<guid isPermaLink="false">https://shiftmag.dev/?p=999</guid>

					<description><![CDATA[<p>Each time some data is exchanged using files, a red flag should pop up, and you should ask yourself – what is a better way to do this? There probably is one.</p>
<p>The post <a href="https://shiftmag.dev/from-file-frustration-to-streamlined-data-exchange-999/">From file frustration to streamlined data exchange: Rethinking the approach</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></description>
										<content:encoded><![CDATA[<figure class="wp-block-post-featured-image"><img loading="lazy" decoding="async" width="1200" height="630" src="https://shiftmag.dev/wp-content/uploads/2023/07/data_exchange.png?x32039" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" style="object-fit:cover;" srcset="https://shiftmag.dev/wp-content/uploads/2023/07/data_exchange.png 1200w, https://shiftmag.dev/wp-content/uploads/2023/07/data_exchange-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2023/07/data_exchange-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2023/07/data_exchange-768x403.png 768w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /></figure>


<p class="wp-block-paragraph">Occasionally, everyone needs to handle data stored in files. CSV files seem like the way to go and are often the first choice &#8211; but I&#8217;d rather call them an anti-pattern.</p>



<p class="wp-block-paragraph">Let&#8217;s say a customer requests an Excel report containing specific data. If this is a one-time thing, we can conveniently send it via email. In most cases, however, the data needs to be sent regularly.&nbsp;Not all clients use sophisticated software like Kafka; even when they do, we don&#8217;t always have access to it. So we need a solution that is both universally available and easily understood. SFTP and CSV files seemingly fit the bill.</p>



<p class="wp-block-paragraph">This solution seems optimal for sending data to an external client. The problem arises when an internal application needs to integrate with ours, requires some data, and we decide to solve it by exporting CSVs. At first glance, this seems a low-hanging fruit.</p>



<p class="wp-block-paragraph">Everyone can download a file.</p>



<p class="wp-block-paragraph">Everyone can read a CSV.</p>



<p class="wp-block-paragraph">It&#8217;s already developed.</p>



<p class="wp-block-paragraph"><strong>While it may appear&nbsp;<em>that</em>&nbsp;simple, ultimately, it proves to be more costly than using a dedicated component for data exchange. </strong>I learned my lesson the hard way. I&#8217;ve worked on both applications that sent and received data via files. Here are some of the issues I discovered along the way.</p>



<h2 class="wp-block-heading"><span id="data-storage">&nbsp;<strong>Data storage</strong></span></h2>



<p class="wp-block-paragraph">The first thing we need is a place to store the data. Since our data is stored in files, it must be placed within a file system. The decision we face is whether to store the files on the&nbsp;<strong>producer</strong>&nbsp;machine,&nbsp;<strong>consumer</strong>&nbsp;machine, or an&nbsp;<strong>intermediary</strong>&nbsp;machine. Each option has its advantages and disadvantages.</p>



<p class="wp-block-paragraph"><strong>Using the producer</strong>&nbsp;machine results in the consumer bearing the entire networking load. The consumer will need to periodically retrieve the data through a&nbsp;<strong>PULL</strong>&nbsp;operation. In the event of a network link failure, the producer will remain unaffected.&nbsp;</p>



<p class="wp-block-paragraph">However, this solution has a drawback &#8211; when consumers are redundant, and there are multiple instances, each instance may attempt to download the same file. Consequently, the same data will be processed multiple times. To address this,&nbsp;<strong>each instance should reserve the file before initiating the download</strong>. This can be accomplished by appending a suffix to the file name or moving the file to another folder. Once the file is reserved, the consumer application can proceed with the file download.</p>



<p class="wp-block-paragraph"><strong>Using the consumer</strong>&nbsp;machine puts all the networking burden on the producer. The producer needs to&nbsp;<strong>PUSH&nbsp;</strong>the data to the consumer machine once the file is created. The consumer machine can watch the local file system for changes and react when a new file is created. As a result, the push-based approach can yield a faster response by the consumer and does not put any networking burden on the consumer. Since the file is sent directly to the consumer instance, this approach does not need&nbsp;<em>file reservation.</em>&nbsp;</p>



<p class="wp-block-paragraph">Pushing files to consumers also has a considerable downside &#8211; the producer must balance these files between the consumer instances. Implementing effective client-side balancing is a tough nut to crack. The producer would need to adapt its balancing strategy when a consumer instance gets offline or online and is added to or removed from the group.</p>



<p class="wp-block-paragraph"><strong>Using an intermediary machine</strong>&nbsp;combines elements of both previously mentioned approaches. It eliminates the need for client-side balancing, but the consumer still needs to reserve the file before downloading it. The data storage is independent of both the consumer and producer, although both parties are still required to transfer files over the network.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="538" src="https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange1-1024x538.png?x32039" alt="" class="wp-image-1053" srcset="https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange1-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange1-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange1-768x403.png 768w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange1.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading"><span id="data-retention"><strong>Data retention</strong></span></h2>



<p class="wp-block-paragraph">Regardless of the chosen method for storing data, it is crucial to ensure that the disk is not filled with files. Failing to do so will render the machines (and the services running on them) unusable. The primary line of defense is to&nbsp;<strong>store files on a separate section of the disk</strong>.&nbsp;</p>



<p class="wp-block-paragraph">Even if the partition gets filled with files, it will not impact other services. This advice applies even when files are stored on an intermediary machine, as some operating system functionalities may not work properly if the disk space is occupied.</p>



<p class="wp-block-paragraph">Accumulating files can happen quite easily. For instance, the consumer application may be down (or not deployed) while the producer application continues to generate files. It can also occur if the producer generates a high volume of data the consumer cannot keep up with.&nbsp;</p>



<p class="wp-block-paragraph">In such cases, it is necessary to prevent the files from <strong>overflowing the disk.</strong> If the data represents events and skipping a few events in the event of a failure is acceptable, a retention policy should be implemented.&nbsp;</p>



<p class="wp-block-paragraph">For example, a script that periodically deletes the oldest files can be developed. This script adds <strong>another component to the architecture that needs to be created, maintained, and monitored</strong>. If the script malfunctions or contains a bug, the data retention may not work as intended.</p>



<h2 class="wp-block-heading"><span id="data-processing"><strong>Data processing</strong></span></h2>



<p class="wp-block-paragraph">A file is removed from the disk when a consumer has read and processed the whole file content. The &#8216;whole file content&#8217; is emphasized since a file represents a batch of data. Errors or failures can happen at any point between parsing and processing the data. If you delete the file without processing all the data contained within it, the data will be lost. On the other hand, if you do not delete the file but have already processed some of the data, you will end up processing the same data twice. This poses a data integrity concern that needs to be addressed. Both discarding data and processing data twice are undesirable and potentially unacceptable. That is why&nbsp;<strong>it is necessary to process a file in its entirety before deleting it</strong>.</p>



<p class="wp-block-paragraph">This can be challenging, especially if the application involves multiple processing steps, including several database writes. Errors occurring in any of these phases can result in the entire batch being reversed. Additionally, processing a batch of data within a single transaction restricts the data processing to only one thread. File reading and data processing should be performed in separate threads to optimize performance.</p>



<p class="wp-block-paragraph">One possible solution is to relax the data integrity requirement by&nbsp;<strong>implementing a queue where all the data is stored after parsing</strong>. This approach considers a file processed once all its records are inserted into the queue. Records can then be dequeued one by one, preventing the entire batch from being reverted. The issue with this approach is that the data in the queue will be lost in the event of an abrupt application failure. Since abrupt application failures are expected to be rare, this trade-off may be acceptable. If preserving data is not acceptable, a persistent queue for the data can be introduced (but we opted out of using new components in favor of using&nbsp;<em>simple CSV reading</em>).</p>



<p class="wp-block-paragraph">It is also important to&nbsp;<strong>set a reasonable limit to the number of records in a file</strong>. A large file might present a huge load of data at once. So huge that it might crash the data if it does not have the memory to read the whole file.</p>



<h2 class="wp-block-heading"><span id="data-sharing"><strong>Data Sharing</strong></span></h2>



<p class="wp-block-paragraph">Once everything is set up and all the monitoring points are implemented (excluded from this article), we can enjoy our manually implemented file-based data exchange solution… until a new consumer is needed for the same data.&nbsp;</p>



<p class="wp-block-paragraph">Fortunately, we already have this functionality (file download+reservation, data retention, data queuing, monitoring, etc.) supported, and we can easily re-use it in any new consumer. Hopefully, the code has been written well enough to be copied and pasted into a library. Otherwise, there will be significant code duplication. Let&#8217;s not forget to create<strong> documentation for the module </strong>so that the solution can be integrated effortlessly.</p>



<p class="wp-block-paragraph">Once we move this code to a module, our file-based data exchange solution will become a reusable component that any application can utilize (provided it is written in the same programming language). The only thing left is instructing the producer to export the files to a new location. There might be some duplicated data between the two locations, but let&#8217;s hope we will not add many of these consumers to the system.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="538" src="https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange-files-1024x538.png?x32039" alt="" class="wp-image-1052" srcset="https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange-files-1024x538.png 1024w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange-files-300x158.png 300w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange-files-768x403.png 768w, https://shiftmag.dev/wp-content/uploads/2023/07/data-exchange-files.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading"><span id="data-storage-already-handles-this-%e2%80%93-and-it-does-it-better"><strong>Data storage already handles this – and it does it better</strong></span></h2>



<p class="wp-block-paragraph">These are only some of the issues that we encountered. There are more of them, some not even mentioned here, and others are yet to be discovered. To resolve them, we had to invest time in development, refactoring, and as a result, we now have a code base to maintain.&nbsp;</p>



<p class="wp-block-paragraph">But <strong>these problems were not unique to us.</strong> They were common problems that most data storage software handles out-of-the-box and does it better!</p>



<p class="wp-block-paragraph">The selection of software depends on the nature of the data. In our case, the data were events, and the producer application performed some batch processing on it. A more&nbsp;suitable storage option than the one we have been using <strong>would be a messaging system:</strong></p>



<p class="wp-block-paragraph">· Producers and consumers would write and read from a topic or a queue.</p>



<p class="wp-block-paragraph">· Data would be stored and replicated to another machine, also enabling Geo-redundancy.</p>



<p class="wp-block-paragraph">· Retention would be managed by the platform, eliminating the need for manual scripts.</p>



<p class="wp-block-paragraph">· Messaging systems have a&nbsp;<em>commit</em>&nbsp;feature to indicate that a record (or batch) has been processed.</p>



<p class="wp-block-paragraph">· Some messaging systems support consumer groups, allowing concurrent processing out-of-the-box.</p>



<p class="wp-block-paragraph">· Different consumers (applications) can be subscribed to the same topic.</p>



<p class="wp-block-paragraph">· Applications can be written in the most popular programming languages.</p>



<p class="wp-block-paragraph">· Monitoring tools for popular systems are already available.</p>



<p class="wp-block-paragraph">· Popular systems are usually well-documented.</p>



<p class="wp-block-paragraph">For other types of data, the solution might be a more suitable data store like <strong>Redis or Postgres</strong>. It all depends on what the data is about and how it can be presented.</p>



<p class="wp-block-paragraph"><strong>Exchanging data via files should be considered an anti-pattern</strong> and only be used when other approaches cannot be implemented (like when integrating with a legacy system).&nbsp;Each time some data is exchanged using files, a red flag should pop up, and you should ask yourself &#8211; what is a better way to do this? There probably is.</p>
<p>The post <a href="https://shiftmag.dev/from-file-frustration-to-streamlined-data-exchange-999/">From file frustration to streamlined data exchange: Rethinking the approach</a> appeared first on <a href="https://shiftmag.dev">ShiftMag</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: shiftmag.dev @ 2026-09-08 11:55:13 by W3 Total Cache
-->