<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog - Inside Programium | Software Development, Product and Digital Transformation Insights</title><description>In our blog, we share up to date trends and best practices, to help you navigate the digital landscape, materialise your ideas, build your products, and grow your business. From MVP development to enterprise solutions.</description><link>https://programium.com/</link><item><title>The Scarcity of Engineering Craftsmanship</title><link>https://programium.com/blog/the-scarcity-of-engineering-craftsmanship/</link><guid isPermaLink="true">https://programium.com/blog/the-scarcity-of-engineering-craftsmanship/</guid><description>Engineering craftsmanship is getting scarce. Code got faster to produce, but judgment only forms through effort. My talk on it, one year later.</description><pubDate>Sat, 03 Oct 2026 18:51:07 GMT</pubDate><content:encoded>&lt;p&gt;To me, engineering craftsmanship is the care that goes into deciding what to build and owning every line of the result. The current market is trying to prove that AI made code cheap to produce. Judgment and the risk of accountability still cost what they always did, because judgment only forms when you put real effort into creating. Skip the effort, and the craft gets scarce.&lt;/p&gt;&lt;p&gt;I&apos;ve been trying to find the time to put my thoughts on engineering craftsmanship into a post: what I believe it really is, and what it means to me.&lt;/p&gt;&lt;p&gt;Last October I gave a talk with the same title at &lt;a href=&quot;https://www.meetup.com/patras-tech-talk/events/311546772/&quot;&gt;Patras Tech Talk&lt;/a&gt; (&lt;a href=&quot;https://www.slideshare.net/slideshow/the-scarcity-of-engineering-craftsmanship/283900764&quot;&gt;slides&lt;/a&gt;). This post picks up where the talk left off, one year later.&lt;/p&gt;&lt;p&gt;I am old enough to remember how software engineers treated software before the mass adoption of Large Language Models (LLMs). It was a period when people were truly intrigued by new ideas, and the limits of hardware pushed them to find creative ways to move technology forward without compromising quality.&lt;/p&gt;&lt;p&gt;It was a time when smart, passionate and dedicated engineers were necessary for a product to truly succeed.&lt;/p&gt;&lt;p&gt;They invented new frameworks, new paradigms and new languages. They spent countless hours, across many different mediums, discussing and co-authoring Request for Comments (RFC) documents, the specs that laid the foundation of what we call technology today.&lt;/p&gt;&lt;p&gt;From small companies to big ones, many individuals, scattered across every level of their organizations, shared one common goal: to design and deliver efficient, well-crafted software they could be proud of, software that either improved people&apos;s lives or inspired other engineers to grow their craft.&lt;/p&gt;&lt;p&gt;But today, that time is long gone.&lt;/p&gt;&lt;h2 id=&quot;generative-chaos&quot;&gt;Generative chaos&lt;/h2&gt;&lt;p&gt;AI has been adopted explosively across many markets. I don&apos;t mean traditional artificial intelligence, but the huge demand for, and supply of, LLMs and LLM wrappers. As a result, we live in a time where theories like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_Internet_theory&quot;&gt;dead internet theory&lt;/a&gt; are becoming more and more plausible.&lt;/p&gt;&lt;p&gt;Most content is now either generated or augmented by AI. People rely heavily on LLM tools to automate their work, to do things they couldn&apos;t do before, or to &quot;improve&quot; the quality of their work.&lt;/p&gt;&lt;p&gt;Companies found new metrics to track, mostly vanity ones like tokens used and lines of code (produced by AI, this time). That pressure has forced employees at every level to rely on AI to some extent. It is now hard to tell what is generated and what isn&apos;t, and that has changed how people interact with each other.&lt;/p&gt;&lt;h2 id=&quot;the-vibe-era-and-the-dunning-kruger-effect&quot;&gt;The vibe era and the Dunning-Kruger effect&lt;/h2&gt;&lt;p&gt;In the talk I called this the vibe era. Low-code, no-code and now AI-code dropped the barrier of entry to writing code to almost nothing. We can now produce a lot of code really fast, often with limited understanding of what it does, and the push for speed has never been higher.&lt;/p&gt;&lt;p&gt;We got lazy. We always wanted to be lazy, and LLMs looked like a way out of hard work. Or maybe they are a way to amplify our &lt;a href=&quot;https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect&quot;&gt;Dunning-Kruger effect&lt;/a&gt;, the bias where people with limited skill in an area overestimate their ability in it. A tool that answers every question with confidence makes it very easy to feel competent without being competent.&lt;/p&gt;&lt;h2 id=&quot;pushing-the-responsibility-to-the-recipient&quot;&gt;Pushing the responsibility to the recipient&lt;/h2&gt;&lt;p&gt;With so much of our work shifted to LLMs, a hard battle starts: reviewing the work.&lt;/p&gt;&lt;p&gt;In the past, writing code took time. There was a ceiling on how much code one developer could write in a day. Writing several variations of an implementation just to decide which one worked best was expensive.&lt;/p&gt;&lt;p&gt;So people spent more time thinking, planning and designing their idea on paper. By the time they started implementing, the result was usually good, because so much of the thinking had happened early. They also knew their implementation details well, because they had designed them.&lt;/p&gt;&lt;p&gt;But the moment the effort needed to produce quick variations dropped, surprisingly, so did the thinking. People spent more time prompting for more variations and delegated every part of their work they could. They refactored heavily, iterated aggressively and kept generating until something looked like it worked.&lt;/p&gt;&lt;p&gt;The thinking moved to whoever has to review the result. A pull request that took minutes to generate can take far longer to review properly, and the reviewer now carries the responsibility the author skipped.&lt;/p&gt;&lt;h2 id=&quot;the-culture-decay&quot;&gt;The culture decay&lt;/h2&gt;&lt;p&gt;The damage reaches past the code. We are slowly but steadily losing mentorship, architecture and intent: the senior engineer explaining why, the design that holds a system together, the reason behind each decision. AI is taking away our effort, and effort is where most of that was learned.&lt;/p&gt;&lt;p&gt;AI also amplifies chaos built on unstable foundations. A model will build on top of a bad design as readily as on a good one, and much faster than any team could. Craftsmanship gets replaced by convenience.&lt;/p&gt;&lt;h2 id=&quot;one-year-later&quot;&gt;One year later&lt;/h2&gt;&lt;p&gt;Since I gave that talk, LLMs have improved quite a bit. In the same year, software engineers have grown huge dependencies on them, to the point where many are unable to do their own work well without them. The effort moved to the model, and the skill followed it.&lt;/p&gt;&lt;h2 id=&quot;i-watched-it-happen-in-my-own-work&quot;&gt;I watched it happen in my own work&lt;/h2&gt;&lt;p&gt;When I first tried to integrate AI into my own workflow, I watched the quality of my own work drop, and it dropped together with the effort I was putting in. Less effort to produce the work meant less thinking about the work, and the result showed it.&lt;/p&gt;&lt;p&gt;That convinced me the problem was what I had stopped doing.&lt;/p&gt;&lt;h2 id=&quot;judgment-is-earned-by-effort&quot;&gt;Judgment is earned by effort&lt;/h2&gt;&lt;p&gt;Judgment only shows up when you put enough effort into creating something. When the effort is reduced, judgment is allowed to be poor, and nothing in the process stops it.&lt;/p&gt;&lt;p&gt;That is why I think craftsmanship is becoming scarce. Producing code got faster. Whether it got cheaper is yet to be proven, except maybe in the short term. Knowing whether the code is right still costs effort, the same effort AI makes easy to skip. The habits we rely on to &lt;a href=&quot;https://programium.com/blog/writing-maintainable-code-for-fast-moving-projects-our-approach/&quot;&gt;keep code maintainable on fast-moving projects&lt;/a&gt; depend on that effort too.&lt;/p&gt;&lt;h2 id=&quot;how-we-work-now&quot;&gt;How we work now&lt;/h2&gt;&lt;p&gt;None of this means we shouldn&apos;t use AI. We use it every day at Programium, on our own code and on the &lt;a href=&quot;https://programium.com/services/custom-software-development/&quot;&gt;custom software&lt;/a&gt; and &lt;a href=&quot;https://programium.com/services/ai-development/&quot;&gt;AI features&lt;/a&gt; we build for clients. What changed is where the thinking happens:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We think the idea through on paper or in a doc before anyone writes a prompt.&lt;/li&gt;&lt;li&gt;Nothing ships unless we can explain how and why it works.&lt;/li&gt;&lt;li&gt;Tests define what correct means, whoever or whatever wrote the code. More on that in &lt;a href=&quot;https://programium.com/blog/automated-testing-as-a-first-class-citizen/&quot;&gt;automated testing as a first-class citizen&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Core logic, and anything on unfamiliar ground, gets written by hand on purpose, so the skill stays sharp.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;As many others have said before me, the awesome part of using tools like LLMs is that they reduce the effort you spend on things that don&apos;t matter in your role: the things you shouldn&apos;t be trying to be the best at, not the ones you should. Use them to become better, not worse.&lt;/p&gt;&lt;h2 id=&quot;the-call-to-craft&quot;&gt;The call to craft&lt;/h2&gt;&lt;p&gt;This is how I closed the talk:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Don&apos;t be lazy. Take ownership.&lt;/li&gt;&lt;li&gt;Keep writing software.&lt;/li&gt;&lt;li&gt;Keep trying, failing, and trying again.&lt;/li&gt;&lt;li&gt;Take pride in your work.&lt;/li&gt;&lt;li&gt;All effort, no matter how small, moves you forward.&lt;/li&gt;&lt;li&gt;AI might look convenient, but it&apos;s far from perfect.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;With discipline comes experience. With experience comes clarity. With clarity comes quality. With quality comes pride. And with all of the above comes craftsmanship.&lt;/p&gt;</content:encoded><author>Vasilis Christopoulos</author></item><item><title>Building for Growth: A Guide to Application Scalability and Performance</title><link>https://programium.com/blog/building-for-growth-a-guide-to-application-scalability-and-performance/</link><guid isPermaLink="true">https://programium.com/blog/building-for-growth-a-guide-to-application-scalability-and-performance/</guid><description>Application scalability starts with measurement. How we profile, load test and monitor before adding servers, and which fix to pick for each bottleneck.</description><pubDate>Wed, 06 Aug 2025 08:00:04 GMT</pubDate><content:encoded>&lt;p&gt;Application scalability starts with measuring the application, and adding servers comes after. Profile it, load test it until it breaks, and find out what every dependency costs you. Then watch latency, traffic, errors and saturation in production, and fix the bottleneck you can see. On Compot, a sub-250 ms p95 at launch was a target we set and measured against.&lt;/p&gt;&lt;p&gt;This guide walks through how we do that, in the order we do it.&lt;/p&gt;&lt;h2 id=&quot;measure-before-you-scale&quot;&gt;Measure before you scale&lt;/h2&gt;&lt;p&gt;Effective scalability begins with a data-driven understanding of your application&apos;s operational needs. Accurately forecasting resource requirements is essential for preventing both over-provisioning, which incurs unnecessary costs, and under-provisioning, which risks system failure.&lt;/p&gt;&lt;p&gt;Adding servers is the most expensive way to find out where your application is slow. The cause is often a handful of operations doing far more work than they need to: a file processed inside the request, a query that scans a whole table, two threads fighting over one lock. Measuring first tells you which one you have and how much capacity you really need. It also stops you paying for capacity you&apos;ll never use, which is the quieter way to get scaling wrong.&lt;/p&gt;&lt;h3 id=&quot;profile-the-application&quot;&gt;Profile the application&lt;/h3&gt;&lt;p&gt;Start with the profiler for your stack: JProfiler or the IntelliJ profiler for Java, cProfile for Python, pprof for Go. Run the application and walk through every user flow while it records. Upload and download files, trigger the heavy processing, submit the forms.&lt;/p&gt;&lt;p&gt;You&apos;re looking for two things. The first is where time and CPU go, which tells you where optimisation will pay off: a thread race, a slow query, a file pipeline that needs re-engineering. The second is memory that gets allocated and never released. A leak shows up as memory that keeps climbing the longer you use the application, and it&apos;s far cheaper to find on a laptop than in production.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;https://blog.programium.com/content/images/2025/08/intellij-profiler.png&quot; class=&quot;kg-image&quot; alt=&quot;IntelliJ IDEA profiler showing a memory dump of a Java application&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; srcset=&quot;https://blog.programium.com/content/images/size/w600/2025/08/intellij-profiler.png 600w, https://blog.programium.com/content/images/size/w1000/2025/08/intellij-profiler.png 1000w, https://blog.programium.com/content/images/2025/08/intellij-profiler.png 1500w&quot; sizes=&quot;(min-width: 720px) 720px&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;A memory dump in the IntelliJ profiler&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id=&quot;load-test-to-find-the-breaking-point&quot;&gt;Load test to find the breaking point&lt;/h3&gt;&lt;p&gt;Profiling covers one user at a time, so the next step is a load test. We use&amp;nbsp;&lt;a href=&quot;https://k6.io/&quot;&gt;k6&lt;/a&gt;;&amp;nbsp;&lt;a href=&quot;https://jmeter.apache.org/&quot;&gt;Apache JMeter&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://gatling.io/&quot;&gt;Gatling&lt;/a&gt;&amp;nbsp;do the same job. Raise the load step by step and record two numbers: the requests per second a single instance handles comfortably, and the point where latency or errors start to climb. Those two numbers are your baseline, and every scaling decision afterwards gets measured against them.&lt;/p&gt;&lt;p&gt;Most of these tools can record a session in the browser and turn it into a replayable script. Record the real user flows once, then edit the script or replay it as often as you need.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;https://blog.programium.com/content/images/2025/08/111346520-32b64100-8676-11eb-9b35-df32ef1982b1.png&quot; class=&quot;kg-image&quot; alt=&quot;k6 dashboard indicating the monitored load testing of a system&quot; loading=&quot;lazy&quot; width=&quot;1136&quot; height=&quot;841&quot; srcset=&quot;https://blog.programium.com/content/images/size/w600/2025/08/111346520-32b64100-8676-11eb-9b35-df32ef1982b1.png 600w, https://blog.programium.com/content/images/size/w1000/2025/08/111346520-32b64100-8676-11eb-9b35-df32ef1982b1.png 1000w, https://blog.programium.com/content/images/2025/08/111346520-32b64100-8676-11eb-9b35-df32ef1982b1.png 1136w&quot; sizes=&quot;(min-width: 720px) 720px&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;load testing report using the tool k6&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 id=&quot;map-your-dependencies&quot;&gt;Map your dependencies&lt;/h3&gt;&lt;p&gt;Your application is only as fast as the slowest dependency on its critical path: the database, the cache, a third-party API. If a payment provider takes 400 ms to answer, a 250 ms p95 is off the table for that flow, however fast your own code is. Map every dependency and measure what it costs per request. Do it before launch, while the architecture can still change.&lt;/p&gt;&lt;p&gt;Availability works the same way. A service that needs three dependencies to answer a request can&apos;t be more available than the three of them together, and&amp;nbsp;&lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/availability-and-beyond-improving-resilience/availability-with-dependencies.html&quot;&gt;AWS shows the maths&lt;/a&gt;. Check the SLAs of what you depend on before you promise one of your own.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;https://blog.programium.com/content/images/2025/08/azure-dependency-profiler.png&quot; class=&quot;kg-image&quot; alt=&quot;Azure Application Insights application map showing calls between services and their latency&quot; loading=&quot;lazy&quot; width=&quot;1093&quot; height=&quot;636&quot; srcset=&quot;https://blog.programium.com/content/images/size/w600/2025/08/azure-dependency-profiler.png 600w, https://blog.programium.com/content/images/size/w1000/2025/08/azure-dependency-profiler.png 1000w, https://blog.programium.com/content/images/2025/08/azure-dependency-profiler.png 1093w&quot; sizes=&quot;(min-width: 720px) 720px&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;A dependency map in Azure Application Insights&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id=&quot;monitor-the-four-golden-signals&quot;&gt;Monitor the four golden signals&lt;/h2&gt;&lt;p&gt;Google&apos;s SRE book names&amp;nbsp;&lt;a href=&quot;https://sre.google/sre-book/monitoring-distributed-systems/&quot;&gt;four golden signals&lt;/a&gt;&amp;nbsp;worth watching on every user-facing service, and we build our dashboards around them:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Latency: how long a request takes. Watch p95 and p99 as well as the average, because the average hides the slow requests, and those are the ones users notice under load.&lt;/li&gt;&lt;li&gt;Traffic: how much demand reaches the system, usually in requests per second.&lt;/li&gt;&lt;li&gt;Errors: the share of requests that fail. A sudden rise is usually the first sign of a fault.&lt;/li&gt;&lt;li&gt;Saturation: how close CPU, memory and disk I/O are to their limits. High saturation means a service is running out of headroom.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We use Axiom for metrics and the dashboards. Putting all four signals for every service on one screen is what makes patterns visible. A drop in requests per second next to a spike in CPU, for example, usually points to a blocking operation.&lt;/p&gt;&lt;h2 id=&quot;trace-requests-end-to-end&quot;&gt;Trace requests end to end&lt;/h2&gt;&lt;p&gt;Metrics tell you something is slow. Tracing tells you where. One request can pass through a frontend, an API, two internal services and a database, and the delay can sit in any of them. Distributed tracing follows the request through each hop and shows how long it spent in each one.&lt;/p&gt;&lt;p&gt;For open-source tracing, look at&amp;nbsp;&lt;a href=&quot;https://www.jaegertracing.io/&quot;&gt;Jaeger&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://zipkin.io/&quot;&gt;Zipkin&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://grafana.com/docs/tempo/latest/&quot;&gt;Grafana Tempo&lt;/a&gt;. Commercial APM platforms such as&amp;nbsp;&lt;a href=&quot;https://www.datadoghq.com/&quot;&gt;Datadog&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://newrelic.com/&quot;&gt;New Relic&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://sentry.io/welcome/&quot;&gt;Sentry&lt;/a&gt;&amp;nbsp;bundle tracing with metrics and logs.&lt;/p&gt;&lt;h2 id=&quot;how-we-troubleshoot-a-traffic-surge&quot;&gt;How we troubleshoot a traffic surge&lt;/h2&gt;&lt;p&gt;When traffic spikes, the order of the checks matters more than speed. We go through the same steps every time:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Dashboards.&lt;/strong&gt;&amp;nbsp;The four golden signals show what changed and when: more traffic, slower responses, more errors, or a resource at its limit.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Logs.&lt;/strong&gt;&amp;nbsp;Query the central log store for errors and warnings around the moment it started, and look for a pattern: one endpoint, one client, one service. Ours go to Axiom.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Recent deployments.&lt;/strong&gt;&amp;nbsp;A fresh code or configuration change is one of the most common causes of sudden instability. Check what shipped in the hours before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The bottleneck.&lt;/strong&gt;&amp;nbsp;Traces and metrics narrow it to one component, and its profile tells you what kind of problem you have:&lt;ul&gt;&lt;li&gt;CPU-bound: inefficient code, or not enough compute.&lt;/li&gt;&lt;li&gt;Memory-bound: a leak, or instances that are too small.&lt;/li&gt;&lt;li&gt;I/O-bound: database contention or slow disks. Query optimisation or a missing index usually fixes it before new hardware does.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Not every surge is good news. &lt;/p&gt;&lt;p&gt;On a large platform where I was technical lead, a sudden spike in traffic turned out to be a DDoS attack on our customer. We traced the attack to its origins and blocked them at the firewall. The attackers rotated to new IP addresses, so blocking them one at a time stopped working. We moved to rate limiting per origin instead: every source got a request budget, and each new address the attackers rotated in hit the same ceiling as the last one. Blocking dealt with the first wave. The rate limit is what held when the attack changed shape, and it costs very little to set up before you need it.&lt;/p&gt;&lt;h2 id=&quot;which-fix-for-which-bottleneck&quot;&gt;Which fix for which bottleneck&lt;/h2&gt;&lt;p&gt;Once you know where the bottleneck is, the fix is usually one of a few well-known patterns. The useful question is what each one costs you.&lt;/p&gt;
&lt;!--kg-card-begin: html--&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th scope=&quot;col&quot;&gt;Symptom&lt;/th&gt;&lt;th scope=&quot;col&quot;&gt;Fix&lt;/th&gt;&lt;th scope=&quot;col&quot;&gt;Trade-off&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;Servers busy delivering images, CSS and JavaScript&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;A CDN serves static assets from edge locations close to the user&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Cache invalidation becomes part of every release&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;A predictable peak, such as a planned campaign&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;Manual scaling: more instances (horizontal) or a bigger machine (vertical)&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Someone has to watch and act, but costs stay predictable&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;Unpredictable load&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;Autoscaling on CPU or request count, with Kubernetes or AWS Auto Scaling Groups&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Without caps, costs scale with traffic, attacks included. Set limits before you turn it on&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;One instance overloaded while others sit idle&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;A load balancer spreads requests across instances&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;One more component to configure and monitor&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;The same expensive reads, over and over&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;A cache such as Redis or Memcached&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Stale data, and an invalidation strategy to design&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;One client, or one attacker, flooding an API&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;Rate limiting per client or origin&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Legitimate bursts can get throttled, so the limits need tuning&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;A failing downstream service dragging its callers down&lt;/th&gt;&lt;td data-label=&quot;Fix&quot;&gt;A circuit breaker stops calls until the service recovers&lt;/td&gt;&lt;td data-label=&quot;Trade-off&quot;&gt;Callers need a fallback for when the circuit is open&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;!--kg-card-end: html--&gt;
&lt;h2 id=&quot;scale-for-the-load-you-can-forecast&quot;&gt;Scale for the load you can forecast&lt;/h2&gt;&lt;p&gt;Building for traffic you may never get has a daily cost: more moving parts, slower changes, and a system that is harder to hire for. We design for the load we can forecast, leave seams where growth would go, and measure before we tune. That&apos;s how&amp;nbsp;&lt;a href=&quot;https://programium.com/case-studies/compot-fi/&quot;&gt;Compot&lt;/a&gt;&amp;nbsp;launched with a sub-250 ms p95, a target we set up front and measured against.&lt;/p&gt;&lt;p&gt;Scalability also depends on the codebase. The habits that keep code&amp;nbsp;&lt;a href=&quot;https://programium.com/blog/writing-maintainable-code-for-fast-moving-projects-our-approach/&quot;&gt;maintainable on fast-moving projects&lt;/a&gt;&amp;nbsp;are the same ones that let you change a system safely when the load changes. If you&apos;re planning for growth, see how we approach&amp;nbsp;&lt;a href=&quot;https://programium.com/services/custom-software-development/&quot;&gt;custom software development&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</content:encoded><author>Vasilis Christopoulos</author></item><item><title>Automated Testing as a First-Class Citizen</title><link>https://programium.com/blog/automated-testing-as-a-first-class-citizen/</link><guid isPermaLink="true">https://programium.com/blog/automated-testing-as-a-first-class-citizen/</guid><description>Skipping tests feels faster until the first regression ships. Why automated testing sits inside every build we ship, and what it buys a team that moves fast.

</description><pubDate>Thu, 17 Jul 2025 17:52:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;&lt;p&gt;In the race to deliver software faster, it&apos;s tempting to skip steps and tell yourself you&apos;ll do them later, in some milestone further down the roadmap. Testing is often one of them. Skipping tests does save time in the short term, but testing is the foundation of reliable, maintainable and scalable systems.&lt;/p&gt;&lt;p&gt;At &lt;strong&gt;Programium&lt;/strong&gt;, automated testing is a first-class citizen. It&apos;s part of everything we build, from small APIs to enterprise platforms.&lt;/p&gt;&lt;p&gt;In this post, we&apos;ll share why testing gets that status and how it pays off for our clients.&lt;/p&gt;&lt;h2 id=&quot;building-confidence-at-speed&quot;&gt;&lt;strong&gt;Building Confidence at Speed&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Modern development moves fast. Features ship quickly, architectures evolve, and teams often work across time zones.&lt;/p&gt;&lt;p&gt;Without automated testing, every change introduces uncertainty:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&quot;Will this break something unexpected?&quot;&lt;/li&gt;&lt;li&gt;&quot;Is the integration still working?&quot;&lt;/li&gt;&lt;li&gt;&quot;Can we safely deploy to production?&quot;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Automated tests give us the confidence to say &lt;em&gt;yes&lt;/em&gt; to these questions, and allow us to deliver faster without compromising quality.&lt;/p&gt;&lt;h2 id=&quot;catching-problems-early-when-theyre-cheaper-to-fix&quot;&gt;&lt;strong&gt;Catching Problems Early (When They&apos;re Cheaper to Fix)&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Bugs caught in production are &lt;strong&gt;costly. &lt;/strong&gt;Not just in time, but in trust.&lt;/p&gt;&lt;p&gt;Automated testing helps catch issues early in the development lifecycle:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Unit tests&lt;/strong&gt; ensure individual components behave as expected.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Integration tests&lt;/strong&gt; confirm systems work together properly.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;End-to-end tests&lt;/strong&gt; validate entire workflows from a user perspective.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;By investing upfront, we prevent problems from becoming expensive disasters later.&lt;/p&gt;&lt;h2 id=&quot;supporting-continuous-delivery-and-agile-teams&quot;&gt;&lt;strong&gt;Supporting Continuous Delivery and Agile Teams&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Our clients expect agility. Whether we’re building a custom application or expanding an existing one, continuous delivery allows us to iterate quickly.&lt;/p&gt;&lt;p&gt;Automated tests are the backbone of this process:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Every commit is tested automatically.&lt;/li&gt;&lt;li&gt;Deployments become routine, not risky events.&lt;/li&gt;&lt;li&gt;Engineers focus on solving business problems, not firefighting regressions.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This leads to faster feedback loops and happier clients.&lt;/p&gt;&lt;h2 id=&quot;enabling-cleaner-code-and-smarter-design&quot;&gt;&lt;strong&gt;Enabling Cleaner Code and Smarter Design&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;There’s a hidden benefit to automated testing: &lt;strong&gt;it encourages better code architecture.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;When you write testable code, you naturally:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Keep functions small and focused.&lt;/li&gt;&lt;li&gt;Use dependency injection for flexibility.&lt;/li&gt;&lt;li&gt;Avoid tightly coupled components.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The result is a system that is easier to understand, extend and maintain, which is what a long-lived product needs. Testing is one of several habits behind that; the rest are in&amp;nbsp;&lt;a href=&quot;https://programium.com/blog/writing-maintainable-code-for-fast-moving-projects-our-approach/&quot; rel=&quot;noreferrer&quot;&gt;writing maintainable code for fast-moving projects&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;keeping-coverage-high-with-ai-coding-agents&quot;&gt;Keeping Coverage High with AI Coding Agents&lt;/h2&gt;&lt;p&gt;AI coding agents are useful for testing once a codebase has structure. Before that, they mostly produce noise.&lt;/p&gt;&lt;p&gt;We learned that the hard way. Our first AI-written tests mostly mocked files they touched, so all they proved was that the mocks worked. Every file came out in a different style. Coverage went up, and our confidence stayed where it was.&lt;/p&gt;&lt;p&gt;The fix was in the codebase. Three things make AI-written tests worth keeping:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Interfaces and API contracts are typed, so integration tests run against the real contract instead of a mock of it.&lt;/li&gt;&lt;li&gt;Every module is laid out the same way, so one good test is a template for the next.&lt;/li&gt;&lt;li&gt;Engineers write the first tests in a module by hand, and the agent follows their shape.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The split of work stays fixed. An engineer decides what correct means by naming the cases and behaviours a test must cover. The agent writes the test bodies, backfills coverage on code that has none, and suggests edge cases we missed. Every test gets reviewed before it merges, like any other code.&lt;/p&gt;&lt;p&gt;Unit and integration tests carry the breadth: the combinations, the edge cases, the error paths. That keeps our end-to-end suite thin, a few Playwright flows over the user journeys that matter most, written by the agent under the same rules.&lt;/p&gt;&lt;p&gt;On one of our current projects, this setup keeps line coverage above 86% with little overhead, because the structure does most of the work before the agent starts. Tests still define what correct means, whoever or whatever wrote the code. We wrote more about where the thinking stays in&amp;nbsp;&lt;a href=&quot;https://programium.com/blog/the-scarcity-of-engineering-craftsmanship/&quot; rel=&quot;noreferrer&quot;&gt;the scarcity of engineering craftsmanship&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;kg-card kg-cta-card kg-cta-bg-grey kg-cta-minimal    &quot; data-layout=&quot;minimal&quot;&gt;
            
                &lt;div class=&quot;kg-cta-sponsor-label-wrapper&quot;&gt;
                    &lt;div class=&quot;kg-cta-sponsor-label&quot;&gt;
                        &lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Let&apos;s build something reliable together&lt;/span&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            
            &lt;div class=&quot;kg-cta-content&quot;&gt;
                
                
                    &lt;div class=&quot;kg-cta-content-inner&quot;&gt;
                    
                        &lt;div class=&quot;kg-cta-text&quot;&gt;
                            &lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;If you’re thinking about scaling your platform, &lt;/span&gt;&lt;a href=&quot;https://programium.com/services/custom-software-development/&quot; rel=&quot;noreferrer&quot; class=&quot;cta-link-color&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;modernizing legacy systems&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;, or ensuring your next release goes smoothly, let’s talk!&lt;/span&gt;&lt;/p&gt;
                        &lt;/div&gt;
                    
                    
                        &lt;a href=&quot;mailto:contact@programium.com&quot; class=&quot;kg-cta-button &quot; style=&quot;background-color: #F0F0F0; color: #000000;&quot;&gt;
                            Mail us now
                        &lt;/a&gt;
                        
                    &lt;/div&gt;
                
            &lt;/div&gt;
        &lt;/div&gt;&lt;h2 id=&quot;protecting-long-term-product-health&quot;&gt;&lt;strong&gt;Protecting Long-Term Product Health&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Your software is a living system.&lt;/p&gt;&lt;p&gt;As features are added and team members change, tests become your safety net.&lt;/p&gt;&lt;p&gt;They act as living documentation, ensuring new engineers can make changes confidently, and that your platform can evolve without fear of breaking mission-critical functionality.&lt;/p&gt;&lt;h2 id=&quot;conclusion-quality-shouldnt-be-optional&quot;&gt;Conclusion: Quality Shouldn&apos;t Be Optional&lt;/h2&gt;&lt;p&gt;At &lt;strong&gt;Programium&lt;/strong&gt;, we believe &lt;strong&gt;quality is not an add-on, it’s built in.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Automated testing helps us deliver software that is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Faster to deploy&lt;/li&gt;&lt;li&gt;Safer to change&lt;/li&gt;&lt;li&gt;Easier to maintain&lt;/li&gt;&lt;li&gt;Trusted by our clients&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It’s how we uphold our commitment to engineering excellence, and why our clients trust us with their most important projects.&lt;/p&gt;</content:encoded><author>Vasilis Christopoulos</author></item><item><title>Flow at Your Fingertips: The Quiet Power of Muscle Memory in Software Development</title><link>https://programium.com/blog/flow-at-your-fingertips-the-quiet-power-of-muscle-memory-in-software-development/</link><guid isPermaLink="true">https://programium.com/blog/flow-at-your-fingertips-the-quiet-power-of-muscle-memory-in-software-development/</guid><description>I thought the newest tools made me fast. My hands said otherwise. What typing practice and keyboard-first workflows did for my flow, slow phase included.</description><pubDate>Tue, 06 May 2025 15:08:23 GMT</pubDate><content:encoded>&lt;p&gt;As software developers, we&apos;re often drawn to the flashiest tools, newest frameworks and the most performant languages. We convince ourselves that staying on the bleeding edge means staying ahead. I know I did. For a long time, I believed I was achieving maximum productivity simply because I was using the latest and greatest tools.&lt;br&gt;&lt;br&gt;Somewhere along the way, I began to notice something. My hands were flying all over the keyboard. My movements weren’t deliberate, they were chaotic. I&apos;d reach for the mouse, then back to the keyboard, then fumble through shortcuts I hadn&apos;t truly internalized or look endlessly through the context menus. When pressure mounted or fatigue set in, I’d start making the same small mistakes over and over again.&lt;br&gt;&lt;br&gt;That’s when it hit me: my workflow wasn&apos;t inefficient because of the tools I was using, it was inefficient because &lt;em&gt;I hadn’t trained my body to use them well&lt;/em&gt;.&lt;/p&gt;&lt;h2 id=&quot;muscle-memory-the-developer%E2%80%99s-silent-ally&quot;&gt;Muscle Memory: The Developer’s Silent Ally&lt;/h2&gt;&lt;p&gt;Managing cognitive load is a well known aspect in programming, keeping track of logic, naming things, understanding business rules. But there’s a hidden load most developers carry without realizing: the physical friction of how we interact with our tools.&lt;br&gt;&lt;br&gt;Muscle memory, the unconscious, trained motion of your fingers, is rarely discussed in developer circles, yet it plays a massive role in shaping how fluidly we work. Think of a pianist who has to glance at the keys every few notes. Or a gamer who can’t quite hit the right button under pressure. Their technical ability isn’t the issue, it’s their lack of &lt;em&gt;automaticity&lt;/em&gt;.&lt;br&gt;&lt;br&gt;When you have to think about how to navigate, open files, switch panes, or reach for the right key, your attention is no longer fully on the code. It’s split. And over a day, a week, or a career, that cost adds up.&lt;/p&gt;&lt;h2 id=&quot;typing-the-foundation-everyone-skips&quot;&gt;Typing: The Foundation Everyone Skips&lt;/h2&gt;&lt;p&gt;This all starts with typing, and typing properly.&lt;/p&gt;&lt;p&gt;It’s ironic that we spend our entire careers at the keyboard, yet most developers never formally learn how to type. Not just fast, but accurately. Ergonomically. Without looking.&lt;/p&gt;&lt;p&gt;It might seem like a small thing, but poor typing technique creates a subtle stream of friction: inconsistent rhythm, constant corrections, breaking flow to check key positions. Over time, these micro-delays interrupt not just speed, but thought.&lt;/p&gt;&lt;p&gt;Once I committed to retraining my typing, with deliberate repetition and patience, I noticed something shift. My fingers weren’t guessing anymore. They were moving &lt;em&gt;with&lt;/em&gt; my mind, not just after it.&lt;/p&gt;&lt;h2 id=&quot;keyboard-first-workflows-more-than-a-trend&quot;&gt;Keyboard-First Workflows: More Than a Trend&lt;/h2&gt;&lt;p&gt;There&apos;s a reason developers who master keyboard-centric tools like Vim, Tmux, or modal editors seem so fast. It’s not just that the tools are efficient (though they are). It’s that using them &lt;em&gt;well&lt;/em&gt; forces you to build habits.&lt;/p&gt;&lt;p&gt;Habits that rely on repetition. Habits that reward consistency. Habits that, over time, become muscle memory.&lt;/p&gt;&lt;p&gt;And here’s the truth: those habits are transferable. Whether you&apos;re in an IDE, a browser-based editor, or your terminal, if your hands know what to do without you thinking about it, you&apos;re not just faster, you&apos;re &lt;em&gt;calmer&lt;/em&gt;. You&apos;re not chasing the cursor or scanning the screen for buttons. You’re staying in the problem space.&lt;/p&gt;&lt;h2 id=&quot;the-slow-phase-is-the-important-phase&quot;&gt;The Slow Phase Is the Important Phase&lt;/h2&gt;&lt;p&gt;The difficult part of all this? You get slower before you get faster.&lt;/p&gt;&lt;p&gt;When I first started retraining how I typed, or forcing myself to stick to keyboard shortcuts and avoid the mouse, I felt like I was moving through molasses. I was less productive. I made more mistakes. I doubted the point of it all.&lt;/p&gt;&lt;p&gt;But that discomfort wasn’t failure, it was &lt;em&gt;unlearning&lt;/em&gt;. It was the messy transition from unconscious inefficiency to conscious, intentional action.&lt;/p&gt;&lt;p&gt;And like any physical skill, whether it&apos;s playing an instrument, doing martial arts, or learning to drive, there’s a breakthrough that only comes on the other side of consistent, sometimes frustrating repetition.&lt;/p&gt;&lt;h2 id=&quot;less-friction-more-flow&quot;&gt;Less Friction, More Flow&lt;/h2&gt;&lt;p&gt;At some point, the friction faded. I stopped thinking about my hands. Navigation became intuitive. My typing smoothed out. And that quiet mastery had ripple effects I didn’t anticipate.&lt;/p&gt;&lt;p&gt;I could stay in flow longer. I felt less tired at the end of the day. I made fewer typos, fewer wrong turns, and fewer decisions driven by interface fatigue.&lt;/p&gt;&lt;p&gt;The work didn’t get easier. I just got &lt;em&gt;less in my own way&lt;/em&gt;.&lt;/p&gt;&lt;h2 id=&quot;final-thought-mastery-is-physical-too&quot;&gt;Final Thought: Mastery Is Physical, Too&lt;/h2&gt;&lt;p&gt;There’s a quiet kind of power in mastering the physical side of development. It’s not glamorous. It won’t show up on a résumé. But it pays off in every session, every sprint, and every late-night debug session.&lt;/p&gt;&lt;blockquote&gt;So if you’ve ever found yourself in your favourite IDE, reaching for the mouse out of habit, making the same navigation mistakes, or watching your hands dance aimlessly across the keyboard, maybe it’s time to slow down.&lt;/blockquote&gt;&lt;p&gt;Not to do less. But to &lt;em&gt;do better&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Train your hands like you train your mind. The results will speak for themselves, without you even needing to think about them.&lt;/p&gt;</content:encoded><author>Artur Rozalski</author></item><item><title>Writing Maintainable Code for Fast-Moving Projects: Our Approach</title><link>https://programium.com/blog/writing-maintainable-code-for-fast-moving-projects-our-approach/</link><guid isPermaLink="true">https://programium.com/blog/writing-maintainable-code-for-fast-moving-projects-our-approach/</guid><description>&quot;Ship now, fix later&quot; rarely reaches the fixing. How we keep fast-moving projects maintainable, from designing for change to reviewing all the code we ship.</description><pubDate>Wed, 16 Apr 2025 16:02:48 GMT</pubDate><content:encoded>&lt;p&gt;In fast-moving projects, speed is everything.&lt;/p&gt;&lt;p&gt;Whether you&apos;re validating an MVP, scaling a successful product, or racing to meet market demands, the temptation is always there: &lt;strong&gt;&quot;Ship now, fix later.&quot;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;But later rarely comes. A common misconception in the software industry is that moving fast is doing everything in a rush.&lt;/p&gt;&lt;p&gt;At Programium, we believe that speed and maintainability aren&apos;t mutually exclusive. &lt;/p&gt;&lt;p&gt;In fact, they go hand-in-hand.&lt;/p&gt;&lt;p&gt;In this post, we’ll share how we balance delivery velocity with sustainable code quality, and why this balance is key to long-term success.&lt;/p&gt;&lt;h2 id=&quot;maintainability-as-a-design-principle&quot;&gt;&lt;strong&gt;Maintainability as a Design Principle&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Before we write a single line of code, we ask:&lt;/p&gt;&lt;blockquote&gt;&quot;How easy should it be to change this in six months?&quot;&lt;/blockquote&gt;&lt;p&gt;Maintainable code is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Easy to read and understand.&lt;/li&gt;&lt;li&gt;Predictable in behaviour.&lt;/li&gt;&lt;li&gt;Modular, so changes are localised.&lt;/li&gt;&lt;li&gt;Well-documented, with clear intent.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;We treat maintainability as an investment, not an afterthought.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Every decision from project structure to naming conventions is guided by this principle.&lt;/p&gt;&lt;h2 id=&quot;clean-code-matters&quot;&gt;&lt;strong&gt;Clean Code Matters&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Clean code might feel &quot;slower&quot; at first, but it’s actually the opposite over time.&lt;/p&gt;&lt;p&gt;Our practices include:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Descriptive naming&lt;/strong&gt;: so code reads like a story.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Small functions&lt;/strong&gt;: Each function does one thing well.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Consistent formatting&lt;/strong&gt;: Tools like Prettier and Checkstyle enforce clarity.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Eliminating dead code&lt;/strong&gt;: If it&apos;s not used, it’s gone.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;💡 &lt;em&gt;Tip:&lt;/em&gt; We treat our codebase like a garden: continuous small cleanups prevent wild overgrowth.&lt;/p&gt;&lt;h2 id=&quot;automated-testing-as-a-safety-net&quot;&gt;&lt;strong&gt;Automated Testing: as a Safety Net&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;We rarely compromise on &lt;a href=&quot;https://programium.com/blog/automated-testing-as-a-first-class-citizen/&quot; rel=&quot;noreferrer&quot;&gt;automated testing&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Why? Because tests give you the confidence to move fast without breaking things. Untested code moves the work to manual validation and manual regression testing, which costs the speed you skipped the tests to gain.&lt;/p&gt;&lt;p&gt;Our typical setup includes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Unit tests&lt;/strong&gt; for fast feedback.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Integration tests&lt;/strong&gt; for system behaviour.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;End-to-end tests&lt;/strong&gt; for critical user flows.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This layered approach means we catch issues early, when they’re cheap and easy to fix.&lt;/p&gt;&lt;blockquote&gt;&lt;em&gt;&quot;If tests are green you should be good to go, if they are not you better fix them first.&quot;&lt;/em&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;using-the-right-architecture&quot;&gt;Using The Right &lt;strong&gt;Architecture &lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Even&lt;/em&gt; in MVPs, we apply architecture thinking:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Domain-Driven Design&lt;/strong&gt; (where applicable) to reflect business logic cleanly.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Separation of concerns&lt;/strong&gt; to avoid tangled systems.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Architecture Decision Records (ADRs)&lt;/strong&gt; to document why decisions were made.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We don’t &quot;over-engineer&quot;, but we leave clear paths for future growth.&lt;/p&gt;&lt;p&gt;We keep the&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Second-system_effect&quot;&gt;second-system effect&lt;/a&gt;&amp;nbsp;in mind: the pull to load a new system with everything the last one left out. So we keep the design simple and make the decisions the project needs now, not the ones it might need someday.&lt;/p&gt;&lt;h2 id=&quot;all-code-is-reviewed&quot;&gt;&lt;strong&gt;All Code Is Reviewed&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;In fast-paced projects, code reviews can feel like bottlenecks.&lt;/p&gt;&lt;p&gt;We make them accelerators instead.&lt;/p&gt;&lt;p&gt;Our approach:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Mandatory peer reviews&lt;/strong&gt;, used to mentor each other, not only to gatekeep.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Focus on high-impact feedback&lt;/strong&gt; (readability, structure, logic).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Automated pull request decoration&lt;/strong&gt; that focuses on the basics (e.g. linting, test coverage, Sonar scans, vulnerability scans) so reviews focus on real improvements of the business logic and code quality.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This aims to keep our velocity high while maintaining quality.&lt;/p&gt;&lt;h2 id=&quot;conclusion-sustainable-speed-wins&quot;&gt;Conclusion: Sustainable Speed Wins&lt;/h2&gt;&lt;p&gt;Our experience taught us that fast growth doesn’t have to mean technical chaos.&lt;/p&gt;&lt;p&gt;&amp;nbsp;By embedding maintainability into our processes, from architecture decisions to daily coding habits, we help our clients scale confidently, knowing their software can evolve as fast as their business does.&lt;/p&gt;&lt;p&gt;If you&apos;re building fast and want to avoid growing pains later, see how we approach&amp;nbsp;&lt;a href=&quot;https://programium.com/services/custom-software-development/&quot; rel=&quot;noreferrer&quot;&gt;custom software development&lt;/a&gt;, or let&apos;s talk.&lt;/p&gt;</content:encoded><author>Vasilis Christopoulos</author></item><item><title>Building Software That Moves Businesses Forward</title><link>https://programium.com/blog/moving-forward/</link><guid isPermaLink="true">https://programium.com/blog/moving-forward/</guid><description>An introduction to the Programium engineering blog. Learn how we build custom software that solves real problems and scales with your ambitions.</description><pubDate>Mon, 07 Apr 2025 09:14:05 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to &lt;strong&gt;Inside Programium,&lt;/strong&gt; our space to share ideas, engineering stories, and lessons from the systems we build.&lt;/p&gt;&lt;p&gt;At Programium, we started with a simple belief: &lt;strong&gt;software should solve real problems, scale with your ambitions, and be built with care.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Over the years, we’ve seen how the right software choices can transform businesses. But too often, companies are stuck between off-the-shelf tools that don’t fit, or over-engineered solutions that create more problems than they solve. We built Programium to be a different kind of partner — one that delivers custom, pragmatic systems with a focus on real-world impact.&lt;/p&gt;&lt;p&gt;Our work spans:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Custom Software Development&lt;/strong&gt; — Frontend, backend, web apps, APIs, and developer tools.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Distributed Systems&lt;/strong&gt; — Cloud-native, scalable infrastructure for modern businesses.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Web3 Development&lt;/strong&gt; — Full-stack solutions for EVM-based platforms.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AI &amp;amp; Automation&lt;/strong&gt; — Smarter workflows and intelligent systems that unlock efficiency.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Through this blog, we’ll share:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How we design systems that scale&lt;/li&gt;&lt;li&gt;Insights from our engineering practices&lt;/li&gt;&lt;li&gt;Honest lessons from the field — what works, and what doesn’t&lt;/li&gt;&lt;li&gt;Explorations in Web3 and AI&lt;/li&gt;&lt;li&gt;And, of course, occasional experiments and things we’re just plain curious about.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you’re building something ambitious, we hope this space brings you ideas, clarity, and inspiration.&lt;/p&gt;&lt;p&gt;Thanks for reading — and welcome to Programium.&lt;/p&gt;</content:encoded><author>Vasilis Christopoulos</author></item></channel></rss>