<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Engineering, testing and discipline]]></title><description><![CDATA[Software Engineer working on DefiSaver. In love with backend and infra, but not estranged to other fields as well. TDD enthusiast.]]></description><link>https://gitpub.xyz</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 11:11:52 GMT</lastBuildDate><atom:link href="https://gitpub.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Careful how much AI-ing you do]]></title><description><![CDATA[I decided to change my course of using AI in my day-to-day developments.
How the cherishing of AI began
I knew about Copilot for cca a year, or a year and a half after it was released to the masses. For pure conservative reasons (I’m from the Balkans...]]></description><link>https://gitpub.xyz/careful-how-much-ai-ing-you-do</link><guid isPermaLink="true">https://gitpub.xyz/careful-how-much-ai-ing-you-do</guid><category><![CDATA[AI]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[cursor]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Mon, 28 Apr 2025 18:37:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745865428564/9791b2c9-dc82-4749-aa44-43175368bfb4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I decided to change my course of using AI in my day-to-day developments.</p>
<h3 id="heading-how-the-cherishing-of-ai-began">How the cherishing of AI began</h3>
<p>I knew about Copilot for cca a year, or a year and a half after it was released to the masses. For pure conservative reasons (I’m from the Balkans after all), I didn’t use it. The classic egoistic thoughts of <em>pff that can’t be that good. Whatever, it’s not that much helpful.</em> And others. I can’t remember why I tried it, but I decided to try it. I was on a call with my TL at that time, pairing on some coding. I was blown away. That dude (Copilot) could anticipate the things I was going to write! It started writing tests for me, and I could <em>TAB</em> ⇥ so much of my work.</p>
<p>I. loved. it.</p>
<p>As time progressed, I started leaning in to AI usage more and more. Nothing crazy. But day by day, <strong>(this part is very important)</strong> things began to change. I started google-ing less, I started reading documentation less, I started challenging myself less, I started reading source code less, I started <strong>writing</strong> less.</p>
<p>To be fair, I owe some very good solutions to AI. I remember once, I was busting my brains out how to solve something in Terraform. At least in a nice way. Decided to go to ChatGPT (or as Primeagen calls it ChatGipity), asked my question, and it offered a very nice suggestion to me. Some of it I didn’t know existed, but some of it I just fell stupid that I didn’t think of. At the same time felt amazing with ChatGPT, and bought the first-class ticket to <strong>lets use AI everywhere.</strong></p>
<p>I’m not sure that destination is somewhere you want to go.</p>
<h3 id="heading-how-the-annoyance-of-ai-began">How the annoyance of AI began</h3>
<p>The first thing that started occurring to me, is that programming began to be less fun. I mentioned that as a very important point. At least to me. Since I love programming. I can spend hours and hours programming something fun and laugh out loud about it. I was <em>TAB</em>-ing, not programming.</p>
<p>The second sign was that Copilot was starting to get it wrong more and more as time progressed. After a while, Copilots invasive recommendations actually started bothering me. I think I couldn’t browse normally through code without it making itself known with a useless suggestion.</p>
<p>The last one was the Cursor overuse. Even at my workplace, talks about Cursor and people using Cursor way too much for pretty much everything in my opinion.</p>
<p>The final one was the appearance of <em>Vibe coding</em>. Quite honestly, my reaction to <em>Vibe coding</em> was, <em>what is happening, where am I?!</em> Generally devs have become astonishingly lazy. The amount of time and effort spent into development of features/improvements or learning/improving. But this was a whole other level.</p>
<p>Remember how I mentioned ChatGipity solved my Terraform problem? Well, you can view the whole situation from a different angle. I didn’t know my stuff good enough to solve my problem. Because of the laziness accumulated over time, I didn’t delve deep enough into learning Terraform and the Hashicorp tools to solve my problem.</p>
<h3 id="heading-how-i-started-shifting-my-perspective">How I started shifting my perspective</h3>
<p>After getting annoyed as fuck with AI, I decided to rotate it a bit. I uninstalled Copilot, and I switched to JetBrains AI. The reason I did that is that basically JetBrains AI offers almost no auto-completion suggestions. At least doesn’t work for me. But, I retained the option that I can have a chit-chat with the AI about some problem if I need to.</p>
<p>Took a bit of getting used to, but my productivity started increasing actually. With the overall productivity, I noticed that I generally produce better code without it. <em>I still use it to generate myself some getter functions</em>.</p>
<p>I wanted to delve deeper into it. So I threw myself into a spiral of philosophical thinking, and investigations. I came to a set of conclusions about it. <strong>It is bad for you, don’t overdo it</strong>.</p>
<h3 id="heading-1-juniors-are-in-the-risk-of-getting-stuck">1. Juniors are in the risk of getting stuck</h3>
<p>Personally, I think juniors are in big trouble. The amount of deep learning and dedication juniors do nowadays (because of crazy frameworks) is at an all time low. But, with Copilot or any other AI tool, the shit is really hitting the fan. In a time-span of 5-10 years, I think current juniors and beginners could suffer the most impact. They will be stuck in a beginner spot, not being able to progress. Dust will fall on their brains, but expectations will start to grow. From themselves and from their employers.</p>
<p>Keep in mind, when you start using Copilot, you are usually astonished with the quality of code it produces. But usually you use it on a function so simple a high school beginner can get it right.</p>
<h3 id="heading-2-your-brain-functions-differently-when-you-write-code">2. Your brain functions differently when you write code</h3>
<p>When you write code, and when you read code, your mind functions totally different. When we read code, like a code review, our minds usually look for bugs, logical errors, and some semantics. Rarely we have the whole scope in our heads, having the feel of impact of that code on the codebase. Thats what happens when you spit all the code from Copilots/Cursors suggestions. I’m 99% confident, that 99% of code suggested can be written better. Not taking into account the prompts like: “Write me a function that does a binary search of <code>[]int</code>“. When you write code, it is totally different. While developing your feature while writing everything, we always delve deeper. We understand what impact our code has deeper. We write it better, we browse around more. The whole approach in our mind is different.</p>
<h3 id="heading-3-we-stopped-learning">3. We stopped learning</h3>
<p>We stopped learning. We don’t delve deep anymore. For example, imagine writing a prompt like: “ChatGipity, create me a middleware for Go echo library that adds random numbers to Cookie Header“. You’ll get your piece of code, probably works because its simple enough. Though usually even misses that, but at least throws some direction. You finish it soon enough, and voila, off to production. But you haven’t learned anything. You haven’t read echo library docs. You haven’t gone through the echo source code. You don’t know what is happening under the hood. Prompt by prompt, we know less and less. Because we don’t need to. We offload it.</p>
<h3 id="heading-4-to-do-the-hard-things-you-have-to-master-the-easy-things">4. To do the hard things, you have to master the easy things</h3>
<p>By offloading everything like that, you started to lose touch with things. You start losing your ability to implement simple and easy things. And if you don’t have a handle on the easy things, you can’t go do the hard things at all. When you have the easy things mastered, the hard things become easier as well. But, its the other way around as well. With losing track of the easy things, you won’t be able to solve the hard things. You know that saying you can’t run without learning to walk first. Yeah, but you can’t let yourself forget to walk as well.</p>
<p>What helped me to fortify my feelings towards AI and its usage is running into a lot of articles from people in the industry that I have the utmost respect regarding software engineering and coding in general. It seems to me that they are fighting hard against Vibe coding, and for a good reason.</p>
<hr />
<p>Don’t get me wrong, I don’t think we should ditch AI tools completely. I think they are amazing. I still use AI in my IDE. I love to have a good discussion with it. Its like a colleague in pair programming, but with all the books and references in mind. <em>Hey, I want to create a secure shell application. I presume the Elm framework would be suitable. Tell me about the Elm framework. What are the good and bad sides. Give me application examples I can browse through</em>.. etc.. etc.</p>
<p>Careful not getting trapped in the AI does everything for me rabbit whole. In a year or two, you will regress a lot.</p>
]]></content:encoded></item><item><title><![CDATA[Why is mentoring important?]]></title><description><![CDATA[There is probably a proverb somewhere regarding my hacky translation of our proverb. This is the closes I got. I mean ChatGPT. (In Serbia: Није знање знати, знање је дати.)
In these recent days, I’m beginning to realise, how important it actually is ...]]></description><link>https://gitpub.xyz/why-is-mentoring-important</link><guid isPermaLink="true">https://gitpub.xyz/why-is-mentoring-important</guid><category><![CDATA[mentoring]]></category><category><![CDATA[Junior developer ]]></category><category><![CDATA[senior-software-engineer]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Sun, 23 Mar 2025 19:31:23 GMT</pubDate><content:encoded><![CDATA[<p><em>There is probably a proverb somewhere regarding my hacky translation of our proverb. This is the closes I got. I mean ChatGPT. (In Serbia: Није знање знати, знање је дати.)</em></p>
<p>In these recent days, I’m beginning to realise, how important it actually is to have a good mentor. To have someone who actually dedicates themselves, their time, energy, brain cells, etc to someones development, wellbeing and improvements. I’ve always known that in a way. But some things, over time and experience, you understand differently. More profoundly. This is one of those.</p>
<p>From time to time, I help out a really close friend of mine for something in his professional life. Either it being a mini debug session because an ORM is giving him issues, or some thought exchanging, guiding. I hate to brag, but I am in luck to have a lot more experience than him, so I tend to help out in any way I can. Even though, that is not nearly enough. We are not having full work days together and the luxury of working together so I can actually work with him on developing certain areas.</p>
<p>In those help out sessions, from time to time, I have a peak into his code. To be brutally honest. Quite often my reaction is, “oh my god“. His code is not bad. It’s actually done really well. On his level. But, his level should be quite higher in the amount of time has passed him being employed. So, my reaction is actually not aimed at him at all. I get disturbed by the non-amounts of time dedicated by his senior peers to him on his development. Even though he is solving complex problems in a good manner, he still has code blocks with:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;Something&gt; <span class="hljs-title">GetThis</span>(<span class="hljs-params"></span>)</span> 
{
    <span class="hljs-keyword">await</span> ...
    <span class="hljs-keyword">await</span> ...
    <span class="hljs-keyword">await</span> ...
    <span class="hljs-comment">// Pardon my C# writting, I have never worked with it in my life. </span>
    <span class="hljs-comment">// Though read a lot of its code</span>
}
</code></pre>
<p>In my opinion, after two to three years of working experience, you should understand that having everything async, but await everything as well doesn’t really make sense. This tells me something else. No senior has ever challenged his perspectives and understandings of architecture/code design. They haven’t dedicated time to him to explain why this might not make sense. I was the first one. That pisses me off.</p>
<h3 id="heading-you-dont-know-what-you-dont-know">You don’t know what you don’t know</h3>
<p><em>You don’t say Pavle?</em></p>
<p>Yeah yeah, I know. Stating the obvious here. But, think about it a bit more. You can’t even begin to comprehend something if you don’t know about its existence, right?</p>
<p>Yes, you can learn everything in the world on your own. But it would take you way too much time. Thats what the education system is for (not getting into it is it good or bad). Just imaging having to learn math from scratch. On your own. No books or anything. Well people had to do it for quite a huge number of years. Now with books and teachers, all that learning is squashed into few years of your life.</p>
<p>Same goes for mentoring. If you let a junior, wonder around, poke stuff and make it work somehow. Without guidance and knowledge sharing. They are going to be wasting huge amounts of time. And in the same time, expectations from them will rise, because if you work for two to three years, your potential future employers (or current ones) will expect certain levels from you. That you might not have. Not because you are on the wrong side, rather because you didn’t have any help and you are on your own. Lets be honest, advanced and good self learners are rare as diamonds. We all go through professors, books and mentors to have a good jump up.</p>
<h3 id="heading-why-you-should-mentor-someone">Why you should mentor someone?</h3>
<p>I was extremely lucky to have great mentors in several places I found myself working. From the very beginning (Shoutout to Victor and Igor). Yet, now I can be even more thankful to them, when I realise just how much it is important.</p>
<p>I encourage you. Take care of the less experienced. Teach them. Guide them. Challenge their perspectives and help them improve themselves where ever you can. Sometimes, that might get personal. Where you might need to help with a personal problem. Most of the times its code, design, software philosophy, etc. One of the most beautiful and fulfilling feelings is helping someone be better. And letting them take all the credit. Because it is theirs.</p>
<p>The biggest benefit of all. You will grow a lot and learn a lot. They can, should and will challenge your perspective. Their out of the box thinking pushes you to learn more and understand something more deeply.</p>
<p>Don’t fall in the trap that you have to control the knowledge. That you have to make every decision. That you have to be asked for every opinion. You destroy your peers improvements that way. Focus your efforts into them going through all of it with guidance. Sometimes pushback. It will be worth it in the long run. As they say, the best team lead (or manager) is the one that has to do absolutely nothing in his work.</p>
<p>What a Sunday rant. Have a nice one.</p>
]]></content:encoded></item><item><title><![CDATA[The cognitive code strain on our brain]]></title><description><![CDATA[Something I noticed, unfortunately, to be deprioritized in the benefit of following some of Uncle Bob's rules blindly is the cognitive complexity we put on ourselves and our colleagues while writing code.
This brings unnecessary complexity to our cod...]]></description><link>https://gitpub.xyz/the-cognitive-code-strain-on-our-brain</link><guid isPermaLink="true">https://gitpub.xyz/the-cognitive-code-strain-on-our-brain</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Complexity]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Sat, 30 Mar 2024 11:00:45 GMT</pubDate><content:encoded><![CDATA[<p>Something I noticed, unfortunately, to be deprioritized in the benefit of following some of Uncle Bob's rules blindly is the cognitive complexity we put on ourselves and our colleagues while writing code.</p>
<p>This brings unnecessary complexity to our code. Even though on the first hint it tricks us that it’s more descriptive and readable, it requires more effort by an another engineer to understand the code. Probably ourselves as well, just in a few months when we come back.</p>
<p>It’s also quite related to the code complexity learning curve meme of a Junior Engineer to Senior Engineer. Whereas more seasoned engineers like to keep it simple. There’s another picture that reminds me of it:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*_uLYD-N9sgT7KnZMRGcPNA.png" alt /></p>
<p>What is the cognitive strain of our brain? Basically putting a cognitive strain on the brain means that we are tiring it. The amount of cognitive complexity of our code is directly proportional to how tired someone is going to be and how much effort and time someone has to invest to go through and understand the code.</p>
<p>One extreme is being completely oblivious to the code we are writing, like naming all of our variables <code>a, b, c, d, i, k, l</code> . I’m trying to tackle the other side, overengineering and overcomplicating it.</p>
<p>Let me give you an example.</p>
<p><em>I write my examples in Go because I’m focusing on it now and working with it, but this is applicable to any environment. With the note that all environments have their own conventions on how-to.</em></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetPrices</span><span class="hljs-params">(currency <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(http.Response, error)</span></span> {
   <span class="hljs-comment">//... Setup code - includes creating client and httpRequest</span>

   resp, err := client.Do(httpRequest)
   <span class="hljs-keyword">if</span> isResponseSuccessful(resp.StatusCode) {
    <span class="hljs-comment">// Do something</span>
   } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Do something else</span>
   }

   <span class="hljs-keyword">return</span> *resp, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isResponseSuccessful</span><span class="hljs-params">(statusCode <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">bool</span></span> {
   <span class="hljs-keyword">return</span> statusCode == <span class="hljs-number">200</span>
}
</code></pre>
<p>Here we see a function that will make an HTTP request to get a price of a currency. I’m not focusing on some details to not overload you (you see what I did there ;) ) with Go as a language and basic setting up of an HTTP client.</p>
<p>What I encountered numerous times is functions and methods getting extracted endlessly but totally unnecessary. Here to achieve a more nice descriptive naming we extracted a response check to a separate function that does a really basic job. But to me who is going through the code the first time, I have to ctrl/cmd + click it to see what the function is doing. Because, what is a successful response? HTTP 200? HTTP 201? HTTP 2xx? Who says that the function name is telling the truth? In reality, it will be slightly more complicated than <code>statusCode == 200</code> . Either way, we will have to jump down, jump back up, and try to remember where we were the moment before. All of that could be avoided by “making it a bit more ugly” (even though I don’t agree with that):</p>
<pre><code class="lang-go">resp, err := client.Do(httpRequest)
<span class="hljs-keyword">if</span> resp.statusCode == <span class="hljs-number">200</span> {
  <span class="hljs-comment">// Do something</span>
} <span class="hljs-keyword">else</span> {
  <span class="hljs-comment">// Do something else</span>
}
</code></pre>
<p>Here, we immediately know what is happening and what is the goal. Let’s face it, all engineers know that status code 200 is a successful response.</p>
<p>The issue arises because cognitive complexity is incremental. This small function is no big deal. But over time, function by function, method by method. We gain hundreds of methods that are not used anywhere else just to stamp them with a nice name.</p>
<p>Another example commonly found is:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Something</span><span class="hljs-params">(listOfItems []<span class="hljs-keyword">string</span>)</span></span> {
 item := findItem(listOfItems, <span class="hljs-string">"item"</span>)

 <span class="hljs-comment">// do something with item</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findItem</span><span class="hljs-params">(listOfItems []<span class="hljs-keyword">string</span>, item <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
 <span class="hljs-keyword">for</span> _, listItem := <span class="hljs-keyword">range</span> listOfItems {
  <span class="hljs-keyword">if</span> listItem == item {
   <span class="hljs-keyword">return</span> listItem
  }
 }
 <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>
}
</code></pre>
<p><em>This looks like some</em> <code>for</code> <em>manual job that you usually don’t encounter, but in Go, it’s quite normal. We don’t have fancy .find() methods. :)</em></p>
<p>Here we find ourselves yet again in a situation, where we would have to go level down to the function, understand what it’s doing and come back up. All for a nice name for the most basic <code>for</code> loop you can see. When this gets incremented over time and amplified it’s really hard and tiring to jump through the matrix up and down to understand simple code.</p>
<p>Let’s try to write simple code, maintainable code and code that we understand easily without firing up our brains to some levels.</p>
<p>By the way, Go is a phenomenal language that is addressing this issue. One of the main purposes of Go is <em>Keep it simple</em>. I think anyone who appreciates that will appreciate Go as a language and could try it! I encourage you!</p>
<p>Keep in mind, this is not related to designing your codebase, your architecture and others. That’s a whole other topic.</p>
<p>I’m obliged to give enormous credit to two people and a book.</p>
<p>My first mentor from my first company was one really talented and fun engineer. Unfortunately, I think I understood many of the lessons later on, but I understood them better thanks to him. Thank you, Victor!</p>
<p>The second is my former boss from Zühlke. He quite directly addressed this <em>bug</em> with me. He was discussing it with me and went into more detail with also recommending the book. Thank you, Igor!</p>
<p>The book is <a target="_blank" href="https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201"><em>A Philosophy of Software Design — by John Ousterhout</em></a>. A huge eye-opener and a good challenge to some coding standards. It’s quite small and short but full of beautiful details.</p>
]]></content:encoded></item><item><title><![CDATA[Be a software engineer - not a tech stack engineer]]></title><description><![CDATA[In the profession of software engineering, I noticed that people often limit themselves to a particular tech stack and don’t want to move forward. Calling themselves Java Engineers, NodeJs Engineers, etc. Of course, there are people that are developi...]]></description><link>https://gitpub.xyz/be-a-software-engineer-not-a-tech-stack-engineer</link><guid isPermaLink="true">https://gitpub.xyz/be-a-software-engineer-not-a-tech-stack-engineer</guid><category><![CDATA[Technical writing ]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Fri, 29 Mar 2024 14:30:40 GMT</pubDate><content:encoded><![CDATA[<p>In the profession of software engineering, I noticed that people often limit themselves to a particular tech stack and don’t want to move forward. Calling themselves Java Engineers, NodeJs Engineers, etc. Of course, there are people that are developing the language itself, but I’m not aiming for that. By doing so, and not wanting to expand your horizon, you quite probably limit yourself to both business opportunities, but also just learning more and advancing your skills.</p>
<p>In addition to forcing a bad tech stack to a particular problem. For example, forcing NodeJs to do some <em>.pdf</em> magic parsing whereas a Java popular library does it out of the box with minimum effort, it’s quite a strain. People are skipping job offers with the most amazing teams and companies and projects that are <em>not their stack</em>.</p>
<h2 id="heading-its-in-the-principles-not-the-stack">It’s in the principles — not the stack</h2>
<p>Personally, I started with the JVM world and have a profound love for it. In the beginning, it was Java, but later on, I stumbled upon Kotlin and got amazed. So for a while, my tech stack was Java&amp;Kotlin on the backend. I guess I was boring enough to persuade my colleagues to introduce it to our project. Thank you Alex &amp; Victor! Of course, as a Java developer, it is my honour duty to always talk s!@#! about JavaScript, npm and the whole package. I think that every time a Java developer that works with JavaScript runs into a silly JS problem has to do the <em>sigh</em> and say <em>Fu!@ing JavaScript</em>. But as life likes to do to it, I ended up with my company on a project that is working exclusively with NodeJs and Typescript. Of course, I had previously mentioned moments.</p>
<p>Over time, I actually liked it. But most of all it made me realise something really important. I was doing the absolute same thing as I was doing with Java or Kotlin, just in a different language. Especially since TypeScript is so similar to Java, I needed one full working day to adapt and for people to not know that I’m actually a Java developer. It helped me realise, the principles are the same everywhere! What I didn’t know out of the box, I could easily find in the docs or google it. Because I know what to look for. (By the way, big shoutout to <a target="_blank" href="https://docs.nestjs.com/">NestJs</a> documentation. It’s amazing!) I needed an endpoint, ok, let’s see how to make that controller. Oh, I need to connect to my SQL database, ok, let’s see how they make repositories here. Event-driven time! Cool! Let’s see how they do that in this environment!</p>
<p>You are always solving similar or the same issues, the <strong><em>principles</em></strong> always apply! You are designing a REST API. You are setting up a Book entity that you want to save to your relational database. You are calculating the time to execute something. You are reaching out to some third-party API to send a notification. All those are tech stack agnostic. Clean code and readable code also follow. Yes, languages have their own conventions that could differ, but if you have a healthy approach to clean and readable code, you will do it everywhere.</p>
<p>So don’t limit yourself. Don’t skip that opportunity because you never typed that language. Take it as a challenge to learn more, you will advance most significantly!</p>
<p>So when someone asks a question that is related to the topic. I like to say that <em>I’m a Software Engineer, not a Java Engineer</em>. Thanks to that mindset I got one of the most wonderful opportunities to work at <a target="_blank" href="https://www.decenter.com/">Decenter</a> with an amazing team developing <a target="_blank" href="https://defisaver.com/">DefiSaver</a>. Here, we work with Go, and that’s quite a shift compared to the previous languages. But it’s super fun, I can rely on my colleagues to help out where needed, but for the most part, I can develop without any issues.</p>
<hr />
<p>One of my favourite approaches is the T-shape approach. You are familiar with multiple sides and stacks, but you are proficient in one area. For me, that was the JVM world. But I have grown to like Go so much that it might grow to be the proficiency I’m after. Know your architecture, know your software design, know your databases, etc. Don’t limit yourself to the language and be brave to experiment. It will be a wild and fun ride!</p>
]]></content:encoded></item><item><title><![CDATA[Automate, automate and automate!]]></title><description><![CDATA[I hope everyone is lucky enough, to have that one annoying friend, the friend that tells you everything as is. Honestly. Usually, it’s quite welcoming, but sometimes. Sometimes it can be one big pain in the a@!.
Well, automation is that friend and mo...]]></description><link>https://gitpub.xyz/automate-automate-and-automate</link><guid isPermaLink="true">https://gitpub.xyz/automate-automate-and-automate</guid><category><![CDATA[Terraform]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Fri, 29 Mar 2024 14:29:36 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://miro.medium.com/v2/resize:fit:700/1*6Y9jshF-FKR384k0L9Hypw.png" alt /></p>
<p>I hope everyone is lucky enough, to have that one annoying friend, the friend that tells you everything as is. Honestly. Usually, it’s quite welcoming, but sometimes. Sometimes it can be one big pain in the <em>a@!</em>.</p>
<p>Well, automation is that friend and more.</p>
<h2 id="heading-why-i-personally-like-automation">Why I personally like automation</h2>
<p>The software engineering OCD of course! 🙃 That is not a 100% joke actually.</p>
<p>During my day-to-day development, I try to automate processes as much as I can. Or at the very least, I try to make a collection of steps easier to repeat. Currently, I’m very lucky to work in a <a target="_blank" href="https://go.dev/">Go</a> environment and we use <a target="_blank" href="https://github.com/spf13/cobra">Cobra</a> to create our internal CLI tools. Oh, the happiness! Each time I stumble upon a repetitive task I try to make a tool so I can make mine and the life of my colleagues easier.</p>
<p>Personally, I like automating steps, especially in the CI/CD workflow, to minimize my potential mistakes. In addition, when you set up your automation to be good, it can be painfully ruthless. If you go to higher measures with linting, when you just forget that one indentation and you get an 🔴. That’s so annoying! I love it! Because it stopped me from piling them so the next time I do formatting it’s not a huge change.</p>
<p>There are a lot of boring tasks that automation can solve. Running tests, builds, etc in parallel. One of the most boring, but crucial tasks is setting up your local environment. That is especially useful for new colleagues. Even though personally I don’t use them because of Goland, the VSCode Dev container setup is amazing. You specify everything there and all a new developer has to do is turn on VSCode and start the dev container, and voila you are good to go.</p>
<p>Setting up your CI/CD well can also help you carry the load of all the verifications. Let’s say even that you would locally run tests, vetting, linting, etc. Why not just do <code>git push</code> and continue on, you will get your results soon enough.</p>
<p>You can even partially automate your PR review process. Introducing <a target="_blank" href="https://www.sonarsource.com/products/sonarqube/">SonarQube</a> to your CI, SonarQube can flag items for you, reducing the load on your colleagues for the first iteration at least.</p>
<p>Summing up. Automating our day-to-day tasks reduce the load you encounter, it will struggle with various setups so we don’t have to, it will be strict so we don’t become lazy, it won’t make silly mistakes with version bumping or the like, and the green marks simply feed the OCD.</p>
<h2 id="heading-automation-challenges">Automation challenges</h2>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*dLic2hnCGdjy_UgjNvu4Ag.png" alt /></p>
<p>After attempting to sell the story of how nice it is, there is the other side of the medal as well. In the beginning, until you get the hang of it, it can be a bit challenging to set up.</p>
<p>When you switch to a new tech stack, a new git hosting platform or anything new. The pain is the biggest. Every little step is quite annoying. “<em>Oh I forgot to run go fmt!”</em>. The triggers for the CI won’t run when supposed to. They will consume too much time. You will fail and fail. But bear with it. Endure it a bit more and it will be rewarding. A bit of discipline is required.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://gitpub.xyz/discipline-within-software-engineering">https://gitpub.xyz/discipline-within-software-engineering</a></div>
<p> </p>
<p>The picture above is a perfect example. You will have to re-run your automation many, many times until you get with the flow of writing and expanding it. You might feel a bit stressed at that time, and you will be. But it’s an investment, just like everything else.</p>
<h2 id="heading-going-the-extra-mile">Going the extra mile</h2>
<p>You can go even further. You can introduce an IaC (Infrastructure as Code) tool to your workflow. That brings version control, less forgetting, and taking care of a lot of things with it! For example, imagine you can just do</p>
<pre><code class="lang-go">module <span class="hljs-string">"new_company_member"</span> {
  <span class="hljs-comment">// some data here</span>
  <span class="hljs-comment">// some data there</span>
}
</code></pre>
<p>and off it goes and automates a lot of steps. Creates a Gmail workspace account. Creates an AWS IAM role, and assigns basic permission, sends invites for Slack, adds to mailing lists, alarm lists, etc. And in the case the member leaves the company, you just delete that patch of code, and all those items are revoked and deleted. So you didn’t forget to revoke that ssh keypair permission on that one instance for internal tools that could cost you.</p>
<p>In case you didn’t notice, I know it’s so hidden in the fine print. I’m a bit in love with it. I manage lot’s of my stuff with Terraform. For fun and practice as well. GitHub repositories, organizations, some account items, etc.</p>
<p>Summed up.</p>
<p>Automate as much as you can, all the boring tasks, all the verifications. Be strict with yourself (but make permission for emergency necessary flexibility of course). Make the CI/CD workflow. <strong>Let it be your honest friend</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Discipline within Software Engineering]]></title><description><![CDATA[When one of the people I look up to, Jocko Willink, was asked the question, what is the definition of discipline, he had a beautiful answer. He answered: “Doing what you should do.”. Great podcast episode with Lex.
Beautiful, harsh truth.
At first lo...]]></description><link>https://gitpub.xyz/discipline-within-software-engineering</link><guid isPermaLink="true">https://gitpub.xyz/discipline-within-software-engineering</guid><category><![CDATA[Testing]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[discipline]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Fri, 29 Mar 2024 14:26:51 GMT</pubDate><content:encoded><![CDATA[<p>When one of the people I look up to, <a target="_blank" href="https://twitter.com/jockowillink">Jocko Willink</a>, was asked the question, what is the definition of discipline, he had a beautiful answer. He answered: “<em>Doing what you should do.</em>”. <em>Great</em> <a target="_blank" href="https://www.youtube.com/watch?v=n2RcVEftY48"><em>podcast episode</em></a> <em>with Lex.</em></p>
<p>Beautiful, harsh truth.</p>
<p>At first look, it doesn’t seem like something special, but if you think about it, you understand how true it is and how often we fail it.</p>
<p>This definition applies to all aspects of life, from eating healthy, exercising, reading, and <strong>developing software</strong>.</p>
<p>Discipline is a habit. If we nurture it, it will come easy to us. If we don’t, we won’t do what we <em>should</em> do.</p>
<h2 id="heading-discipline-in-software-engineering">Discipline in Software Engineering</h2>
<p>To succeed as an individual, as a team and as a company we have to nurture it. And when motivation fails us, we have to rely on discipline. Otherwise, quite quickly we can find ourselves in trouble. Usually in form of technical dept.</p>
<p>It's hard, it's annoying and painful. But, it can be equally and more rewarding.</p>
<p>What does that mean for us Software Engineers? When you are tempted to take that shortcut to make it happen fast, don’t take it. When you start telling yourself and Tuesday 13:00 that you should have deployed these changes yesterday, don’t take the shortcut. Usually, it’s just an hour or two maximum of an investment. All those: “The release will be soon”, “I’m late”, “Oh look at the amount of code, I can’t write tests for that”, etc. are lies! At that point, our brain is just lying to us, trying to trick us to take the shortcut!</p>
<p>What do we get from that? Technical debt. What does that mean? Because we were too lazy to spend one more hour cleaning up or doing it right, over a period of time there will be a compound effect of those decisions. Then we will start feeling slow, not contributing properly or just plain unhappy. As one of the speakers, I listened to would put it:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*8hxfRk3hx-EZM1S26Q1XuA.jpeg" alt /></p>
<h2 id="heading-write-those-tests">Write those tests!</h2>
<p>You know that feeling when you have some code and you really feel like not testing it?</p>
<p>That is exactly when you should write them. Go for a walk, go for a coffee and relax, and come back and ace it! Why? Because you before all, but also your colleagues will be very grateful for it. You will find logic, design flaws and bugs. Above else, you are going to be very proud of yourself! It will help you infinitely when refactoring comes.</p>
<h2 id="heading-forming-discipline-for-the-non-obligatory-things">Forming discipline for the non-obligatory things</h2>
<p>There is another form of discipline you can nurture. You know that moment when you browse through code, and you spot a small segment of code that is, well, bad? It could be something even you wrote a year ago. It could be an outdated team convention. An ugly for-loop I guess? Instead of just skipping it, stop and dedicate 5–10 minutes for some quick safe refactorings. Rename that variable. Rename that method. Extract that if statement. Inline that method.</p>
<p><em>A safe refactor is usually something we can completely rely on our IDE to do. For example, renaming a variable or a method. The IDE will take care of it without you going around clicking ctrl+c ctrl+v.</em></p>
<p>In the same way, you have a compounding effect with bad decisions, you will have one with good ones. If each member of the team does this (even if you start that's amazing), PR-by-PR your code will be cleaned up! And you know what comes into play here? Tests! If you wrote those tests and weren't lazy, you are going to want to kiss yourself here for having a safeguard for refactors.</p>
<hr />
<p>Everything is a habit. Bad decisions, good decisions. We are defined by the small actions we take each day, they all sum up in the end and reward us.</p>
]]></content:encoded></item><item><title><![CDATA[Getting faster with testing]]></title><description><![CDATA[Small intro
Perfectly skippable
I know that this title sounds a bit contradicting when you are new or generally not used to writing your own tests. In certain moments, it is, so you are partially right.
Personally, I as well experienced the path from...]]></description><link>https://gitpub.xyz/getting-faster-with-testing</link><guid isPermaLink="true">https://gitpub.xyz/getting-faster-with-testing</guid><category><![CDATA[Go Language]]></category><category><![CDATA[unit testing]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Pavle Prica]]></dc:creator><pubDate>Fri, 29 Mar 2024 14:20:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711721953081/3c49239a-9461-4499-a7e9-e81f57f6ffa9.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-small-intro">Small intro</h2>
<p><em>Perfectly skippable</em></p>
<p>I know that this title sounds a bit contradicting when you are new or generally not used to writing your own tests. In certain moments, it is, so you are partially right.</p>
<p>Personally, I as well experienced the path from not understanding the difference between a unit or an integration test (really understanding it) to getting a bit TDD addicted. I know I know, sounds like I’m intelligent as a chair, but when you work with frameworks such as Spring, it’s perhaps not that intuitive for a beginner.</p>
<p>To generally address the <em>“contradictions”</em> of the title, if you are bumping into testing it may seem like a waste of time, extra unnecessary code to maintain or simply boring. The funny part is, you are going to do it anyway. And most likely in such a manner that you are going to spend more time doing it.</p>
<h2 id="heading-how-are-you-actually-wasting-more-time-not-writing-tests">How are you actually wasting more time not writing tests</h2>
<p><em>I’m going to write my examples in Go since that is my main orientation for now, but I generally like to think it’s in the principles, not the tech stack. So it’s applicable to any environment as well.</em></p>
<p>Let’s say it’s another day at your job and you are writing some service code for your web backend. Your ticket requires you to add a simple method of adding two numbers, so your Excel-like web frontend can call the endpoint and get the result. I know, it’s quite a useless example, and I’m quite confident you won’t encounter it in your daily job.</p>
<p>Somewhere inside your service, you have:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> calc

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Add</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
 <span class="hljs-keyword">return</span> a + b + <span class="hljs-number">1</span>
}
</code></pre>
<p>This code is quite simple, and even a TDD fanatic would be courageous to push it to production directly. But let’s not treat it that way.</p>
<p>Now, you as a conscious developer prior to opening your PR and asking for a review want to test your code and see if it’s actually behaving as it should. What are you going to usually do? Fire up Postman, click on “New request”, fill up the URL, add the endpoint, required parameters, fire up the server and click “Send”. That does include specifying the “Content-Type” header and the JSON creation. Of course, you can also curl it, it’s a longer one:</p>
<pre><code class="lang-bash">curl --location --request POST <span class="hljs-string">'http://localhost:8080/calculations/addition'</span> \
--header <span class="hljs-string">'Content-Type: application/json'</span> \
--data-raw <span class="hljs-string">'{
    "a": 5,
    "b": 5
}'</span>
</code></pre>
<p>For some unknown reason, the response is:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"result"</span>: <span class="hljs-number">11</span>
}
</code></pre>
<p>Well, that’s off, let’s check the code. It seems that for some quite unknown reason, we added + 1 at the end of our function. Maybe it’s a copy+paste error, maybe just talking with a colleague and not looking at what I’m typing error, or maybe it was the GitHub copilot. Either way, it’s bad. We go quickly fix it, we go to Postman, click “Send” — phew it’s all good now.</p>
<p>This was indeed a simple process. But what if it had more variations? What if we have a bit of complex branching within our code? What if we have to pass several layers of code just to get to invoke this method, and it has to pass several layers back? We have to do a lot of work just to test the Add() function. Even in this scenario, we could have been faster.</p>
<p>The alternative would be to have:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> (
 <span class="hljs-string">"github.com/stretchr/testify/assert"</span>
 <span class="hljs-string">"testing"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestAdd</span><span class="hljs-params">(t *testing.T)</span></span> {
 actual := Add(<span class="hljs-number">5</span>, <span class="hljs-number">5</span>)
 assert.Equal(t, <span class="hljs-number">10</span>, actual)
}
</code></pre>
<p>Or if you want to make the test really good and fancy:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> calc

<span class="hljs-keyword">import</span> (
 <span class="hljs-string">"github.com/stretchr/testify/assert"</span>
 <span class="hljs-string">"testing"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestAdd</span><span class="hljs-params">(t *testing.T)</span></span> {
 tests := []<span class="hljs-keyword">struct</span> {
  name     <span class="hljs-keyword">string</span>
  a        <span class="hljs-keyword">int</span>
  b        <span class="hljs-keyword">int</span>
  expected <span class="hljs-keyword">int</span>
 }{
  {
   name:     <span class="hljs-string">"When 1 + 1 should be 2"</span>,
   a:        <span class="hljs-number">1</span>,
   b:        <span class="hljs-number">1</span>,
   expected: <span class="hljs-number">2</span>,
  },
  {
   name:     <span class="hljs-string">"When 2 + 2 should be 4"</span>,
   a:        <span class="hljs-number">2</span>,
   b:        <span class="hljs-number">2</span>,
   expected: <span class="hljs-number">4</span>,
  },
  {
   name:     <span class="hljs-string">"When 3 + 3 should be 6"</span>,
   a:        <span class="hljs-number">3</span>,
   b:        <span class="hljs-number">3</span>,
   expected: <span class="hljs-number">6</span>,
  },
 }

 <span class="hljs-keyword">for</span> _, test := <span class="hljs-keyword">range</span> tests {
  t.Run(test.name, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(t *testing.T)</span></span> {
   actual := Add(test.a, test.b)
   assert.Equal(t, test.expected, actual)
  })
 }
}
</code></pre>
<p>So, besides actually being faster, and not worrying about the surrounding code we added several other things to our code and us.</p>
<p>We added:</p>
<ol>
<li><p>self-confidence in our code</p>
</li>
<li><p>A code constraint — if we or someone adds the + 1 the tests will break and protect us</p>
</li>
<li><p>documentation of the method.</p>
</li>
</ol>
<p>The beauty of it it’s always there. You don’t have to bug around with Postman or other methods. You are gaining on two fronts, momentarily testing, but also expanding and guarding your code with those tests. If you are testing the endpoint itself, write an integration test that does an HTTP POST to your server and verifies the result. After a few times almost always you are going to be faster than the manual method and it’s easy to modify — and as mentioned before, it guards you.</p>
<h2 id="heading-confidence">Confidence</h2>
<p>One of the greatest benefits that I think gets you hooked up on TDD or testing in general, is the confidence it gives you when you push your code. For some items, you didn’t even start up your app and you have the confidence it works. It gives you fast verifications of your code and it gives you sort of written proof that it’s good. Other than that, I can’t even count the number of times I found my own bugs before pushing the code actually thanks to those tests. It could be small things, it could be you learning that you actually don’t understand either the requirement or the tools you are using within the code.</p>
<h2 id="heading-speed">Speed</h2>
<p>Testing is one of those items that gain speed over time. When you are new to it, the testing environment hasn’t been set up fully perhaps, or the culture doesn’t nurture it yet — it’s probably not the fastest thing around. It’s one of the investments you have to give and wait for to come back. I promise you it will come back. As you get more proficient with it and the team is starting to gain its culture, your development speed will increase dramatically. It might even get to you to the point of being faster than you originally were.</p>
<p>We also have to think about more than just the time we invest to write those tests. When you add the time and effort saved from discovering bugs early, not introducing new ones, and organising your code efficiently and well (in order to be able to test something good you have to define your classes/interfaces/objects well. Otherwise it’s not testable properly.), and the documentation you provide. The math is quite good. It’s also a really great learning mechanism for technology and tools.</p>
<h2 id="heading-code-constraint-and-guarding">Code constraint and guarding</h2>
<p>Each time you write a test you add another guard to your code. What do I mean by that? If you or someone else comes and modifies the code, there could be unintended consequences. You attempt to improve the code, but yet the test breaks. That can be a wonderful pointer that you made a mistake and have to watch out, otherwise you could end up breaking your production environment.</p>
<p>Refactoring is one of the most wonderful examples. One of the top priorities prior to heavy refactoring is to have tests in place. Otherwise, how are you going to know you didn’t break the code? It’s quite normal to want to come back to your old code, wanting to improve it. IDEs help a lot of course, but without tests and doing some deep refactors, you are risking breaking functioning code. Of course, it <strong>doesn’t</strong> have to mean that those tests are <strong>valid</strong> as well, but if you are in a good environment with a good team it’s abnormally helpful!</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*l2qEXyuaR_ePn9R3G0Vv3Q.png" alt /></p>
<h2 id="heading-documentation">Documentation</h2>
<p>One of the greatest benefits I could put forward is documenting your code with tests. When you look at a method or an interface/class/object you are trying to figure out what is it doing for and what is its purpose. Well, don’t the tests seem tempting to look at? If you scroll back to the <em>“fancy”</em> example you can see how it does that. From the behaviour naming of tests “When we get this it should do this” to simply looking at the code execution. When tests are written well, with behaviour descriptions they can provide wonderful documentation and insights into our code so when a new engineer comes, he/she can go through the tests and understand our code much, much faster.</p>
<p>I hope I managed to persuade you to at least give it a shot and see how it suits you. Remember to give it time and you have to be persistent. I would also recommend reading the “Test Driven Development: By Example” — by Kent Beck. Not to be forced to do TDD, just to get more insights into testing and what it brings you. In addition, it’s always cool to check out your testing framework in more detail. Every technology has it.</p>
<p>Also, be careful not to overdo it. It can be tempting but also lead to bad tests. For example mocking absolutely everything that in the end creates pointless tests, etc.</p>
<p>Have in mind that the example provided is a simple one. There is a good challenge in organising your code, providing good mocks and verifications. But it also brings lots of fun (and frustration (: ) with it!</p>
<p>Have a pleasant day!</p>
]]></content:encoded></item></channel></rss>