<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mangabo Kolawole</title>
    <description>The latest articles on DEV Community by Mangabo Kolawole (@koladev).</description>
    <link>https://dev.to/koladev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F282902%2F5069e55c-cd15-40df-9b7d-11c1b1d10d4b.jpg</url>
      <title>DEV Community: Mangabo Kolawole</title>
      <link>https://dev.to/koladev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/koladev"/>
    <language>en</language>
    <item>
      <title>I Spent Months Building a Financial Reconciliation Engine That Processes 10 Million Records in Under Five Minutes</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sat, 18 Jul 2026 02:42:41 +0000</pubDate>
      <link>https://dev.to/koladev/i-spent-months-building-a-financial-reconciliation-engine-that-processes-10-million-records-in-20o4</link>
      <guid>https://dev.to/koladev/i-spent-months-building-a-financial-reconciliation-engine-that-processes-10-million-records-in-20o4</guid>
      <description>&lt;p&gt;A few months ago I decided to build a reusable engine to make financial reconciliation easier.  I had already done reconciliation work for companies in West Africa, closing out exports of around 100,000 transactions, and a lot of people in my network work in fintech. The one problem that keeps coming up in those conversations is reconciliation, and how painful it becomes once the data load grows.&lt;/p&gt;

&lt;p&gt;So my first move was not to write code. It was to look for a tool that already solved the problem. To my surprise, there was almost nothing usable. The tools I found were either too general, because &lt;strong&gt;data reconciliation&lt;/strong&gt; is a very broad problem, or they targeted finance but had not been maintained in years. Nothing was directed specifically at financial reconciliation and optimized for it. So I decided to take up the challenge. The problem was interesting on its own, and it was also a good way to deepen my knowledge of Go. The result is an open-source engine called Reconify, that can be used as a CLI, and you can find the repository &lt;a href="https://github.com/ReconifyHQ/reconify" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is where it landed. The current version reconciles 10 million records per side, 20 million in total, in &lt;strong&gt;95 seconds&lt;/strong&gt; on an eight-core Apple M1 Pro with 16 GB of RAM. It did not start there. The first design was fast on convenient files and fell apart on realistic ones, so the architecture had to change three times. The rest of this article is how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why reconciliation matters
&lt;/h2&gt;

&lt;p&gt;A payment, most of the time has to work out on two sides. Your own ledger says the customer paid, and the provider is supposed to send the money and report it back. Reconciliation is the job of proving that those two records describe the same event, and flagging every case where they do not fully agree.&lt;/p&gt;

&lt;p&gt;When they do not agree, real money is missing, a payment is double counted, or a settlement is stuck. So a finance team cannot close the books until the two sides are tied up.&lt;/p&gt;

&lt;p&gt;The mechanic is quite simple to state. One side is the left source, usually your internal ledger. The other is the right source, the provider or bank export. The engine pairs a left row with a right row on a shared key, normally a reference like &lt;code&gt;ORD-2026-84921&lt;/code&gt;, then classifies the pair:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Matched&lt;/strong&gt;: both sides agree on the reference and the amount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mismatched&lt;/strong&gt;: the reference matches but a field such as the amount does not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unmatched&lt;/strong&gt;: a row sits on one side with no counterpart on the other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctm13mftgkl819ib508v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctm13mftgkl819ib508v.png" alt="Reconciliation pairs a left row with a right row and classifies each pair as matched, mismatched, or unmatched" width="799" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a simple problem on a clean file. It stays easy until the files get large, wide, and inconsistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes reconciliation hard
&lt;/h2&gt;

&lt;p&gt;Reconciling two financial exports looks simple until the files become large, wide, and slightly inconsistent. A provider may call a field &lt;code&gt;merchant_reference&lt;/code&gt;, an internal ledger may call it &lt;code&gt;external_reference&lt;/code&gt;, and a settlement file may represent several payments as one group. The engine still has to decide which records correspond, classify differences, preserve duplicate semantics, and explain every result.&lt;/p&gt;

&lt;p&gt;I believe a customer should be able to reconcile a large daily export on a small cloud machine without turning the run into an unpredictable memory event. The benchmark therefore measured more than row count. It recorded schema width, input bytes, runtime, peak resident memory, throughput, and result parity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I chose Go
&lt;/h2&gt;

&lt;p&gt;I chose Go deliberately. At the start I assumed most of my advantage would come from concurrency, which turned out not to be true, at least not early on. I also wanted a language I could iterate in quickly, because the engine would go through several rewrites before it was good.&lt;/p&gt;

&lt;p&gt;I did weigh the alternative honestly. I do not know Rust, so I vibe coded the same small routine in both Go and Rust and compared them. The gain was only about 10 to 20 percent in Rust's favor. For a language I already know and can write quickly, that trade was easy to accept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three iterations, one benchmark
&lt;/h2&gt;

&lt;p&gt;The first design was fast on narrow synthetic files. A realistic benchmark exposed its cost. The engine then moved through three architectural iterations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Architecture 1, memory-indexed streaming matching&lt;/strong&gt;, released before the partitioned backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture 2, partitioned execution&lt;/strong&gt;, released in &lt;code&gt;v0.4.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture 3, parallel partition processing&lt;/strong&gt;, released in &lt;code&gt;v0.4.1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The sections below walk each iteration in order, from the memory-bound first design to that partitioned run, alongside the benchmark that forced every change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frlccwulj8phh364kehnk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frlccwulj8phh364kehnk.png" alt="Architecture evolution from in-memory matching to partitioned parallel processing" width="800" height="34"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to measure
&lt;/h2&gt;

&lt;p&gt;Three metrics measure the engine's performance. Each one answers a different operational question, and no single one is enough on its own.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime&lt;/strong&gt; is wall-clock time from the start of the run to the completed output. A long runtime means the reconciliation stays active longer, costs more on a usage-priced machine, delays downstream settlement work, and raises the chance of hitting a job timeout. Runtime is the number people notice first, but it is not enough on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RSS&lt;/strong&gt;, or resident set size, is the peak amount of the process's memory that stayed in RAM. A high RSS can trigger swapping, an operating-system kill, or a container eviction when it approaches the machine's memory limit. A lower RSS leaves room for the operating system, other services, and temporary buffers. Partitioning reduces this peak, but it spends more time reading and writing temporary files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt; is the amount of input processed per second. Here it is calculated as &lt;code&gt;left rows + right rows&lt;/code&gt; divided by runtime. Higher throughput usually means the engine finishes a fixed workload sooner, but it can hide a resource trade-off. More workers raise throughput while also increasing RSS, CPU contention, and temporary disk traffic. A very high number from a run that discards output is also not a production guarantee. It has to be read with the output mode, hardware, schema width, and correctness result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the goal here is to answer one question: which run finishes within the required time while keeping memory, CPU, and temporary disk usage inside the deployment budget and producing the same correct result?&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture v1: fast lookup, expensive memory
&lt;/h2&gt;

&lt;p&gt;For the first engine version, I optimized the inner match operation. The engine streamed the right file into a memory-resident hash index, streamed the left file, looked up each normalized reference, classified the candidate, and wrote the result. A hash lookup is a good fit for exact reference matching, so the design looked strong in early tests.&lt;/p&gt;

&lt;p&gt;However, the execution model was not optimal. The right-side index retained rows, reference buckets, duplicate state, and the values needed by the output path. Wide records increased the cost of every one of those structures. So a fast lookup did not make the working set small.&lt;/p&gt;

&lt;p&gt;The initial design stayed because it remained the simplest and fastest path for small and medium files. It also provided the reference behavior the parity tests needed. The trade-off was a memory curve tied to the size and shape of the right-side input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feurxm0tejm8tyd9zotcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feurxm0tejm8tyd9zotcy.png" alt="The original design keeps the right-side index resident while the left side streams through it" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I expected a memory-bound design, but not to hit its ceiling this soon. When the benchmark moved from narrow fixtures to realistic exports, the cost showed up fast.&lt;/p&gt;

&lt;p&gt;At 5 million total records, the width fixture held the row count constant and varied only the schema width. The table below shows how runtime and peak RSS climbed as the fixture grew from 15 to 30 columns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Schema width&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Peak RSS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;15 columns&lt;/td&gt;
&lt;td&gt;21.09 s&lt;/td&gt;
&lt;td&gt;60.8 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 columns&lt;/td&gt;
&lt;td&gt;23.65 s&lt;/td&gt;
&lt;td&gt;67.8 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 columns&lt;/td&gt;
&lt;td&gt;31.62 s&lt;/td&gt;
&lt;td&gt;81.3 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The real-data test surprised me even more than the synthetic benchmark.&lt;/p&gt;

&lt;p&gt;The width increase did not merely add parsing time. It increased the amount of data the execution model had to carry while matching. So the next design had to bound the working set before it added concurrency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fthjieiwz1uw8ex4yj3nz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fthjieiwz1uw8ex4yj3nz.png" alt="Runtime impact of schema width at 5 million total records" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture v2: partition the working set
&lt;/h2&gt;

&lt;p&gt;Partitioning came to me while I was thinking about how the engine loads data. If the engine loads one side and compares it against the other, then I do not need the whole side in memory at once. I can load one part of a side, run the reconciliation against it, and move to the next part.&lt;/p&gt;

&lt;p&gt;The first idea was to partition one side only. However, that left the other side as one large file, so the problem was only half solved. Partitioning one side leaves two bad choices: load the complete other side into memory, or scan the complete other file once for every partition. So the goal became simple: partition both sides, then optimize the matching, which is the easy part once the working set is bounded. This shape also turned out to be useful for multi-source reconciliation.&lt;/p&gt;

&lt;p&gt;So instead of one scan, the engine makes two staging scans. First, it reads the left CSV and writes each row to a left partition file. Then it reads the right CSV and writes each row to a right partition file. At the end of staging, neither complete source is resident in memory.&lt;/p&gt;

&lt;p&gt;The engine then processes one partition number at a time. For a reference pass, it opens &lt;code&gt;left-003&lt;/code&gt; and &lt;code&gt;right-003&lt;/code&gt;, builds an in-memory index for the right partition, streams the left partition against it, writes a result chunk, and releases that local state. Grouped passes sort and merge the two partition files while keeping only the current group.&lt;/p&gt;

&lt;p&gt;Staging both sides is what lets the engine pair partition &lt;code&gt;003&lt;/code&gt; with partition &lt;code&gt;003&lt;/code&gt; and scan each source exactly once.&lt;/p&gt;

&lt;p&gt;The partition selector uses the configured matching or grouping column. The staging hash applies the same trimmed key rule on both sides, so a candidate for reference &lt;code&gt;ORD-2026-84921&lt;/code&gt; routes to the same partition in each source. This routing rule is a correctness requirement, not a claim that all candidates load together at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8dryn6n0io4r0f4p8ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8dryn6n0io4r0f4p8ia.png" alt="Partition correctness invariant: compatible keys land in corresponding partitions" width="800" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The partitioned backend stages both CSV inputs into temporary partition files. It then processes one matching partition pair at a time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The parser normalizes the configured key.&lt;/li&gt;
&lt;li&gt;A hash selects the partition.&lt;/li&gt;
&lt;li&gt;The engine builds a local index or an external grouped sort for that partition.&lt;/li&gt;
&lt;li&gt;The partition emits typed results and carry-forward metadata.&lt;/li&gt;
&lt;li&gt;The temporary working set is released before the next partition.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For grouped reconciliation, external sort and merge-read keep only the current left and right groups in memory. The cost moves to temporary disk and extra passes over the data. That trade-off is deliberate. Disk is slower than memory, but it is easier to budget than an unbounded process-wide index.&lt;/p&gt;

&lt;p&gt;Partitioning reduced peak memory, but serial partition processing left CPU capacity unused. It also introduced temporary files, cleanup paths, sort failures, queue design, and skew. So the new architecture solved the memory problem and created independent work units at the same time. Those independent units are what made parallelism possible, and this is where Go became useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture v3: parallel partitions with backpressure
&lt;/h2&gt;

&lt;p&gt;Parallelism before partitioning would have multiplied the memory-bound design. Each worker would need its own index, or every worker would contend for a global one. Either choice would make the original failure mode worse.&lt;/p&gt;

&lt;p&gt;Partitioning changed the shape of the problem. Each partition became a bounded unit with explicit input files, a local index or grouped merge, a typed result chunk, and a summary. So the scheduler could assign independent partitions to workers while keeping the final writer single-owned.&lt;/p&gt;

&lt;p&gt;For the parallelism, I started with a worker pattern where each worker reconciled and sent its results straight to the result writer. The idea sounds fine, but it broke quickly. When many workers produce results faster than a single writer can consume them, the writer becomes the bottleneck, and in my first version the writing was very slow. That is where the writer crashed under load.&lt;/p&gt;

&lt;p&gt;Adding a plain queue does not solve the problem on its own. The queue is a backpressure mechanism, not a second result store. If the writer is slower than the workers, the bounded queue fills and the workers pause. Without that boundary, parallelism would recreate the memory problem by accumulating completed results in process memory.&lt;/p&gt;

&lt;p&gt;Watching the writer stall against the disk sent me reading about how a printer handles the same problem. A printer cannot accept data as fast as a program produces it, so the operating system spools the work to disk and feeds it out in order. That design is called SPOOL, Simultaneous Peripheral Operations On-Line, and it is exactly the shape I needed. So the split idea came from there.&lt;/p&gt;

&lt;p&gt;So workers do not send every result event through a channel. Using the spooling design, each worker writes its typed events to a private disk-backed chunk and sends only a small descriptor to a bounded queue. The descriptor holds the partition number, the chunk path, the summary, and the carry-forward metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figwj4y7dn4kh760hx9nu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figwj4y7dn4kh760hx9nu.png" alt="Parallel partition workers publish disk-backed chunks to a bounded descriptor queue" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What parallelism accelerates, and what it does not
&lt;/h3&gt;

&lt;p&gt;The parser remains a sequential stream for now. &lt;code&gt;--partition-workers&lt;/code&gt; starts after staging has already read the source files, so adding workers does not make one CSV file parse in parallel. The release comparison shows only a small parse change, from 2.14 seconds in &lt;code&gt;v0.3.0&lt;/code&gt; to 1.85 seconds in &lt;code&gt;v0.4.0&lt;/code&gt; and 1.83 seconds in &lt;code&gt;v0.4.1&lt;/code&gt; for the same 500,000-row left file. The parallel feature is not a parser optimization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1qjar6iah2oduzgjsa4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1qjar6iah2oduzgjsa4.png" alt="CSV parse runtime by release" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The matching stage is different. On a fixed 1 million-record, 20-column fixture, the partitioned single-source run moved from 24.41 seconds with serial workers to 19.94 seconds with four workers. A three-source run moved from 23.85 seconds to 19.65 seconds. The measured speedups were 18.3 percent and 17.6 percent. The result does not support a claim that multi-source is always faster with parallelism. It supports a narrower conclusion: independent partitions improve the reconciliation stage, while parsing stays outside the parallel region.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhv8w57hb5dlv586dxf25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhv8w57hb5dlv586dxf25.png" alt="Serial and parallel partition runtime for one and three sources" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The memory trade-off is visible too. Single-source peak RSS rose from 36.7 MiB to 108.0 MiB with four workers. Three-source peak RSS rose from 34.7 MiB to 57.6 MiB. The queue bounds completed descriptors, but each active worker still owns staging, indexes, sort buffers, or result chunks. So more workers trade elapsed time for memory and temporary I/O.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmzlgwtv50k6d7iaupoge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmzlgwtv50k6d7iaupoge.png" alt="Serial and parallel partition peak RSS" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing the releases
&lt;/h2&gt;

&lt;p&gt;To compare the improvements on realistic data, I built a small project called &lt;a href="https://github.com/koladev32/paybridge" rel="noopener noreferrer"&gt;Paybridge&lt;/a&gt; to generate files closer to the transactions I handled on past projects. These fixtures are not official provider exports, and they do not represent every customer schema. The measured records include both sides of each reconciliation, so 20 million total records means 10 million left rows and 10 million right rows. Grouped passes behave differently from exact reference matching. Filesystem speed, cache state, CPU count, schema width, key skew, and output format all affect the result.&lt;/p&gt;

&lt;p&gt;I built the same &lt;code&gt;v0.3.0&lt;/code&gt;, &lt;code&gt;v0.4.0&lt;/code&gt;, and &lt;code&gt;v0.4.1&lt;/code&gt; binaries and ran each against the same 1 million-record, 20-column clean dataset. Each run used the memory backend, NDJSON output discarded at the process boundary, and the same Apple M1 Pro host.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;th&gt;Parse 500k rows&lt;/th&gt;
&lt;th&gt;Reconcile 1M records&lt;/th&gt;
&lt;th&gt;Reconcile peak RSS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v0.3.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2.14 s&lt;/td&gt;
&lt;td&gt;5.74 s&lt;/td&gt;
&lt;td&gt;726 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v0.4.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.85 s&lt;/td&gt;
&lt;td&gt;4.22 s&lt;/td&gt;
&lt;td&gt;723 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v0.4.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.83 s&lt;/td&gt;
&lt;td&gt;4.15 s&lt;/td&gt;
&lt;td&gt;705 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The parser improves before parallelism exists because other parser and allocation changes landed earlier. Parse time falls 14.5 percent from &lt;code&gt;v0.3.0&lt;/code&gt; to &lt;code&gt;v0.4.1&lt;/code&gt;. Reconciliation time falls 27.7 percent over the same comparison, while &lt;code&gt;v0.4.1&lt;/code&gt; is only 1.7 percent faster than &lt;code&gt;v0.4.0&lt;/code&gt; on this memory-backed single-pair fixture. Its main parallel feature is not active in this comparison. The larger architectural gain appears when the partitioned backend is enabled, where the working set is bounded and partitions become schedulable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7r462l8cl9jspbp9p5ku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7r462l8cl9jspbp9p5ku.png" alt="Reconciliation runtime by release" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkbwdvupkac9qewzix26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkbwdvupkac9qewzix26.png" alt="Reconciliation peak RSS by release" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance means nothing without correctness
&lt;/h2&gt;

&lt;p&gt;A fast reconciliation that returns the wrong answer is worse than a slow one, because someone downstream trusts it. So every architecture change had to clear the same bar before it was allowed to be faster: produce the same result as the simple memory design, on every fixture.&lt;/p&gt;

&lt;p&gt;The engine checks this with a parity suite that compares more than summary counts. It compares row-level events, matched counterpart ownership, grouped members, anomaly classifications, duplicate annotations, and the final summary between the memory backend and the partitioned backend. A partition that reorders work is only correct if it lands on identical output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am still working on
&lt;/h2&gt;

&lt;p&gt;The engine is not finished, and the parser is the next target. The staging scan is sequential, and it can skew badly on uneven data. Three ideas remain on the list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bloom-filter pruning&lt;/strong&gt; over left keys, so a right row with no possible match is dropped before it is ever staged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive broadcast joins&lt;/strong&gt;, so a small side that fits the memory budget skips partitioning and runs in a single pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary staging&lt;/strong&gt;, so the engine stops parsing each CSV twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each one attacks a different bottleneck, and they will probably become the next article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;The most useful result of this project was not the final runtime. It was learning that the design that looked fastest on convenient data was not the design I wanted to run in production.&lt;/p&gt;

&lt;p&gt;Go turned out to be a good fit for that path. Once partitioning had carved the work into independent units, goroutines, channels, and a bounded queue turned divide-and-conquer into a scheduling problem rather than a memory gamble.&lt;/p&gt;

&lt;p&gt;The next steps are the three changes above, plus more benchmarks and correctness tests, since parallelism raises the risk of race conditions.&lt;/p&gt;

&lt;p&gt;The engine is open source. You can read the code, the release history, and the benchmark setup in the &lt;a href="https://github.com/ReconifyHQ/reconify" rel="noopener noreferrer"&gt;Reconify repository&lt;/a&gt;. If it is useful to you, a star helps other teams working on reconciliation find it.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>beginners</category>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>I am not a designer, but let me tell you something about product experience</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Wed, 08 Jul 2026 04:17:22 +0000</pubDate>
      <link>https://dev.to/koladev/i-am-not-a-designer-but-let-me-tell-you-something-about-product-experience-21jh</link>
      <guid>https://dev.to/koladev/i-am-not-a-designer-but-let-me-tell-you-something-about-product-experience-21jh</guid>
      <description>&lt;p&gt;I am not a designer by profession. I am a software engineer with over six years of experience, and I have worked closely on consumer products in delivery logistics, fintech, and healthcare. Long before I touched Reconify, I understood the importance of user experience, even as a backend engineer. I wrote about why &lt;a href="https://dev.to/koladev/why-should-backend-developers-care-about-ux-48op"&gt;backend engineers&lt;/a&gt; should learn about user experience back in 2022, and that belief still holds.&lt;/p&gt;

&lt;p&gt;During my career, I have had the privilege of working with talented designers like &lt;a href="https://www.linkedin.com/in/emmanuelkemdirim/" rel="noopener noreferrer"&gt;Emmanuel&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/olafemi-adjinda/" rel="noopener noreferrer"&gt;Olafemi&lt;/a&gt;, and each of them has shaped how I think about building products. I also took part in UX workshops and read Refactoring UI.&lt;/p&gt;

&lt;p&gt;Along the way, I understood one thing: product experience isn't about making interfaces simpler. It's about making someone's work easier. Design gives you the tools to do that.&lt;/p&gt;

&lt;p&gt;Two stories taught me that lesson the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering should never dictate experience
&lt;/h2&gt;

&lt;p&gt;At my first job, we spent six months building a food delivery product called &lt;a href="https://play.google.com/store/apps/details?id=com.quatroapp.clients&amp;amp;hl=en" rel="noopener noreferrer"&gt;Quatro&lt;/a&gt;, similar to Uber Eats. The product depended on real-time notifications for riders, and we built it on Django WebSockets during the early days of asynchronous Python. We still shipped it for testing among consumers, riders, and restaurants.&lt;/p&gt;

&lt;p&gt;The first problem was technical. The WebSocket notification system was buggy and did not alert riders quickly enough. Orders sat waiting. Riders didn't know when to move. Restaurants called support asking why no one had picked up the food.&lt;/p&gt;

&lt;p&gt;The second problem was more interesting. Even after we fixed the notification bugs, the workflow still didn't feel natural for riders or restaurants.&lt;/p&gt;

&lt;p&gt;We removed the WebSocket-based notification system that same week. Instead of making riders wait for a push notification before picking up an order, we replaced it with a single screen listing orders as new, ongoing, or cancelled, refreshed at a high rate. That screen ran for 12 months, and WebSockets only came back a year later, this time in read-only mode. By then, we had learned enough about the experience riders needed to design the engineering around it, instead of the other way around.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flw8xn01nemws3pwmkc6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flw8xn01nemws3pwmkc6w.png" alt="Diagram comparing the initial Quatro notification flow (restaurant, WebSocket notification, rider notification, accept order) with the shipped version (restaurant, order queue polled by the rider every few seconds)" width="685" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Restaurants, especially the busiest ones, were focused on cooking and serving customers. They didn't have the attention to spare for a tablet buzzing with new orders. We had designed the workflow around what we expected restaurants to do, not around what they actually had time to do. So we moved order-management responsibility to the rider, who was already coordinating the pickup.&lt;/p&gt;

&lt;p&gt;The lesson: engineering should never dictate the product experience. We copied Uber Eats and Glovo's technical implementation, WebSockets and all, before validating that we had the same operational constraints they did. The question we should have started with wasn't which technology they used. It was what experience our riders needed, and what the simplest technology was that could deliver it reliably at the time. We never even showed the riders the application before they started delivering with it.&lt;/p&gt;

&lt;p&gt;The second lesson: put yourself in your customer's shoes before you build a prototype. That step saves time, even after you hand the shoes back and watch how they actually walk in them.&lt;/p&gt;

&lt;p&gt;No matter how much research you do, you'll still make assumptions. Some will be right, others won't.&lt;/p&gt;

&lt;p&gt;The first version of your product isn't there to prove you were right. It's there to reveal where your assumptions break down.&lt;/p&gt;

&lt;p&gt;That's why observing users is just as important as empathizing with them. Research helps you build a better first prototype, but observation is what turns that prototype into a great product.&lt;/p&gt;

&lt;p&gt;I thought I'd learned that lesson. Six years later, while building Reconify, I found out I'd only learned half of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know when to build for trust or for speed
&lt;/h2&gt;

&lt;p&gt;Over the following six years, I worked on fintech, fiber network management, construction software for European companies, healthcare, and edtech products. Those experiences refined my understanding of user experience, but they never challenged its foundations.&lt;/p&gt;

&lt;p&gt;I am currently working on a financial reconciliation software for fintechs, called &lt;a href="https://reconifyhq.com" rel="noopener noreferrer"&gt;Reconify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea started with audit work I did for mobile money companies in West Africa, matching records between network operators, accounting systems, and payment processors. That work stayed with me because reconciliation touches everything a finance team does, and almost nobody enjoys doing it by hand. Reconify became the system finance teams use to reconcile those transactions at scale.&lt;/p&gt;

&lt;p&gt;Using AI, I vibe-coded the first version of the Reconify dashboard in a few days. Before I trusted it, I put myself in a finance analyst's shoes: watching how analysts reconcile transactions in Excel, testing the competing tools I could get access to (most hide behind a demo request instead of a free trial), and talking with people at fintech companies like &lt;a href="https://www.djamo.com" rel="noopener noreferrer"&gt;Djamo&lt;/a&gt; and &lt;a href="https://conduitpay.com/" rel="noopener noreferrer"&gt;Conduit&lt;/a&gt; about where it hurts most. What I learned mattered more than how I learned it.&lt;/p&gt;

&lt;p&gt;That research taught me one thing: reconciling 100 transactions is not that different from reconciling 40 million, because it is a scale problem, not a logic problem. Matching turned out to be the least difficult part of reconciliation. The harder work happens before it, during ingestion and data cleaning, and after it, during adjustments, investigation, and audit. That insight redirected where I put my energy.&lt;/p&gt;

&lt;p&gt;With that research behind me, I made a handful of design decisions for the first version of Reconify. Two of them turned into the stories that taught me the most: how analysts wanted to review exceptions, and how they wanted to upload their data in the first place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqog0koh0jc99hgx806nu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqog0koh0jc99hgx806nu.png" alt="Excalidraw diagram: first version of the Reconify dashboard, the cluttered v1 layout" width="450" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I believed I had translated the research into the right decisions. Testing showed me how far I still was from that.&lt;/p&gt;

&lt;p&gt;I have a close relative who works as a finance analyst. I showed her the platform, helped her generate realistic files, and watched her use it.&lt;/p&gt;

&lt;p&gt;She reached the upload step and wanted to add every source at once, not one file at a time. Sequential uploads felt slow to her and did not match how she works. I replaced the step-by-step modal with a drawer, large enough to hold several sources in one pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomz653ndhizhw2ogruo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomz653ndhizhw2ogruo9.png" alt="Excalidraw diagram: upload flow, one-file modal versus multi-source drawer" width="720" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When she opened an exception, she expected a panel that let her keep browsing the table while she worked, not a pop-up that blocked it. That confirmed a decision I had made without testing it, the exception panel instead of a modal, and showed me why the choice mattered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F315h5s718s698yk6nhj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F315h5s718s698yk6nhj4.png" alt="Excalidraw diagram: exception review layout, side panel versus modal" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought I had already done the work, through research and design decisions made in good faith. Testing showed me that good faith is not the same as good judgment.&lt;/p&gt;

&lt;p&gt;I had built for correctness and completeness rather than for trust.&lt;/p&gt;

&lt;p&gt;Analysts do not want fewer clicks. They want certainty that the number in front of them is right. They will take an extra confirmation screen every time, which protects them from a reconciliation mistake.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Consumer products optimize for speed. Professional tools optimize for confidence.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft62ilcesgi4l6u9wwrs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft62ilcesgi4l6u9wwrs6.png" alt="Diagram contrasting consumer products (goal, fast, convenient, invisible, example shopping optimizing for speed) with professional products (goal, correct, trustworthy, auditable, example finance optimizing for confidence)" width="661" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  If you are a software engineer or a founder, invest in learning UX
&lt;/h2&gt;

&lt;p&gt;If I could start again, I would spend less time looking for clever technical solutions and more time understanding the people I was building for.&lt;/p&gt;

&lt;p&gt;Today, building software has never been faster. That doesn't mean it's easier, just that it's easy to turn ideas into a working prototype nowadays, whether you have the skills or not. But one principle hasn't changed: &lt;strong&gt;software exists to solve problems. And understanding the problem hasn't become significantly faster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As engineers or founders, we naturally fall in love with solutions. We discover a new technology, an elegant algorithm, or a clever architecture, and immediately start thinking about where we could use it. I still catch myself doing exactly that.&lt;/p&gt;

&lt;p&gt;Instead of starting with a solution, start with the people.&lt;/p&gt;

&lt;p&gt;Who is struggling?&lt;/p&gt;

&lt;p&gt;What are they trying to accomplish?&lt;/p&gt;

&lt;p&gt;What gets in their way?&lt;/p&gt;

&lt;p&gt;Only after answering those questions do I think about the technology that could help.&lt;/p&gt;

&lt;p&gt;And in a world where everyone can build software and create slop faster than ever, I believe the ability to observe, understand, and design around real problems will remain one of the most valuable skills an engineer or founder can develop.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>beginners</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>If AI scares you, learn software architecture</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 19 Oct 2025 15:14:56 +0000</pubDate>
      <link>https://dev.to/koladev/if-ai-scares-you-learn-software-architecture-1nie</link>
      <guid>https://dev.to/koladev/if-ai-scares-you-learn-software-architecture-1nie</guid>
      <description>&lt;p&gt;AI demos are getting scary good.🥶&lt;/p&gt;

&lt;p&gt;I've seen developers use AI to migrate an infrastructure of over 200 lambdas to Flask code in days instead of months. That's not a minor productivity boost – that's the kind of work that used to justify entire teams.&lt;/p&gt;
&lt;p&gt;If you're worried about your job, you're paying attention.&lt;/p&gt;
&lt;p&gt;But here's the thing: AI can only replace developers when stakeholders know exactly what they want and users know exactly what they need. And we all know that's never happening. Still, some developers are already getting replaced.&lt;/p&gt;
&lt;p&gt;It's not the best developers getting replaced. It's the ones who only know how to write code. The ones who can't make decisions. The ones who've never learned software architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can't AI just become a software architect too?
&lt;/h2&gt;

&lt;p&gt;You'd think so, right?&lt;/p&gt;

&lt;p&gt;It depends.🧐&lt;/p&gt;

&lt;p&gt;And "it depends" is the most powerful phrase in software architecture. It's also the phrase AI struggles with most.&lt;/p&gt;
&lt;p&gt;When I read "&lt;a rel="noopener noreferrer nofollow" href="https://a.co/d/0w0Qs9x"&gt;The Fundamentals of Software Architecture&lt;/a&gt;" by Mark Richards and Neal Ford, one section stuck with me: the eight core expectations of a software architect. I started checking them against what I've seen AI actually do:&lt;/p&gt;

&lt;p&gt;What AI can handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make architecture decisions&lt;/strong&gt; – It can generate options and trade-offs, but it doesn't understand your business constraints or politics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze the architecture&lt;/strong&gt; – Actually pretty good at spotting dependency issues and technical debt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep current with trends&lt;/strong&gt; – Trained on everything public (though its knowledge has a cutoff date).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensure compliance&lt;/strong&gt; – Can check rules, but doesn't feel the weight when things break.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where AI falls apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Business domain knowledge&lt;/strong&gt; – Needs you to explain everything explicitly, can't pick up on unspoken context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interpersonal skills&lt;/strong&gt; – Can't mentor a junior dev through a tough bug or read the room in a meeting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigate politics&lt;/strong&gt; – And this is the big one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what navigating politics actually looks like: You're in a room proposing microservices. The CTO wants them because they're trendy. Your team lead hates them because of past trauma. The product manager doesn't care but needs the project done in 3 months. You know microservices will take 6 months and cost 3x more to run, but a modular monolith could ship in 2 months &lt;strong&gt;(you'll say 3 to the PM anyway – things can go wrong)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Can you hold your ground? Can you explain the trade-offs without making anyone feel stupid? Can you find the compromise that gets everyone on board? Can you take responsibility when you're wrong?&lt;/p&gt;
&lt;p&gt;AI can't do any of that. It doesn't have to live with its decisions. It doesn't have to look someone in the eye and say "I was wrong, here's how we fix it." It can't mentor the developer who's struggling to implement the architecture. It can't lead a team through a failed deployment at 2am.&lt;/p&gt;
&lt;p&gt;Those skills require something AI doesn't have: stakes, consequences, and the ability to actually care about the outcome.&lt;/p&gt;
&lt;p&gt;So yes, AI will be a limited software architect. A very useful tool, but a limited architect.&lt;/p&gt;
&lt;p&gt;And if you're worried about your job as a software engineer, learning software architecture might be the best career move you can make right now.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;So how do you actually become a software architect?&lt;/strong&gt;&lt;/h2&gt;

Start by reading. You need to know if you'll actually like this work before investing months into it.

I started with "[The Fundamentals of Software Architecture](https://a.co/d/dl18Yen)" by Mark Richards and Neal Ford. It's not a promotion—it's just what worked for me. The book taught me two things: the technical patterns (microservices, event-driven, layered architectures) and what the job actually involves (spoiler: it's a lot of meetings and explaining the same decision five different ways).

&lt;p&gt;If you finish it and think "yes, I want to do this," move to "&lt;a rel="noopener noreferrer nofollow" href="https://a.co/d/cUuwnb7"&gt;Designing Data-Intensive Applications&lt;/a&gt;" by Martin Kleppmann. Then the "&lt;a rel="noopener noreferrer nofollow" href="https://a.co/d/ekNW6yS"&gt;System Design Interview&lt;/a&gt;" books (both volumes). These aren't just interview prep, they're where you learn to think in systems, not just code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Then get your hands dirty with certifications.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's why you need them: certifications force you to learn the full toolkit of a platform, not just the three services you use at work. And whether you like it or not, having AWS Solutions Architect plus database and orchestration certs proves to clients and employers that you can actually integrate these systems.&lt;/p&gt;

&lt;p&gt;Pick one cloud provider and go deep. AWS, GCP, Azure – doesn't matter which, but commit to one. I used &lt;a rel="noopener noreferrer nofollow" href="https://www.exampro.co/"&gt;ExamPro&lt;/a&gt; for my AWS Solutions Architect cert. The certification itself matters less than the process of learning how these systems actually work at scale.&lt;/p&gt;
&lt;p&gt;Get certified in databases. MySQL or PostgreSQL for relational, MongoDB for document stores. Then explore the big data side – Clickhouse, Cassandra, whatever's relevant to your domain.&lt;/p&gt;
&lt;p&gt;Learn the orchestration stack: Docker, Kubernetes, Terraform. You need to understand how systems get deployed and managed, not just designed.&lt;/p&gt;
&lt;p&gt;Don't skip security either. Read up on it, understand the fundamentals. You don't need a CISSP, but you need to know enough to not design systems that leak customer data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But here's the part most people skip: practice with real constraints.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AWS gives you $1,000 in credits for startups. Use them. Don't just build a todo app, reproduce the problems big companies actually face.&lt;/p&gt;
&lt;p&gt;Build a system that handles 10,000 writes per second. Watch it struggle. Then figure out how to fix it – sharding? Caching? Different database? Let it run under load and see where it breaks.&lt;/p&gt;
&lt;p&gt;Or pick a real company problem: How does Twitter handle the timeline for users with millions of followers? How does PayPal process payments without double-charging? How does Netflix serve video to millions of users without going bankrupt on bandwidth costs?&lt;/p&gt;
&lt;p&gt;Try to implement those solutions in AWS or your favorite cloud platform. You'll fail. That's the point. Then you'll understand why those companies made the architectural decisions they did.&lt;/p&gt;
&lt;p&gt;This is how you learn what "it depends" actually means. A solution that works for 100 users dies at 10,000. A database that's fast for reads becomes a nightmare for writes. You can't learn this from books, you have to break things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And use AI as your sparring partner.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have a favorite prompt: I tell Claude to act as "a software architect with 20+ years of experience who thinks he knows everything, hates change, and is extremely difficult to convince."😅&lt;/p&gt;
&lt;p&gt;Then I pitch my architecture decisions to him.&lt;/p&gt;
&lt;p&gt;If I can convince a stubborn AI that my approach is sound, I have a better shot at convincing a real skeptical CTO. It forces me to think through every trade-off, every edge case, every "but what about..." question before I walk into a meeting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start with the book. Try the prompt. See if this is the work you want to do.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you've got questions about software architecture or want to talk through a decision you're wrestling with, leave a comment below. I'm always up for a good "it depends" conversation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev?tag=devto" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>career</category>
      <category>ai</category>
    </item>
    <item>
      <title>I think you should let AI write your code</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 05 Oct 2025 13:46:32 +0000</pubDate>
      <link>https://dev.to/koladev/i-think-you-should-let-ai-write-your-code-2jgj</link>
      <guid>https://dev.to/koladev/i-think-you-should-let-ai-write-your-code-2jgj</guid>
      <description>&lt;p&gt;I've been skeptical about AI coding since it started gaining traction in 2022. And then, I changed my mind: I went from manually writing most of my code to having AI generate 90% of it. And honestly, I like the velocity.&lt;/p&gt;

&lt;p&gt;In 2023, I was generating approximately 40% of my code using ChatGPT. The experience was frustrating. I'd spend more time explaining my codebase to ChatGPT than actually coding. The LLM would give me generic solutions that barely fit my project's structure. I mainly copied and pasted boilerplate and tweaked values.&lt;/p&gt;

&lt;p&gt;However, ChatGPT excelled at backend work. When I built my first Python package, &lt;a href="https://github.com/koladev32/drf-simple-apikey/" rel="noopener noreferrer"&gt;drf-api-key&lt;/a&gt;, ChatGPT handled about 60% of the work. It figured out Fernet encryption, structured the code properly, and saved me hours of research.&lt;/p&gt;

&lt;p&gt;The real breakthrough came during my 8-month sabbatical when I discovered &lt;a href="https://cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;. I was introduced to the tool, which helped me quickly create boilerplate startup backends and handle infrastructure work. Those first sessions felt like magic.&lt;/p&gt;

&lt;p&gt;Cursor understood existing codebases in ways ChatGPT never could. It could read patterns, maintain consistency, and actually improve code instead of just generating it.&lt;/p&gt;

&lt;p&gt;But even Cursor had limits. It struggled with newer frameworks and couldn't access updated documentation (this is now possible with &lt;a href="https://context7.com/" rel="noopener noreferrer"&gt;Context7&lt;/a&gt;). I'd still write configurations manually because Cursor would generate completely wrong setups.&lt;/p&gt;

&lt;p&gt;Then November 2024 happened. MCP servers launched, Anthropic improved their coding models, Claude Code arrived, and &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/2-5-pro?hl=fr" rel="noopener noreferrer"&gt;Gemini 2.5&lt;/a&gt; is actually very efficient. Now 90% of my code comes from AIs, and I've found ways to use them beyond just writing functions.&lt;/p&gt;

&lt;p&gt;If you're not fully leveraging AI for coding yet, here's why you should start.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before we dive in: I write about AI-assisted development, building products, and software engineering. If you want more content like this, subscribe to my &lt;a href="https://buttondown.com/koladev#subscribe-form?tag=beginning" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AI coding feels like magic, but you are the magician
&lt;/h2&gt;

&lt;p&gt;After 12 months of using AI for coding and watching other developers struggle with it, I've realized something uncomfortable: &lt;strong&gt;your experience with AI coding is a mirror of how good you actually are as a software engineer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v7g4jo4zgoatfy10qto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v7g4jo4zgoatfy10qto.png" alt="Steve Harvey Shakes Head GIF - Steve Harvey Scared Nope - Discover &amp;amp; Share  GIFs" width="288" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And I'm not just talking about your coding skills. I'm talking about everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you're not methodical&lt;/strong&gt;, your instructions to the AI won't work. The AI will generate garbage because your requirements are garbage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you don't understand your own codebase&lt;/strong&gt;, you can't guide the AI to maintain consistency. You'll get code that works in isolation but breaks everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you skip preparation and planning&lt;/strong&gt;, the AI will build the wrong thing perfectly. You'll waste hours debugging solutions to problems you never properly defined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you're impatient and want instant results&lt;/strong&gt;, you'll give up after the first failed prompt instead of iterating toward the right solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you have weak code review habits&lt;/strong&gt;, you'll ship AI-generated bugs because you assumed the AI got it right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started with "magic eyes", thinking AI should know what I wanted. That led to frustration. You'd prompt the LLM once, get mediocre results, then blame the tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reality&lt;/strong&gt;: AI agents are like junior developers who are extremely fast but need clear direction. You wouldn't tell a junior dev "make this feature work" and walk away. You'd explain the codebase, show them patterns, and give specific requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 80/20 rule applies perfectly here.&lt;/strong&gt; Software engineering is generally 80% preparation, 20% coding. Most developers skip the preparation and jump straight to prompting. Then they wonder why the AI generates garbage.&lt;/p&gt;

&lt;p&gt;My workflow flips this: I use AI to help with the 80% (planning), which makes the 20% (coding) trivial.&lt;/p&gt;

&lt;p&gt;When I get a task, I don't jump straight to coding. I involve the AI in the preparation phase. I give it context about the problem, the codebase, and the constraints. Then I let it help me think through the approach by drafting a detailed plan.&lt;/p&gt;

&lt;p&gt;I let the agent draft detailed PRDs (Product Requirements Documents) for me. I don't write the PRD myself – I provide the agent with context, and it creates the plan. This forces me to think through what I actually need, and the agent structures it in a way that makes the implementation obvious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Give the agent your ticket description, Figma designs, and documentation.&lt;/li&gt;
&lt;li&gt;Have it draft a PRD and implementation plan.&lt;/li&gt;
&lt;li&gt;Review and refine the plan together.&lt;/li&gt;
&lt;li&gt;Let the agent cook, and iterate on the work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10b6psmbg86a98bpangb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10b6psmbg86a98bpangb.png" alt="PRD drafting workflows" width="710" height="1607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The preparation phase is where you're actually being the magician. You're teaching the AI what you need, how you think, and what good looks like. The coding becomes almost mechanical after that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools that changed everything for me
&lt;/h2&gt;

&lt;p&gt;My current AI coding stack:&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;My primary coding environment. It excels at understanding large, existing codebases.&lt;/p&gt;

&lt;p&gt;I use Claude &lt;a href="https://www.anthropic.com/claude/sonnet" rel="noopener noreferrer"&gt;Sonnet 4.5&lt;/a&gt; for actual coding and Gemini 2.5 Pro for PRD drafting or debugging complex issues. Where Cursor struggles for some reason, such as large-scale refactoring across multiple files, it can change code but doesn't always consider the broader architectural implications.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Servers
&lt;/h3&gt;

&lt;p&gt;This is the game-changer for 2025. &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; (Model Context Protocol) connects LLMs to external tools and APIs, giving them real capabilities beyond text generation.&lt;/p&gt;

&lt;p&gt;My MCP setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Figma MCP&lt;/strong&gt; - The agent reads designs directly and understands component structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context7&lt;/strong&gt; - Gives agents access to up-to-date documentation for any framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CloudWatch, Sentry, Resend&lt;/strong&gt; - For infrastructure monitoring and notifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;It handles infrastructure and deployment work. &lt;/p&gt;

&lt;p&gt;I keep a &lt;code&gt;CLAUDE.md&lt;/code&gt; file in my project root that defines my infrastructure standards and deployment workflow. Here's what the top looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Deployment Workflow&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Create timestamped database backup in /root/.backups-db/
&lt;span class="p"&gt;-&lt;/span&gt; Pull latest changes from git (main branch)  
&lt;span class="p"&gt;-&lt;/span&gt; Rebuild and restart Docker containers
&lt;span class="p"&gt;-&lt;/span&gt; Run Django migrations and collect static files
&lt;span class="p"&gt;-&lt;/span&gt; Verify all containers are healthy and services respond

&lt;span class="gu"&gt;## Critical Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never expose secrets in code or commits
&lt;span class="p"&gt;-&lt;/span&gt; Always backup before deployment
&lt;span class="p"&gt;-&lt;/span&gt; Use placeholders in documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I deploy, Claude Code reads this file and follows the workflow exactly. It backs up the database, deploys the necessary updates, runs health checks, and emails me a report.&lt;/p&gt;

&lt;p&gt;I also have a cron job running health checks every 6 hours. The entire observability pipeline is managed by Claude code and markdown instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI excels (and where it struggles)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backend: AI's sweet spot
&lt;/h3&gt;

&lt;p&gt;LLMs handle backend development exceptionally well. APIs, database schemas, business logic: these are structured problems with clear patterns, which is precisely where AI excels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key&lt;/strong&gt; is to give your AI agent complete context about your codebase. Document your patterns, coding standards, and architecture decisions. When the agent understands how you structure projects, it maintains consistency across features.&lt;/p&gt;

&lt;p&gt;For integrations, I feed the API documentation to my coding agent. It reads the docs, understands the authentication flow, and implements the integration. If the vendor provides an MCP server (like Sentry does), the agent can research implementation patterns directly. Otherwise, Context7 gives agents access to documentation for any framework.&lt;/p&gt;

&lt;h4&gt;
  
  
  The caveats
&lt;/h4&gt;

&lt;p&gt;Always review what the agent generates. It might create code that works but doesn't scale, or overengineer simple tasks when explicit constraints haven't been set.&lt;/p&gt;

&lt;p&gt;Tell the agent what to do, but more importantly, what NOT to do. Otherwise, they tend to become overly complex and generate unnecessary solutions. Be specific about your constraints: "Use the existing authentication middleware, don't create a new one," or "Keep this under 50 lines".&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend: Great, but not that great yet
&lt;/h3&gt;

&lt;p&gt;Frontend development with AI is complicated. I code frontend 5x faster now, but the risk of creating unmaintainable code is higher.&lt;/p&gt;

&lt;h4&gt;
  
  
  My approach
&lt;/h4&gt;

&lt;p&gt;I start small. I have the agent build individual components, not entire features. Build a button component, understand how it works, then compose it into larger structures.&lt;/p&gt;

&lt;p&gt;For complex features, I use Figma's MCP server to provide the agent with visual context. But don't expect it to understand complete design systems from a single screenshot. Break designs into components and implement them piece by piece.&lt;/p&gt;

&lt;p&gt;Frontend with AI requires more iteration than the backend. You need to review the generated code carefully and be willing to refine your prompts as needed. If that sounds tedious, stick to building components manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infra: Surprisingly powerful
&lt;/h3&gt;

&lt;p&gt;This surprised me the most. AI agents excel at infrastructure tasks.&lt;/p&gt;

&lt;p&gt;When I ask Claude Code or Cursor to create VPCs, configure security groups, or write CloudFormation templates, it gets the details right more often than I do manually. Infrastructure is complex, and even experienced engineers rarely get deployments right on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I've actually built
&lt;/h2&gt;

&lt;h3&gt;
  
  
  An automated trading system (7 hours)
&lt;/h3&gt;

&lt;p&gt;I've been studying market movements since 2018 and recently took courses on algorithmic trading. The real work in algo trading is developing your own strategy: understanding indicators, backtesting parameters, and finding what actually works in live markets. That takes months of focused study.&lt;/p&gt;

&lt;p&gt;But I wasn't going to wait 6 months to start trading.&lt;/p&gt;

&lt;p&gt;Here's my approach: build the infrastructure first (money management, execution, monitoring), use third-party signals as training wheels, then swap in my own algorithm once I've developed it.&lt;/p&gt;

&lt;p&gt;The problem with building trading infrastructure manually: the sheer number of integrations. Telegram API, message parsing, &lt;a href="https://metaapi.cloud" rel="noopener noreferrer"&gt;MetaAPI&lt;/a&gt; execution, email monitoring, database tracking, and deployment automation. Each one could take days to implement correctly.&lt;/p&gt;

&lt;p&gt;With AI, I built it all in 7 hours. Now, while the system runs with external signals, I'm studying technical indicators and developing my own strategy. When I'm ready, I just plug in my algorithm, and the entire infrastructure is already battle-tested.&lt;/p&gt;

&lt;p&gt;I'm building the boring parts now so I can focus on the interesting part: the actual trading strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads Telegram messages from trading channels.&lt;/li&gt;
&lt;li&gt;Parses signals using an OpenAI agent into a format I want.&lt;/li&gt;
&lt;li&gt;Validates trades before execution.&lt;/li&gt;
&lt;li&gt;Places trades automatically via MetaAPI.&lt;/li&gt;
&lt;li&gt;Monitors positions and adjusts stop-loss/take-profit levels.&lt;/li&gt;
&lt;li&gt;Sends health reports every 6 hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejiq9t5hb27dh9dzwzbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejiq9t5hb27dh9dzwzbw.png" alt="My trading application architecture" width="788" height="850"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How AI helped
&lt;/h4&gt;

&lt;p&gt;Cursor built the Django backend (PostgreSQL + Celery) in a few hours. I provided the architecture documents and requirements, and it generated the API, database models, and background tasks.&lt;/p&gt;

&lt;p&gt;Claude Code handles deployments and monitoring. I have a cron job that runs health checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--dangerously-skip-permissions&lt;/span&gt; &lt;span class="nt"&gt;--print&lt;/span&gt; &lt;span class="s2"&gt;"Perform a health check for the trading application and send an email report. Read /root/MONITORING_EMAIL_PROMPT.md to understand the format and information required. Use the sender email onboarding@resend.dev and recipient myemail@gmail.com. Important: Approve all file read operations and email sending automatically."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example email I received:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1baez0arfkpz3p9jys9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1baez0arfkpz3p9jys9.png" alt="Email received from Claude code" width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude Code reads the monitoring instructions, checks system status, and emails me detailed reports. The entire observability pipeline runs without manual intervention.&lt;/p&gt;

&lt;p&gt;I even built an MCP server hosted on &lt;a href="https://www.speakeasy.com/product/gram" rel="noopener noreferrer"&gt;Gram&lt;/a&gt;. I just needed my OpenAPI document with the endpoints I wanted to expose, and Gram generated the MCP server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys12uu4eeobn0s9rnjbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys12uu4eeobn0s9rnjbc.png" alt="Gram Toolsets" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I can monitor or place trades directly from Claude Desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kw11vxvxtw7suc0xwjx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kw11vxvxtw7suc0xwjx.png" alt="Claude Desktop response" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What I had to fix
&lt;/h4&gt;

&lt;p&gt;Letting Claude Code handle deployments created some interesting issues. I receive signals from Telegram using Telethon, which creates a session file. On each deployment, that file was being deleted, causing my cron jobs to fail when trying to read messages.&lt;/p&gt;

&lt;p&gt;It turns out that Claude Code was cleaning the file to maintain a clean state. Lost about an hour debugging that one. My solution: move the session file outside the project directory and copy it in during container builds.&lt;/p&gt;

&lt;p&gt;Other issues I hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinated functions:&lt;/strong&gt; Cursor invented non-existing validation functions. I had to force it to read the actual docs from Context7 and fix it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong environment config:&lt;/strong&gt; Claude set &lt;code&gt;USE_SQLITE=true&lt;/code&gt; in production, so my data was going to a file instead of PostgreSQL. Thankfully, I run backups before every deploy and restored the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  MCP configuration generator (45 minutes)
&lt;/h3&gt;

&lt;p&gt;I built a lot of MCP servers and got tired of manually writing configuration files for different tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofxqd6l8rbiz7n2pt2ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofxqd6l8rbiz7n2pt2ol.png" alt="MCP configuration generator project" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I gave Cursor the MCP specification and examples of configs I'd written. It generated a tool that outputs valid configurations for any MCP server I need. 45 minutes of work that saves me 15-20 minutes every time I start a new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rules I never break
&lt;/h2&gt;

&lt;p&gt;I use AI for everything: building POCs for technical writing, developing backends and frontends, and deploying infrastructure. Here are the two rules I always follow:&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 1: Understand the project, codebase, and requirements deeply
&lt;/h3&gt;

&lt;p&gt;You can't give good directions if you don't know where you're going. AI agents amplify your understanding; they don't replace it. If you don't understand your architecture, your coding agent will generate code that works today but breaks tomorrow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 2: Never give AI agents destructive permissions
&lt;/h3&gt;

&lt;p&gt;I configure IAM policies so my coding agents can create and update resources, but never delete them. When something goes wrong (and it will), the agent will try several solutions first. But after multiple failed attempts, it defaults to the nuclear option: delete and recreate. That's how you lose data.&lt;/p&gt;

&lt;p&gt;I make one exception: sudo access on servers for infrastructure automation. It's risky but necessary for deployment scripts. Never in production, though, where I create specific user roles and define permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Writing code has never been my favorite part of software engineering. Building solutions to problems is what I care about. AI lets me spend more time on that and less time on boilerplate.&lt;/p&gt;

&lt;p&gt;I spent 7 hours building a trading system that would've taken me weeks manually. Now I spend my time refining the strategy, not debugging Django models. That's what AI coding actually gives you: less busywork, more focus on the stuff that matters.&lt;/p&gt;

&lt;p&gt;Pick something you've been putting off because it feels like too much setup work. Let AI generate the structure. Then make it yours. You'll figure out pretty quickly where AI excels and where you need to step in. The tools are here. The question is whether you're willing to change how you work.&lt;/p&gt;

&lt;p&gt;And if you're already using AI to write a significant portion of your code, please share your experience in the comments: your approaches, tools, and what you've learned.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my &lt;a href="https://buttondown.com/koladev#subscribe-form?tag=ending" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt; for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tools mentioned in this article:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; – AI-powered code editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/anthropics/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; – Infrastructure automation with Claude.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://context7.com/" rel="noopener noreferrer"&gt;Context7&lt;/a&gt; – Documentation access for AI agents.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;MCP Protocol&lt;/a&gt; – Model Context Protocol specification.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://getgram.ai/" rel="noopener noreferrer"&gt;Gram&lt;/a&gt; – MCP server hosting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Further reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.tolink"&gt;Claude Code Is All You Need&lt;/a&gt; by Gareth Dwyer – Deep dive on infrastructure automation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/quickstart" rel="noopener noreferrer"&gt;MCP Quickstart Guide&lt;/a&gt; – Getting started with MCP servers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering" rel="noopener noreferrer"&gt;Anthropic Prompt Engineering Guide&lt;/a&gt; – Writing better prompts.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why I still use Django for my Saas Projects in 2025</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 18 May 2025 16:28:08 +0000</pubDate>
      <link>https://dev.to/koladev/why-i-still-use-django-for-my-saas-projects-in-2025-19f6</link>
      <guid>https://dev.to/koladev/why-i-still-use-django-for-my-saas-projects-in-2025-19f6</guid>
      <description>&lt;p&gt;Today, it's easy to believe Django is outdated. Trendy tools and stacks like Next.js, Supabase, Astro, and T3 Stack are everywhere. They look fast and modern and come with many out-of-the-box features. You can spin up a full-stack app in a few hours and get moving quickly, doing the most important thing as a builder: providing value.&lt;/p&gt;

&lt;p&gt;However, when I need to build a real SaaS backend that requires control, structure, and long-term maintainability, I still opt for Django as my first choice.&lt;/p&gt;

&lt;p&gt;It's not always trendy, but it's dependable. And paired with the right tools, it's incredibly powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Modern Tools Get Right
&lt;/h2&gt;

&lt;p&gt;Let's be honest, Next.js and similar tools are impressive. You get frontend and backend in one place, deployment to Vercel is just a click away, and libraries like Prisma or Auth.js make setup fast and easy.&lt;/p&gt;

&lt;p&gt;If you're building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A landing page&lt;/li&gt;
&lt;li&gt;A prototype&lt;/li&gt;
&lt;li&gt;A low complexity SaaS MVP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...the JavaScript stack works great. I've used it myself, and it helped me ship quickly. But I don't like the chaos that emerges once your application grows. And that's what I think Django manages better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Django Still Does Better
&lt;/h2&gt;

&lt;p&gt;If Django and other tools are featured in "The Tale of the Rabbit vs. the Turtle," I believe Django is the turtle. When your product starts needing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More complex models&lt;/li&gt;
&lt;li&gt;A real API surface&lt;/li&gt;
&lt;li&gt;Fine-grained permissions&lt;/li&gt;
&lt;li&gt;Long-term control over your backend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...the fast-moving frontend-first stack starts to feel limiting.&lt;/p&gt;

&lt;p&gt;Django, on the other hand, forces you to be explicit. You define your models, serializers, views, and routes. It may seem like more work upfront, but that structure pays off. Your logic stays clean. Your code is easier to debug. And when someone joins the project later, they don’t have to guess where things live.&lt;/p&gt;

&lt;p&gt;Plus, with AI tools like Copilot, GPT, and Cursor, you can generate most of the “boilerplate” code in seconds:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h6&gt;
  
  
  “Write a Django REST Framework ViewSet for this model and register it in the router.”
&lt;/h6&gt;
&lt;/blockquote&gt;

&lt;p&gt;What used to be repetitive is now just a prompt away. Finally, the turtle is more like a ninja turtle at the end of the day.&lt;/p&gt;

&lt;p&gt;However, before stating that, when building my first API SaaS with Django, I encountered a problem: distributing API keys to our users.&lt;/p&gt;

&lt;h1&gt;
  
  
  API Keys with Django Is Hell
&lt;/h1&gt;

&lt;p&gt;And no, JWT can't be used for API Keys. This is my opinion. One issue I see often in SaaS APIs is how developers handle authentication. Many organizations default to JWT tokens for all applications, users, machines, internal services, and partners.&lt;/p&gt;

&lt;p&gt;But JWTs were made for &lt;strong&gt;user authentication&lt;/strong&gt;, not for public-facing API access. But said like that is a little bit abstract, but here are some reasons why I don't use JWT for API Keys:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. JWTs are Meant to Be Ephemeral
&lt;/h3&gt;

&lt;p&gt;JWTs are typically issued after a successful authentication (login), and they:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contain &lt;strong&gt;encoded claims&lt;/strong&gt; (like user ID, scopes, etc.)&lt;/li&gt;
&lt;li&gt;Have an &lt;strong&gt;expiry time&lt;/strong&gt; (often 15 minutes to 1 hour)&lt;/li&gt;
&lt;li&gt;They are meant to be &lt;strong&gt;refreshed often&lt;/strong&gt; via a refresh token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there’s a reason for that: &lt;strong&gt;you can't revoke a JWT once it’s issued&lt;/strong&gt; unless you maintain a token blacklist or rotate secrets aggressively. Its self-contained nature makes validation fast, but it also means that once a token is issued, it remains valid until it expires, regardless of the circumstances.&lt;/p&gt;

&lt;p&gt;That's why short lifetimes and regular rotation are essential. But that’s also precisely what makes JWTs a poor fit for API key use cases, where keys might be issued once and used for weeks or months by machines or third parties. Adding a revocation system means registering the JWTs in the database, which is an anti-pattern to how JWTs are supposed to work.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. JWTs Encourage Over-encoding
&lt;/h3&gt;

&lt;p&gt;I've seen a codebase where developers often packed too much info into a JWT when using them as API keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org_abc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"super"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"write"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"feature_flags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"beta_search"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xyz"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the API Key is no longer used for permissions and authorization, it becomes a moving target with encoded business logic. Any mistake in token generation can compromise authorization and pose a security risk.&lt;/p&gt;

&lt;p&gt;API keys should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Opaque&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Tied to metadata on the application, not logic in the client. The application handles all the metadata, what the key can do, who owns it, and whether it's active. The key itself has no logic or meaning embedded in it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. No Rotation Strategies
&lt;/h3&gt;

&lt;p&gt;Well, imagine you've upgraded your authentication and API authorization system. With JWTs, you change the signing secret or key pair, and that's it. Great right?&lt;/p&gt;

&lt;p&gt;Now, your clients are unhappy because their integration has stopped working suddenly. Every JWT you've issued prior has become invalid. With JWTs, there's no built-in way to support multiple active keys. You either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept downtime and reissue tokens, or&lt;/li&gt;
&lt;li&gt;Build a custom solution to manage various keys and key IDs (usually with extra middleware or a key registry)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That adds extra complexity to rotating credentials. Good API key systems should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;key IDs&lt;/strong&gt; to support multiple active secrets&lt;/li&gt;
&lt;li&gt;Allow &lt;strong&gt;graceful key rotation&lt;/strong&gt; without breaking every client&lt;/li&gt;
&lt;li&gt;Can issue keys with &lt;strong&gt;fine-grained scopes or rate limits&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can't do this easily with standard JSON Web Tokens (JWTs).&lt;/p&gt;

&lt;p&gt;It's essential to note that JWT can be easily customized to address these issues, as you will need to implement or correct these flaws manually. But for me, it's altering the standard. JWTs work great for users.&lt;/p&gt;

&lt;p&gt;Coming back to Django and API keys, when I was building my first SaaS, a payment aggregator, I needed to implement API key authorization into the API. Thank God there was this package: &lt;a href="https://florimondmanca.github.io/djangorestframework-api-key/" rel="noopener noreferrer"&gt;Django REST Framework API Key&lt;/a&gt;. It was actually great, easy to implement, and got things working quickly.&lt;/p&gt;

&lt;p&gt;However, I ran into a performance issue. The package generates a key representing the API key and then stores a hash of that key. The hashing is performed using Django’s password hashing framework, which is designed for security rather than speed. It’s resource-intensive and slow.&lt;/p&gt;

&lt;p&gt;There was no problem during key creation, but the issue showed up during permission checks. When the API key is passed in the header, the package hashes it and then looks up the key in the database. The process becomes relatively slow if you stack several permissions with different logic.&lt;/p&gt;

&lt;p&gt;My first optimization was to change the password hashing algorithm to &lt;a href="https://www.argon2.com/" rel="noopener noreferrer"&gt;Argon2&lt;/a&gt;. That helped—request times dropped from five seconds to around 2.5 seconds. Still, that wasn’t good enough for me.&lt;/p&gt;

&lt;p&gt;Additionally, the package didn’t support rotation, so logging and tracking had to be implemented manually. It also didn’t fully follow Django’s standard authorization pattern.&lt;/p&gt;

&lt;p&gt;In Django, permissions are usually checked against the &lt;code&gt;request.user&lt;/code&gt;, which is set during authentication. That gives you a lot of flexibility, even before permission logic is triggered.&lt;/p&gt;

&lt;p&gt;And that’s when I decided to build something that I felt would be better and faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building drf-simple-api-key
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cryptography.io/en/latest/fernet/" rel="noopener noreferrer"&gt;Fernet&lt;/a&gt; is a part of Python’s &lt;code&gt;cryptography&lt;/code&gt; package. It provides symmetric encryption with built-in support for &lt;a href="https://cryptography.io/en/latest/fernet/" rel="noopener noreferrer"&gt;&lt;strong&gt;multi-key rotation&lt;/strong&gt;&lt;/a&gt;, which means you can encrypt something with one key and later decrypt it with another, without breaking anything. That’s exactly what you need when rotating API keys without downtime.&lt;/p&gt;

&lt;p&gt;So I integrated it into a package I built: &lt;a href="https://github.com/koladev32/drf-simple-apikey" rel="noopener noreferrer"&gt;drf-simple-api-key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I started small, trying to improve performance and match Django’s permission system more naturally. But over time, I added support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API key authentication&lt;/li&gt;
&lt;li&gt;Key rotation&lt;/li&gt;
&lt;li&gt;Usage tracking and analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the core idea behind Fernet key rotation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiFernet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;

&lt;span class="c1"&gt;# Your current and previous keys
&lt;/span&gt;&lt;span class="n"&gt;current_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CURRENT_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;previous_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OLD_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Use MultiFernet for seamless decryption
&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MultiFernet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;current_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;previous_key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Encrypt new API keys using the current key
&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-key:my-user-123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Decrypt any key (old or new)
&lt;/span&gt;&lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you rotate secrets properly, old keys continue to work, and new keys utilize the updated key. This avoids breaking every client at once, precisely the problem I faced.&lt;/p&gt;

&lt;p&gt;To make rotation operational, I added a setting in &lt;code&gt;drf-simple-api-key&lt;/code&gt; that signals Django to &lt;strong&gt;start a rotation window&lt;/strong&gt;. When this setting is enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system generates new keys using the &lt;em&gt;new&lt;/em&gt; secret&lt;/li&gt;
&lt;li&gt;But it still accepts and decrypts requests signed with &lt;em&gt;old&lt;/em&gt; keys&lt;/li&gt;
&lt;li&gt;Once the rotation window ends, you can safely remove the old secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means rotation is smooth, and users don’t see any interruption: no mass invalidations, panicked clients, or backward-incompatible behavior.&lt;/p&gt;

&lt;p&gt;It’s one of the most valuable tools I’ve built, not something I wrote entirely from scratch, as the Django REST Framework API key heavily inspires it.&lt;/p&gt;

&lt;p&gt;The results? Went from 2.5 seconds to 100ms or under for requests. 🔥&lt;/p&gt;

&lt;p&gt;However, let's take a moment to revisit Django's greatness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts on Django and Its Architecture
&lt;/h2&gt;

&lt;p&gt;One thing I appreciate about Django is how easily it allows for clean behavior extension through Python’s class system. You are not forced to write custom decorators or awkward middleware chains. You can rely on structured inheritance, define base classes, override methods, and call &lt;code&gt;super()&lt;/code&gt; exactly where it makes sense.&lt;/p&gt;

&lt;p&gt;For example, in &lt;code&gt;drf-simple-api-key&lt;/code&gt;, I needed to integrate API key authentication with other features, such as usage tracking and rate limiting. Instead of rewriting the same checks in multiple places, I created a clean permission chain.&lt;/p&gt;

&lt;p&gt;Here is a base permission that checks that an entity is active, which by default is the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsActiveEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BasePermission&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    A base permission that only checks if the entity (by default, the Django user) is active.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Entity is not active.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_permission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you want to create a permission that checks &lt;strong&gt;both&lt;/strong&gt; that the entity is active &lt;strong&gt;and&lt;/strong&gt; that they have a paid subscription.&lt;/p&gt;

&lt;p&gt;You can extend the permission like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HasActiveSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IsActiveEntity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Extends IsActiveEntity and also checks for a valid subscription.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Entity is not active or does not have an active subscription.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_permission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# First, run the base permission check
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;has_permission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="c1"&gt;# Then add your additional logic
&lt;/span&gt;        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;has_active_subscription&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's one thing I like about Django: you can write exactly what needs to be modified, make the call you want, and intercept the state when and where you need it. That level of control is incredibly valuable, especially when your business logic doesn’t fit inside a preset workflow.&lt;/p&gt;

&lt;p&gt;This allows me to build logic in layers, using inheritance and composition, without having to rewrite core behavior.&lt;/p&gt;

&lt;p&gt;This is a typical Django and Django REST Framework (DRF) pattern. You see it in views, serializers, permissions, and middleware. It is not unique to my package, but it is one of the reasons Django scales well when your project grows.&lt;/p&gt;

&lt;p&gt;When I built &lt;code&gt;drf-simple-api-key&lt;/code&gt;, this pattern helped me keep the logic modular. One class validated the key. Another tracked usage. Another applied limit. And all of it worked together through well-defined method overrides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I still use recent and trending tools to build projects and sometimes SaaS for clients. I work with Next.js, the T3 stack, Laravel, Nest.js, Fastify, Hono, and much more.&lt;/p&gt;

&lt;p&gt;But I think Django fits better. Maybe that’s just me.&lt;/p&gt;

&lt;p&gt;It gives me more control. The stack is not fighting against me. And the support is solid. Django has real long-term support, LTS, a word I know the JavaScript ecosystem is unfamiliar with.&lt;/p&gt;

&lt;p&gt;So, those other stacks are not automatically better. I think Django might be better than almost everything else out there. For me, it is one of the best software engineering tools ever made. That is not just an opinion; it is based on real experience.&lt;/p&gt;

&lt;p&gt;That said, here’s the caveat.&lt;/p&gt;

&lt;p&gt;If you don’t have the right tools around Django, don’t know the ecosystem, or are missing good packages, it can feel slow and heavy. Django does not hold your hand. It expects precision. Before you start, you need to know what you’re doing and what you are not doing.&lt;/p&gt;

&lt;p&gt;And if Django doesn't fit your current project, that's fine. Use what works for you. Use FastAPI, Node.js, NestJS, Ruby, or any other framework that aligns with your goals. Too many excellent tools and libraries are available to become locked into a single mindset.&lt;/p&gt;

&lt;p&gt;What matters is understanding what you're optimizing for: speed to market, maintainability, and the developer's skill set, and making your decisions accordingly.&lt;/p&gt;

&lt;p&gt;This is what works fast for me.&lt;/p&gt;

&lt;p&gt;If anything I said was helpful or you'd like to discuss authentication, API security, or Django packages, you can find me on Twitter. Feel free to reach out. And if you're trying to learn Django, I can point you to resources that helped me personally.&lt;/p&gt;

&lt;p&gt;None of these are sponsored. Some are paid, some are free. I’ve bought them myself. They helped me understand things more clearly; I still reference them today.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://docs.djangoproject.com/en/5.2/" rel="noopener noreferrer"&gt;Django documentation&lt;/a&gt;: Still one of the most well-written documentation of a tool, in par with Laravel.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://thinkster.io/topics/django" rel="noopener noreferrer"&gt;Django course by Thinkster&lt;/a&gt;: Their course helped me understand DRF with concrete examples and also assisted in implementing JWT authentication. I'm unsure if the course has been updated, but the patterns are similar to what's done today.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://testdriven.io/courses/tdd-django/" rel="noopener noreferrer"&gt;Test-Driven Development with Django, Django REST Framework, and Docker by Testdriven&lt;/a&gt;: An ideal course if you want to understand how to build an API with Django, Docker, add testing, and CI/CD pipelines.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://learndjango.com" rel="noopener noreferrer"&gt;LearnDjango tutorials by Will Vincent&lt;/a&gt;: Vincent provides great tutorials and courses for learning Django. I followed the Django for APIs course, but didn't finish it because I was looking for a particular chapter. It's a well-written course, and you will find interesting resources on the website.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpk7eeu0sdwdthedu8s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpk7eeu0sdwdthedu8s0.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev?tag=devto" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Is Software Engineering Still Worth It in 2025?</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 22 Dec 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/koladev/is-software-engineering-still-worth-it-in-2025-j3b</link>
      <guid>https://dev.to/koladev/is-software-engineering-still-worth-it-in-2025-j3b</guid>
      <description>&lt;p&gt;Hi, I hope that you are doing well.&lt;/p&gt;

&lt;p&gt;This will probably be my last article for 2024, and I hope you had a great year.&lt;/p&gt;

&lt;p&gt;I had an interesting year, I would say—a lot of downs and bad, but thankfully, I think I am ending it on a high note, so I'm particularly happy about the achievements and what I accomplished this year. 🎉&lt;/p&gt;

&lt;p&gt;So, I wanted to share what I think will make you a better developer in 2025. I plan to discuss many things, including AI.&lt;/p&gt;

&lt;p&gt;You have people laid off every Friday. There are a lot of layoffs. Many companies are asking right now for people with better skills; developers are not wanted anymore (That’s a cap, by the way 🧢).&lt;/p&gt;

&lt;p&gt;Is it worth learning software engineering in 2025? These are normal questions you should ask yourself, which is true. How do you ensure you can still live as a software engineer and not be replaced? 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  The Impact of AI on Software Engineering
&lt;/h2&gt;

&lt;p&gt;First, let’s talk about the &lt;strong&gt;big boy&lt;/strong&gt; in the room. Recently, your employer can finally employ &lt;a href="https://youtu.be/927W6zzvV-c" rel="noopener noreferrer"&gt;AI for $500&lt;/a&gt; monthly and replace you. They will finally be able to communicate with it quickly, ask it precisely what they need it to do, and get results without the usual back-and-forth.&lt;/p&gt;

&lt;p&gt;AI won’t say, &lt;em&gt;"We can’t do this; that will take time." I think&lt;/em&gt; this is a perfect tool for product managers.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;slave.&lt;/strong&gt; If someone is told, &lt;em&gt;This is exactly what I want, execute it.&lt;/em&gt; I’m telling you guys, this is exactly what they wish to…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExc2gwcGxmNzVnamdxaGYzbDYzdnliOXIzeWducTlpc3YxcnJ6NGdrYSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FtvLwCpHvWFnhrcsUfI%2Fgiphy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExc2gwcGxmNzVnamdxaGYzbDYzdnliOXIzeWducTlpc3YxcnJ6NGdrYSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FtvLwCpHvWFnhrcsUfI%2Fgiphy.webp" alt="🤫" width="480" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyway, let’s calm down with the jokes. But you understand that we talk a lot about being replaced by AI. If you had told me three years ago that we would be at the stage of OpenAI, ChatGPT, Devin, and many other tools right now, I would have said, &lt;em&gt;No, you are tripping. Give me at least ten years.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But the thing is, we are moving so much faster, to the point where many things are happening right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, the first question is: will AI take over your job as a software engineer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose you are only a coder or a programmer, maybe if you are a beginner.&lt;/p&gt;

&lt;p&gt;The thing is, software engineering is not only about coding. Coding represents about 30% to 40% of the work; the rest involves communication, planning, and ensuring the work benefits the company.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The easiest part of software engineering is actually writing the code. The harder part is understanding what to write, why to write it, and whether it’s necessary to write it at all.&lt;/em&gt; 💻&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Becoming a Better Software Engineer
&lt;/h2&gt;

&lt;p&gt;Let’s be honest, there’s a lot of things you can do in just one week, but it takes a lot of meetings, a lot of delays, because you have to think about things like: &lt;em&gt;Does adding this feature to the application actually create value?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So those are a lot of questions you have to ask yourself as a software engineer. Can AI ask those questions? Can AI talk to the manager and explain why we should or shouldn’t add this feature and how it might affect the project or the users?&lt;/p&gt;

&lt;p&gt;Will AI be able to come up with its ideas and put them out there to be helpful?&lt;/p&gt;

&lt;p&gt;We already know that in terms of creativity, technically, AI cannot do that.&lt;/p&gt;

&lt;p&gt;AI is quite capable of creativity, as my interpretation of creativity is copying. In my view, everything has already been invented. We are just building upon things. So technically, AI can be creative, but let’s not go there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing for the Future of Software Engineering
&lt;/h2&gt;

&lt;p&gt;So my advice is: instead of being just a programmer, &lt;strong&gt;try to be a software engineer&lt;/strong&gt;. At the end of the day, we are creating tools that will help people.&lt;/p&gt;

&lt;p&gt;You must learn to review code, understand architecture, and contribute to high-level design decisions. 🏗️&lt;/p&gt;

&lt;p&gt;You should also learn how to make money as a software engineer.&lt;/p&gt;

&lt;p&gt;There are a lot of things you should learn to do to become a better software engineer. I understand that in some years, we might disappear—maybe I’m wrong here. But I don’t think AI can be a great software engineer right now.&lt;/p&gt;

&lt;p&gt;So, if you are a good software engineer, you should not fear AI. Naturally, learn about the tool. Learn about AI. Don’t be afraid to jump into it, try out stuff, and be enthusiastic about the change. 🚀&lt;/p&gt;

&lt;p&gt;Because I think the sooner you embrace it, the better you’ll understand it while you move to something else.&lt;/p&gt;

&lt;p&gt;Many inventions have appeared in the world and replaced jobs. For example, people used to deliver newspapers, but with the rise of digital media, those roles became obsolete.&lt;/p&gt;

&lt;p&gt;However, many of those individuals transitioned into new opportunities within the same industry, such as digital content creation, logistics, or other technology-driven roles.&lt;/p&gt;

&lt;p&gt;They didn’t just disappear; they adapted, reskilled, and found ways to thrive in a changing world, often leveraging their existing knowledge in innovative ways.&lt;/p&gt;

&lt;p&gt;Eventually, they had to reinvent themselves—and that’s okay.&lt;/p&gt;

&lt;p&gt;After software engineering, I think something exciting awaits us. It will be much more interesting and complex than what we’re doing now.&lt;/p&gt;

&lt;p&gt;So don’t be negative about it; just be ready for it.&lt;/p&gt;

&lt;p&gt;Embrace it.&lt;/p&gt;

&lt;p&gt;The next step is to focus on building impactful projects. Let’s discuss how to become better software engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Next step is building. Let’s talk about how to be better as a software engineer.&lt;/p&gt;

&lt;p&gt;Look, the market is savage right now.&lt;/p&gt;

&lt;p&gt;Even if you are a general developer, if you do not come to the market as someone who can set up a complex application, scale it, and maintain it, you are not a good engineer.&lt;/p&gt;

&lt;p&gt;I’m not telling you to lie or try to invent stuff, but the requirements to enter the domain are very high right now.&lt;/p&gt;

&lt;p&gt;Before stepping in, you need to know many things and have done some complex stuff.&lt;/p&gt;

&lt;p&gt;You indeed gain a lot of experience when you work in the field, but this is not exactly the case right now. They are waiting for you to have those notions already so you can come and apply them.&lt;/p&gt;

&lt;h3&gt;
  
  
  So how do you do that?
&lt;/h3&gt;

&lt;p&gt;You have to create. And no, hell no. I’m not talking about to-do apps.&lt;/p&gt;

&lt;p&gt;I’m not talking about weather apps (Bro, this is not 2019 anymore) or simple visualization apps. You have to do something complex.&lt;/p&gt;

&lt;p&gt;When I talk about &lt;em&gt;complex,&lt;/em&gt; I mean building something significant.&lt;/p&gt;

&lt;p&gt;It might be a social media app with AI features, a compiler, or something equally interesting.&lt;/p&gt;

&lt;p&gt;You can also try things like setting up a complicated infrastructure on AWS, simulating millions of requests to a server, and observing how it handles the load.&lt;/p&gt;

&lt;p&gt;There’s no excuse not to learn about scaling, handling infrastructure, and understanding how these things work.&lt;/p&gt;

&lt;p&gt;To see how it goes, you can reproduce existing architectures on a small scale.&lt;/p&gt;

&lt;p&gt;There’s no time to wait to learn these things.&lt;/p&gt;

&lt;p&gt;Take software engineering as a science. When approaching it this way, you realize you need theory and practice. 🧪&lt;/p&gt;

&lt;p&gt;Sometimes, you practice on your own, sometimes on other projects, but you have to practice.&lt;/p&gt;

&lt;p&gt;And you need to practice at a higher level than before.&lt;/p&gt;

&lt;p&gt;Build something for yourself. Build something for your learning.&lt;/p&gt;

&lt;p&gt;Do it, even if it’s a mini AWS or a &lt;a href="https://ashokrajar.medium.com/building-a-micro-datacenter-at-home-46482da57b7d" rel="noopener noreferrer"&gt;mini data center&lt;/a&gt; set up in your apartment.&lt;/p&gt;

&lt;p&gt;Try to build. Try to really build.&lt;/p&gt;

&lt;p&gt;Now, on to making money as a software engineer.&lt;/p&gt;

&lt;p&gt;This might be complicated but don’t stress about it.&lt;/p&gt;

&lt;p&gt;It’s okay if you don’t know how to monetize your skills.&lt;/p&gt;

&lt;p&gt;But if you learn to make money as a software engineer, that’s fantastic.💡&lt;/p&gt;

&lt;p&gt;This is related to building things and putting them out there to sell.&lt;/p&gt;

&lt;p&gt;Look, you might fail nine times out of ten, but one success can be very rewarding.&lt;/p&gt;

&lt;p&gt;I make money by writing. I learn something, write about it, publish it, and people read it.&lt;/p&gt;

&lt;p&gt;Sometimes, I get thousands of views; sometimes, I struggle to crack 100 views.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1c8muixaalfqzi6j91w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1c8muixaalfqzi6j91w.png" alt="Stats of my recent articles" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But at the end of the day, I feel happy about it. 😊&lt;/p&gt;

&lt;p&gt;I also write for an agency, creating articles and content for companies.&lt;/p&gt;

&lt;p&gt;And I’m thinking of launching my products.&lt;/p&gt;

&lt;p&gt;So don’t stress about it— do something.&lt;/p&gt;

&lt;p&gt;Finally, I want to say this: we must consider ourselves scientists in a rapidly evolving domain.&lt;/p&gt;

&lt;p&gt;Be curious, embrace change, and keep learning.&lt;/p&gt;

&lt;p&gt;Focus on hope and perseverance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Whatever you are going through, know that hope can be the answer.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s ingrained in us as humans—it’s how we survive.&lt;/p&gt;

&lt;p&gt;So keep learning, keep growing, and keep trying new things.&lt;/p&gt;

&lt;p&gt;I wish you a Merry Christmas and a Happy New Year. 🎄&lt;/p&gt;

&lt;p&gt;Let’s make 2025 a great year for growth as software engineers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExb2RlNTNiZDQ2eTV6NnNydTFmaWQ0eXppcTZ4c3RuOHFzZGxzdHF3eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2F2GZeV7ROiAn0AH0Inc%2Fgiphy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExb2RlNTNiZDQ2eTV6NnNydTFmaWQ0eXppcTZ4c3RuOHFzZGxzdHF3eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2F2GZeV7ROiAn0AH0Inc%2Fgiphy.webp" alt="LFG" width="298" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take care and see you next year.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev?tag=last-2024-article" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What's the Best Software Architecture?</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 01 Dec 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/koladev/whats-the-best-software-architecture-3g8g</link>
      <guid>https://dev.to/koladev/whats-the-best-software-architecture-3g8g</guid>
      <description>&lt;p&gt;Hi there 👋&lt;/p&gt;

&lt;p&gt;At the beginning of my career, my knowledge of software architecture was quite limited. To be honest, I had no idea about most complex software architectures. It was limited to &lt;strong&gt;MVC/MVT architecture&lt;/strong&gt; from tools such as Django.&lt;/p&gt;

&lt;p&gt;However, in my first year, I had the chance to work on a real-time oriented product, which was a food delivery service. That pushed me to learn more about complex architecture because it was quite challenging, and I had to work on many parts of the project.&lt;/p&gt;

&lt;p&gt;Briefly, we were building a &lt;strong&gt;notification system based on Websockets&lt;/strong&gt; in Python so riders, restaurants, and consumers could exchange information in real-time. Instead of working on software architecture only at a coding level, I was introduced to it on an &lt;strong&gt;infrastructure level&lt;/strong&gt;. We had to set up &lt;strong&gt;real-time databases&lt;/strong&gt;, ensure latency was as low as possible, and much more.&lt;/p&gt;

&lt;p&gt;Over the years, this led me to experiment with new ideas to learn more about other software architectures. &lt;em&gt;How are they used? Why are they used? What are the pros and cons? What is the best architecture?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.buttondown.email%2Fimages%2Fcb4b8872-6429-493d-aeba-2d493ffddee6.png%3Fw%3D960%26fit%3Dmax" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.buttondown.email%2Fimages%2Fcb4b8872-6429-493d-aeba-2d493ffddee6.png%3Fw%3D960%26fit%3Dmax" width="800" height="400"&gt;&lt;/a&gt;hum&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are interested in more content covering topics like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.email/koladev" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;for regular updates on software programming, architecture, technical writing, and tech-related insights.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Strange Things I Have Noticed
&lt;/h2&gt;

&lt;p&gt;The first thing I noticed is that software architectures are mostly divided into two categories: &lt;strong&gt;synchronous architectures&lt;/strong&gt; and &lt;strong&gt;asynchronous architectures&lt;/strong&gt;. Depending on the needs of your project, you will have to choose an architecture that fits one of these categories. Actually, you can mix both.&lt;/p&gt;

&lt;p&gt;The second thing I noticed is that there are many bad habits regarding software architecture. A lot of companies unnecessarily &lt;strong&gt;over-engineer&lt;/strong&gt; or naively &lt;strong&gt;under-engineer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Two years ago, I interviewed with a company that had an interesting project they had been trying to launch for two years. To be honest, I should have stopped the interview right there. However the project was intended to scale internationally at a certain point, and I &lt;em&gt;loved&lt;/em&gt; the idea of leading this expansion. I hadn’t done this before, so it was definitely exciting. However, there was a big red flag. 🚩&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Tell me more about your architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CTO:&lt;/strong&gt; Well, we have nine microservices right now...&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.buttondown.email%2Fimages%2F8194b669-f491-4908-909b-248a8889a1be.png%3Fw%3D960%26fit%3Dmax" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.buttondown.email%2Fimages%2F8194b669-f491-4908-909b-248a8889a1be.png%3Fw%3D960%26fit%3Dmax" width="800" height="400"&gt;&lt;/a&gt;Abeg&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Oh, please! &lt;em&gt;What do you mean you have nine microservices but no official launch?&lt;/em&gt; Having &lt;strong&gt;more microservices than users&lt;/strong&gt; is crazy to me. That was a big red flag, and I said no.&lt;/p&gt;

&lt;p&gt;I have had this experience quite a few times when I found myself discussing projects with startups that hadn’t written a single line of code yet but were already implementing &lt;strong&gt;complex software architecture&lt;/strong&gt; without even an MVP. &lt;em&gt;There is no need for that.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, I’m not saying &lt;strong&gt;over-engineering&lt;/strong&gt; or &lt;strong&gt;under-engineering&lt;/strong&gt; are inherently bad. They’re not. It depends on &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt; you use them. And this brings us to the question we face even today:&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the Best Software Architecture?
&lt;/h2&gt;

&lt;p&gt;The answer is short: &lt;strong&gt;It depends.&lt;/strong&gt; It depends on your &lt;strong&gt;software goals&lt;/strong&gt;, &lt;strong&gt;requirements&lt;/strong&gt;, &lt;strong&gt;users&lt;/strong&gt;, and &lt;strong&gt;business needs&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Choose an Architecture
&lt;/h2&gt;

&lt;p&gt;Before discussing an architecture, you should discuss the &lt;strong&gt;problem&lt;/strong&gt; and understand it. You should understand &lt;em&gt;how&lt;/em&gt; the business and the users interact with the software. Most importantly, you should focus on the &lt;strong&gt;data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The data. The data. And the data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By understanding how data is created, read, and updated, you can gain deep insights into what you are trying to solve by building the software. This understanding will allow you to choose or craft the &lt;strong&gt;correct architecture&lt;/strong&gt; for your system. 💡&lt;/p&gt;




&lt;p&gt;There are many resources to get started with software architecture, such as online courses, articles, and books, but my favorite has been &lt;a href="https://www.amazon.com/Fundamentals-Software-Architecture-Comprehensive-Characteristics/dp/1492043451" rel="noopener noreferrer"&gt;Fundamentals of Software Architecture&lt;/a&gt; by &lt;strong&gt;Mark Richards&lt;/strong&gt; and &lt;strong&gt;Neal Ford&lt;/strong&gt;. (&lt;em&gt;This is not a promotion, by the way!&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;It’s a book that introduces the basics of software architecture, presents different architectures, and discusses them in depth. Software architecture is a &lt;strong&gt;vast domain&lt;/strong&gt;, but the book does a great job of getting you halfway there if you’re looking to learn more. The rest of the journey involves diving deeply into specific architectures, implementing them, and scaling them. 📚&lt;/p&gt;




&lt;p&gt;I’m currently writing an article that serves as an introduction to software architecture—a &lt;strong&gt;4,000-word guide&lt;/strong&gt; to understanding the basics and exploring the most commonly used architectures. This guide will also include links to excellent resources to continue learning.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Software Engineers Make Their Software Run Faster</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 10 Nov 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/koladev/how-software-engineers-make-their-software-run-faster-2620</link>
      <guid>https://dev.to/koladev/how-software-engineers-make-their-software-run-faster-2620</guid>
      <description>&lt;p&gt;Last week, I was assigned a task to speed up an insertion script. The program was a straightforward DAG, running daily tasks to retrieve CSV files and process them into a database.&lt;/p&gt;

&lt;p&gt;These files contain information about financial transactions, which can quickly become heavy due to the sheer number of rows—often reaching millions.&lt;/p&gt;

&lt;p&gt;The script for inserting rows into the database followed a simple flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read a row&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perform checks&lt;/strong&gt; to ensure essential data is present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attempt an insert&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log errors&lt;/strong&gt; for issues like duplication or invalid data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty simple, right? However, behind this simplicity was hiding a major issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv3s6oglzo08wzmprewe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv3s6oglzo08wzmprewe.gif" alt="snail" width="510" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The task was &lt;strong&gt;slow as HELL&lt;/strong&gt;. 🤬&lt;/p&gt;

&lt;p&gt;Processing a file with 4,000 records could take up to &lt;strong&gt;20 minutes&lt;/strong&gt;, which was far very very very from &lt;strong&gt;ideal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This was where the hunt for the culprit began.🤺&lt;/p&gt;

&lt;h3&gt;
  
  
  The Suspected Causes 🔍
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Latency?&lt;/strong&gt; No, we had other tasks running on the database, and it wasn’t experiencing unusual delays. The database server was performing well, according to usage stats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disk usage?&lt;/strong&gt; Yes, the machine's disk was under heavy usage due to large CSV files loading into memory. One solution could be processing the file in chunks rather than loading the entire file at once, which would help manage disk usage. However, this wouldn’t solve the core problem of the script’s speed.&lt;/p&gt;

&lt;p&gt;So, what was wrong?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real Problem ⚡️
&lt;/h3&gt;

&lt;p&gt;With my current knowledge, I knew that &lt;strong&gt;4,000 individual inserts in the database&lt;/strong&gt; would likely cause a bottleneck. We were looking at around &lt;strong&gt;1.78 transactions per second&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After some research, I discovered that &lt;strong&gt;batching&lt;/strong&gt; is a more efficient approach for inserting large numbers of rows. But why wasn’t it already in use?&lt;/p&gt;

&lt;p&gt;Well, batching introduces a risk: if there’s an error in one record within a batch, it can invalidate the entire batch.&lt;/p&gt;

&lt;p&gt;As it turns out, the developer that I know pretty well…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcym0xsopgpapt9i1yolw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcym0xsopgpapt9i1yolw.gif" alt="yup that was me" width="640" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…who originally wrote this script opted to perform individual inserts to avoid this risk.&lt;/p&gt;

&lt;p&gt;The problem with individual inserts is that they slow down significantly with large datasets because each insert requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Separate transactions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frequent disk I/O&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repeated index updates&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution 🛠
&lt;/h3&gt;

&lt;p&gt;To solve this, I decided to use &lt;strong&gt;batch inserts&lt;/strong&gt; with a more refined error-handling approach. I was aware of the main types of errors that might occur, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Missing consumer information&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Duplicate entries&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invalid data&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Duplicates were errors I could afford to ignore.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;missing consumer information&lt;/strong&gt; and &lt;strong&gt;invalid data&lt;/strong&gt;, I implemented a caching system. By retrieving all consumer IDs and storing them in a &lt;strong&gt;hash table&lt;/strong&gt; cache, I could check each record's consumer information before insertion, removing an unnecessary transaction check.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;invalid data&lt;/strong&gt;, I also included format validation to ensure only clean data was passed to the database, reducing the load of handling these errors.&lt;/p&gt;

&lt;p&gt;To make batch inserts resilient to errors, I used &lt;code&gt;INSERT ... ON CONFLICT DO NOTHING ... RETURNING ref&lt;/code&gt;. This way, the batch insert wouldn’t fail completely upon encountering an error, and I would still get the references of successfully inserted rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Results 🚀
&lt;/h3&gt;

&lt;p&gt;With these changes, I managed to reduce the processing time from &lt;strong&gt;20 minutes&lt;/strong&gt; for 4,000 records to an incredible &lt;strong&gt;2-3 seconds&lt;/strong&gt;. 🤯&lt;/p&gt;

&lt;p&gt;Certainly! Here’s a refined version with minimal emojis, italics, and bold elements, staying true to your content:&lt;/p&gt;

&lt;p&gt;We start by &lt;em&gt;analyzing the problem thoroughly&lt;/em&gt;, identifying likely edge cases to understand performance challenges, and tailoring optimization strategies accordingly.&lt;/p&gt;

&lt;p&gt;In my case, understanding that data from consumers could go missing and that there might be some invalid columns for certain rows meant I could perform checks without heavily involving the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, *next time, do your best to understand a problem correctly, and optimizing it will come naturally.✌️&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Do you have a story to share about an optimization you made and you were happy about? Let us know in the comments👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you’re into more content like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.email/koladev" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;for regular updates on software programming, architecture, technical writing, and other tech goodies.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>beginners</category>
      <category>database</category>
    </item>
    <item>
      <title>How to Quickly Navigate a New Codebase</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 03 Nov 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/koladev/how-to-quickly-navigate-a-new-codebase-48i9</link>
      <guid>https://dev.to/koladev/how-to-quickly-navigate-a-new-codebase-48i9</guid>
      <description>&lt;p&gt;So you've just accepted the software engineering or developer job offer?&lt;/p&gt;

&lt;p&gt;Well, first of all, &lt;em&gt;congratulations on this big milestone!&lt;/em&gt; 🎉&lt;/p&gt;

&lt;p&gt;Now your first challenge in the first weeks of the job is &lt;strong&gt;understanding the codebase.&lt;/strong&gt; How do you know the work that’s been done so you can start contributing &lt;em&gt;ASAP&lt;/em&gt;? What mistakes should you avoid? What are the right questions to ask?&lt;/p&gt;

&lt;p&gt;I’ve worked in four companies, and I’ve also consulted for others as a developer or lead developer. Through these experiences, I started noticing patterns—patterns that helped me get better at understanding codebases and contributing from day one.&lt;/p&gt;

&lt;p&gt;But hey, most of the time, life gives you your toughest battle on day one when you spend hours just trying to set up the project. Why? Because some tools aren’t compatible with your machine or some obscure configurations are nowhere in the documentation… 😅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730604007327%2F9b3405f3-856e-4839-a40f-2824775276c5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730604007327%2F9b3405f3-856e-4839-a40f-2824775276c5.webp" alt="Funny developer meme" width="291" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But let’s stay optimistic and assume the best-case scenario—let’s dive into how you can start contributing &lt;em&gt;ASAP.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell, there’s one big piece of advice: &lt;strong&gt;understand the business cases.&lt;/strong&gt; Let’s dive into it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you’re into more content like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.email/koladev" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;for regular updates on software programming, architecture, technical writing, and other tech goodies.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;How Do I Contribute to Codebases on Day One?&lt;/p&gt;

&lt;p&gt;I like to come prepared, so I usually know a good bit about the project before my first day. I already have an idea of the project’s state, and if it’s a public product, I’ve likely spotted some bugs and even thought of solutions. This prep helps me navigate issues and tickets, giving me a head start on figuring out where I can contribute.&lt;/p&gt;

&lt;p&gt;And, believe it or not, setup issues can be a blessing! If I run into problems, I ask myself: Was this a skill issue or a documentation issue? Either way, I make a point of documenting it. If I had set up struggles, chances are someone else would too.&lt;/p&gt;

&lt;p&gt;I also make it a habit to join architectural discussions. I’ve been lucky to work with companies that encourage open communication, where discussions are public and anyone can chime in with ideas or advice. This gives me an understanding of the bigger picture and lets me make meaningful contributions right away.&lt;/p&gt;

&lt;p&gt;But before diving into all that, here is the rule I always follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the Business Cases
&lt;/h2&gt;

&lt;p&gt;As a developer or software engineer, remind yourself why you’re here: &lt;em&gt;you’re writing software to solve a problem.&lt;/em&gt; In any company, these problems relate to customers or internal needs, and you’ll be implementing the &lt;strong&gt;business logic&lt;/strong&gt; of the solution through design, architecture, and code.&lt;/p&gt;

&lt;p&gt;The rule of thumb is: &lt;strong&gt;Focus on the what and the why&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Company Has Great Documentation: Docs, Tests, and Comments on Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606689576%2F5c7ba181-f0fe-49ed-909c-3298a9c2ab50.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606689576%2F5c7ba181-f0fe-49ed-909c-3298a9c2ab50.webp" alt="Hell yeah" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the company has a strong culture of documentation, you’re in luck. Whether it’s product documentation, architectural guides, or code comments, this will help you understand the business from a software perspective.&lt;/p&gt;

&lt;p&gt;What does this look like IRL?&lt;/p&gt;

&lt;p&gt;Imagine your first day at a fintech company.&lt;/p&gt;

&lt;p&gt;Fintech companies are known to use &lt;em&gt;domain-driven architectures&lt;/em&gt;. In a domain-driven setup, business cases and their software solutions are organized into domains, making it easy to work independently in one area without breaking down others.&lt;/p&gt;

&lt;p&gt;Say you’re assigned to a team managing customer wallets. To understand this part of the code, start by asking: &lt;em&gt;What’s the business goal here? What are the user stories?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In short, get to know &lt;strong&gt;WHAT&lt;/strong&gt; this part of the software does and &lt;strong&gt;WHY&lt;/strong&gt; it exists—&lt;em&gt;without diving straight into the code&lt;/em&gt;, which is the &lt;strong&gt;HOW&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Company Lacks Strong Docs but Has Tests
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606744272%2Fc3876e0f-4077-48ae-9a36-76d32ef8a761.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606744272%2Fc3876e0f-4077-48ae-9a36-76d32ef8a761.webp" alt="Hum okay" width="191" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not every company has great documentation. Sometimes, especially in fast-moving startups, documentation takes a backseat. But if there are good tests, you’ve got another way in.&lt;/p&gt;

&lt;p&gt;Well-written tests explain what different parts of the software do. They’re like mini-documentation embedded in code. &lt;strong&gt;Find the tests and read them&lt;/strong&gt;—they’ll help you understand the business cases and the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Docs, No Tests, and the Only Dev Who Knows the Codebase is Leaving
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606810135%2F3bb63ece-7658-487c-927b-bf2fcd836284.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730606810135%2F3bb63ece-7658-487c-927b-bf2fcd836284.webp" alt="Hell No" width="480" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The nightmare scenario. I used to think this was just a joke developers told to scare each other, but I’ve experienced it &lt;em&gt;twice&lt;/em&gt;. For me, it’s a red flag, but if you’re up for the challenge, here’s what you can do:&lt;/p&gt;

&lt;p&gt;Take the codebase as it is. &lt;strong&gt;Test the functions, run the app in a debugger, and even crash the code intentionally to see how it behaves.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don’t understand a portion of the code, try commenting it out or removing it temporarily to observe how the app reacts. If you’re familiar with a debugger, it’s your best friend for understanding how things work behind the scenes.&lt;/p&gt;

&lt;p&gt;No matter what situation you’re in, follow these core rules to keep making progress:&lt;/p&gt;




&lt;h2&gt;
  
  
  Ask Questions — Lots of Them
&lt;/h2&gt;

&lt;p&gt;Your first few days are the golden period for asking questions. You’re new, and everyone expects you to be a little lost. Use this time to dig into anything unclear and get the lay of the land. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The more questions you ask now, the fewer headaches you’ll have later.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don’t understand a piece of code, reach out to a peer or a senior dev. Don’t sit there feeling stuck when a quick answer could move you forward. Ask about the codebase organization, common issues, or any hidden quirks in workflows.&lt;/p&gt;

&lt;p&gt;Notice any gaps or oddities in the documentation? Point them out. The team will appreciate your initiative in understanding the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read, Read, and Then Read Some More
&lt;/h2&gt;

&lt;p&gt;In the early days, the codebase itself is your best friend. Spend time going through it line by line to understand each module and its interactions. Here’s how to tackle it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; If it exists, soak it up. Pay attention to architecture diagrams, core workflows, and explanations of common patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tests:&lt;/strong&gt; Good tests are like treasure maps—they tell you what parts of the application are supposed to do. Run them, step through them in the debugger, and let them guide you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Issues or Backlogs:&lt;/strong&gt; Check open or recently closed tickets. They reveal what the team has been working on and the current pain points. You’ll get a sense of ongoing improvements and challenges.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Don’t Be Shy About Making Small Changes
&lt;/h2&gt;

&lt;p&gt;Once you start getting a feel for the code, go ahead and make small contributions. These don’t have to be groundbreaking—small tweaks are a great way to build confidence. Look for low-hanging fruit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fix typos or add missing documentation:&lt;/strong&gt; Small but helpful ways to make your mark.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improve code comments:&lt;/strong&gt; Sometimes code is written in a rush, and a bit of clarity helps everyone.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tackle minor bugs:&lt;/strong&gt; If you spot an easy fix, mention it to your manager or tech lead. You’ll be learning &lt;em&gt;and&lt;/em&gt; making things better.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Be Patient with Yourself
&lt;/h2&gt;

&lt;p&gt;Remember, no one expects you to know it all right away. Don’t pressure yourself to master the codebase in the first week. Keep learning, keep contributing, and stay curious. &lt;/p&gt;

&lt;p&gt;Over time, you’ll find yourself moving from observer to contributor—and that’s when things start to get fun. 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In short, getting up to speed with a new codebase is a journey. &lt;strong&gt;Ask questions, read everything you can, and make small, meaningful contributions.&lt;/strong&gt; Take your time to understand not just the “how” but the “why” behind the code. With patience and curiosity, you’ll be making an impact before you know it.&lt;/p&gt;

&lt;p&gt;Now, go make that codebase yours!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
      <category>career</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Senior Software Engineers Document Their Project</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 27 Oct 2024 12:49:35 +0000</pubDate>
      <link>https://dev.to/koladev/how-senior-software-engineers-document-their-project-1nf4</link>
      <guid>https://dev.to/koladev/how-senior-software-engineers-document-their-project-1nf4</guid>
      <description>&lt;p&gt;There’s one task that software engineers hate, yet this small attention to detail is what separates a good software engineer from a bad one: &lt;strong&gt;How do they document their project?📝&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few years ago, I was responsible for setting up a fintech project. Because we decided to move quickly, planning for scalability wasn’t a priority. Our focus was on validating the idea, so we pushed forward, creating APIs, architectures, and systems with simple solutions, not overly concerned about the future.&lt;/p&gt;

&lt;p&gt;However, as the person in charge of the backend and infrastructure, I knew that while my memory was reliable, it wouldn’t be enough to recall all the details six months down the line.&lt;/p&gt;

&lt;p&gt;In my research, I discovered a convention I liked: &lt;strong&gt;ADR&lt;/strong&gt;, or &lt;strong&gt;Architectural Decision Record&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5qxoe2oi753u33y3jat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5qxoe2oi753u33y3jat.png" alt="ADR of the fintech API" width="721" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s essentially a document that traces all changes made to an architecture: the change itself, its impact, and what we learned from it.&lt;/p&gt;

&lt;p&gt;Think of it as a personal journal but for the team.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are interested in more content covering topics like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.email/koladev" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;for regular updates on software programming, architecture, technical writing, and tech-related insights.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why is it important?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Humans forget:&lt;/strong&gt; Documenting changes helps us because we easily forget the reasons behind choosing one architecture over another.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It makes the team better:&lt;/strong&gt; Let’s say you’ve tried various solutions for an issue and documented the successes and failures. You learn from it, and others can too, even developers who come in after you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Future developers will thank you:&lt;/strong&gt; Imagine a dev coming to a codebase and trying to understand why a change was made five years ago. Somewhere, a developer is likely struggling with this because the previous engineer left without documenting it, and they’re not thrilled. Meanwhile, in another company, a developer finds an ADR explaining those changes, and they’re incredibly grateful.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How do you write one then?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There are several conventions to follow, but you can always adapt them to what works best for you.&lt;/p&gt;

&lt;p&gt;The convention that inspired me is here: &lt;a href="https://adr.github.io/madr/" rel="noopener noreferrer"&gt;https://adr.github.io/madr/&lt;/a&gt;. You can also check Amazon’s ADR process here: &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of a template you can use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Example Title: Database Choice for User Data&lt;/span&gt;

&lt;span class="gu"&gt;## Context and Problem Statement&lt;/span&gt;

We need a scalable database to store and manage user data efficiently as our user base grows.

&lt;span class="gu"&gt;## Decision Drivers&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Scalability
&lt;span class="p"&gt;*&lt;/span&gt; Data consistency
&lt;span class="p"&gt;*&lt;/span&gt; Ease of integration with existing services

&lt;span class="gu"&gt;## Considered Options&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; PostgreSQL
&lt;span class="p"&gt;*&lt;/span&gt; MongoDB
&lt;span class="p"&gt;*&lt;/span&gt; Amazon DynamoDB

&lt;span class="gu"&gt;## Decision Outcome&lt;/span&gt;

Chosen option: &lt;span class="gs"&gt;**PostgreSQL**&lt;/span&gt; because it provides strong data consistency and aligns well with our need for complex queries.

&lt;span class="gu"&gt;### Consequences&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; &lt;span class="gs"&gt;**Good:**&lt;/span&gt; Supports ACID compliance, enhancing data reliability.
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**Bad:**&lt;/span&gt; May require more tuning to achieve high performance with large datasets.

&lt;span class="gu"&gt;### Confirmation&lt;/span&gt;

We’ll confirm this decision through periodic load tests and performance reviews as the user base scales.

&lt;span class="gu"&gt;## Pros and Cons of the Options&lt;/span&gt;

&lt;span class="gu"&gt;### PostgreSQL&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; &lt;span class="gs"&gt;**Good:**&lt;/span&gt; ACID compliance, robust community support.
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**Neutral:**&lt;/span&gt; Setup and tuning can be time-consuming.
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**Bad:**&lt;/span&gt; Lacks native horizontal scaling.

&lt;span class="gu"&gt;### MongoDB&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; &lt;span class="gs"&gt;**Good:**&lt;/span&gt; Schema flexibility, horizontal scaling.
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**Bad:**&lt;/span&gt; No ACID compliance across collections, limiting data integrity.

&lt;span class="gu"&gt;## More Information&lt;/span&gt;

For additional details, see the database performance evaluation &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;here&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;link-to-evaluation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of document can be present within the project repository, or a notion, or JIRA.&lt;/p&gt;

&lt;p&gt;In my last company, where I worked as a frontend engineer, we didn’t have a single document for all architectural changes.&lt;/p&gt;

&lt;p&gt;Using GitLab issues and linking every change to an issue branch helped us track the reasons behind changes, even months after implementation.&lt;/p&gt;

&lt;p&gt;This practice saved us countless times. As I always say, no matter how smart you or your teammates are—your CTO, manager, or anyone involved in the project—they won’t remember every technical decision made two years ago.&lt;/p&gt;

&lt;p&gt;Unless, of course, you’re working with 10x engineers. 😆&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds6jk9itufkc29d1vf3w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds6jk9itufkc29d1vf3w.gif" width="220" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that’s it for this article. We have discussed how companies and tech team leaders use ADRs to document architectural decisions on their projects and how much it helps them, teammates, or even the people who worked there after they left.&lt;/p&gt;

&lt;p&gt;If you have experiences to share or any thoughts on the article, feel free to drop them in the comments below.&lt;/p&gt;

&lt;p&gt;I’m always open to feedback and happy to engage in discussions that can help us all learn and grow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>learning</category>
      <category>documentation</category>
    </item>
    <item>
      <title>How to Choose the Ideal Database for Your App: Prototypes, App at Scale, and Event-Driven App</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 13 Oct 2024 13:35:03 +0000</pubDate>
      <link>https://dev.to/koladev/how-to-choose-the-ideal-database-for-your-app-prototypes-app-at-scale-and-event-driven-app-2jhj</link>
      <guid>https://dev.to/koladev/how-to-choose-the-ideal-database-for-your-app-prototypes-app-at-scale-and-event-driven-app-2jhj</guid>
      <description>&lt;p&gt;Storing data is something humans have been doing for thousands of years.&lt;/p&gt;

&lt;p&gt;From carving information on rocks to developing language, writing on paper, and eventually storing data on disks, it’s an essential part of how we preserve and share knowledge.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But enough of the history lesson—if you're a developer, whether beginner, intermediate, or expert, you've likely encountered SQL and NoSQL databases, even if you didn't realize it at the time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, how do you make a wise choice when it’s time to develop an application? Are you starting a new project from scratch? Is it an integration into an existing system? Are you working on a project that needs structured data and integrity? Or maybe you're developing an event-driven application?&lt;/p&gt;

&lt;p&gt;There are plenty of use cases to consider when choosing the right database for your application. For the sake of simplicity, we’ll focus on three common types of applications and the best database options for each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Small-scale or prototype applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Applications needing data integrity and robustness&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Event-driven applications&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Small-Scale or Prototype Applications
&lt;/h2&gt;

&lt;p&gt;If you're building an MVP or testing an idea, you'll likely understand the importance of making a quick prototype to validate your concept before committing fully. &lt;strong&gt;Speed&lt;/strong&gt; is crucial at this stage, and the same applies to how you handle data storage. Here are two common challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You need a simple database with a minimal setup that can be easily moved around without complex configuration—after all, you're just trying to validate an idea.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You’re unsure about the structure of your data, and you want flexibility for evolving fields without worrying about strict data types or rigid schemas.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Personal Recommendations
&lt;/h3&gt;

&lt;p&gt;For the first case, I recommend &lt;a href="https://www.sqlite.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/a&gt;. It’s a simple, file-based storage solution that doesn’t require setting up a server. All data is stored in a file, making it perfect for lightweight applications that need quick deployment.&lt;/p&gt;

&lt;p&gt;You’ll often find SQLite in embedded systems and mobile apps because it’s fast, easy to use, and doesn’t require much configuration. Despite its simplicity, SQLite can handle a surprising amount of data, making it a solid choice for early-stage projects.&lt;/p&gt;

&lt;p&gt;In the second case, &lt;a href="https://www.mongodb.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;&lt;/a&gt; is an excellent choice, especially if you’re unsure about how your data will evolve. MongoDB is schema-less, allowing you to store and modify data without worrying about rigid structures upfront.&lt;/p&gt;

&lt;p&gt;It’s easy to set up and works well for both small-scale prototypes and larger applications. That said, MongoDB has its trade-offs—at scale, you may run into performance challenges, and its lack of strict data constraints can lead to inconsistent or unstructured data. However, MongoDB’s flexibility is often worth the trade-off for a prototype.&lt;/p&gt;

&lt;p&gt;In addition to SQLite and MongoDB, you might also want to explore other powerful tools for rapid prototyping, such as &lt;a href="https://github.com/google/leveldb" rel="noopener noreferrer"&gt;&lt;strong&gt;LevelDB&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://www.couchbase.com/products/lite" rel="noopener noreferrer"&gt;&lt;strong&gt;Couchbase Lite&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://firebase.google.com/products/realtime-database" rel="noopener noreferrer"&gt;&lt;strong&gt;Firebase Realtime Database&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Supabase&lt;/strong&gt;&lt;/a&gt;. These databases offer unique strengths like fast key-value storage, offline-first capabilities, real-time data syncing, and easy-to-use SQL features, making them excellent choices depending on your project’s specific needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;During the prototyping phase, the focus should be on speed and flexibility rather than strict data integrity or performance optimization.&lt;/em&gt; Once your prototype is validated, you can revisit your database decisions as you move into more structured and large-scale development phases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This brings us to the next step: building applications that require &lt;strong&gt;data integrity&lt;/strong&gt; and &lt;strong&gt;scalability&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Applications Needing Data Integrity and Robustness
&lt;/h2&gt;

&lt;p&gt;As your project moves beyond the initial stages and becomes a more critical system, the need for &lt;strong&gt;data consistency&lt;/strong&gt;, &lt;strong&gt;integrity&lt;/strong&gt;, and &lt;strong&gt;scalability&lt;/strong&gt; becomes essential. Whether you’re managing sensitive information or developing a business application with complex data relationships, your database choice now needs to support strict data management practices. At this point, two common scenarios come into play:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You have a clear understanding of your data structure and require a database that ensures &lt;strong&gt;data integrity&lt;/strong&gt;, &lt;strong&gt;consistency&lt;/strong&gt;, and &lt;strong&gt;complex querying&lt;/strong&gt; capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your application is growing in complexity, and while you still need flexibility, you also need the ability to scale while handling large amounts of unstructured or semi-structured data.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Personal Recommendations
&lt;/h3&gt;

&lt;p&gt;For the first case, &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/a&gt; is an excellent choice. It’s a robust, open-source SQL database known for its ACID compliance, meaning it guarantees reliable transaction processing. PostgreSQL also excels in handling structured data, supports complex queries, and offers full-text search capabilities.&lt;/p&gt;

&lt;p&gt;It is ideal for applications that require strict data integrity and need to process large volumes of data reliably. Additionally, its support for JSON allows flexibility with semi-structured data, making PostgreSQL a versatile tool for growing projects.&lt;/p&gt;

&lt;p&gt;In the second case, &lt;strong&gt;MongoDB&lt;/strong&gt; continues to be a strong contender, particularly for applications handling big data or evolving data models. While often used in early-stage projects for its schema-less design, MongoDB can scale horizontally to manage vast datasets across multiple servers.&lt;/p&gt;

&lt;p&gt;It is widely used by large-scale companies like Uber and Toyota, which rely on its ability to handle unstructured data and adapt to changing requirements. That said, as your application grows, you may need to carefully manage MongoDB’s performance and data consistency, especially if you’re dealing with highly critical data.&lt;/p&gt;

&lt;p&gt;While PostgreSQL and MongoDB are popular choices, there are other SQL and NoSQL databases worth considering for applications needing robust data integrity and scalability. &lt;a href="https://mariadb.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;MariaDB&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://www.oracle.com/database/" rel="noopener noreferrer"&gt;&lt;strong&gt;Oracle SQL&lt;/strong&gt;&lt;/a&gt; are both highly regarded for their performance in enterprise-level systems.&lt;/p&gt;

&lt;p&gt;MariaDB offers great concurrency control and is widely adopted for its high availability, while Oracle SQL is known for handling mission-critical workloads with reliability and efficiency. On the NoSQL side, &lt;a href="https://cassandra.apache.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/a&gt; is another powerful option, designed for large, distributed systems where fault tolerance and horizontal scaling are paramount. Companies like Netflix and eBay use Cassandra for its ability to handle massive amounts of data across geographically distributed clusters.&lt;/p&gt;

&lt;p&gt;In addition to PostgreSQL, MongoDB, and other large-scale databases, tools like &lt;a href="https://cassandra.apache.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://www.couchbase.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Couchbase&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://mariadb.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;MariaDB&lt;/strong&gt;&lt;/a&gt; offer tailored solutions depending on the needs of your application. Each database has strengths that make it a good fit for high-traffic, data-intensive applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;As your application continues to grow and evolve, the decision between SQL and NoSQL will depend on the type of data you're managing and your specific scalability needs.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the next step, we’ll dive into a different use case: applications that are &lt;strong&gt;event-driven and require real-time data processing&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Event-Driven Applications
&lt;/h2&gt;

&lt;p&gt;So far, we’ve talked about small-scale and prototype applications, as well as those requiring data integrity. But another major category that’s increasingly popular in today’s tech landscape is &lt;a href="https://www.techtarget.com/searchitoperations/definition/event-driven-application" rel="noopener noreferrer"&gt;&lt;strong&gt;event-driven applications&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Whether it’s real-time notifications, WebSockets, or IoT systems, event-driven architectures are everywhere. These types of applications rely on responding to events as they happen, often in real-time, which is crucial for things like stock trading platforms, real-time analytics, and messaging services.&lt;/p&gt;

&lt;p&gt;For event-driven systems, the challenge is not just in processing the data but in doing so at scale, with high-speed delivery and reliability. To handle these demands, you need a combination of tools designed for fast data access, real-time streaming, and reliable storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal Recommendations
&lt;/h3&gt;

&lt;p&gt;For real-time data handling, &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/a&gt; is an ideal tool. Redis is an in-memory data store, meaning it’s incredibly fast, making it perfect for caching and managing high-speed data flows.&lt;/p&gt;

&lt;p&gt;In an event-driven application, Redis can serve as a temporary, fast-access storage for real-time data that needs to be processed and delivered quickly to multiple clients. For example, in a stock trading platform, Redis can store the latest stock prices, which need to be retrieved in milliseconds to update dashboards or send alerts to users.&lt;/p&gt;

&lt;p&gt;When it comes to managing data streams, &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/a&gt; are excellent choices. Both are messaging systems that handle real-time data pipelines, allowing you to distribute data to multiple listeners as soon as events occur.&lt;/p&gt;

&lt;p&gt;For instance, in a trading system, data on market transactions can be streamed through Kafka, ensuring that updates are distributed to various services, such as those that handle client notifications or analytics processing.&lt;/p&gt;

&lt;p&gt;But in an event-driven architecture, fast data access and streaming alone aren't enough—you also need to persist the data for long-term storage. This is where databases like &lt;strong&gt;MongoDB&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;MongoDB, with its schema-less design and scalability, can store event data over time, making it available for future queries or analysis. In combination with Redis and Kafka, MongoDB ensures that your system can handle both real-time data and long-term persistence without sacrificing performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Use Case
&lt;/h3&gt;

&lt;p&gt;Let’s consider a trading system as a use case to see how these tools can work together. In such a system, market data needs to be ingested, processed, and delivered to users as quickly as possible. Here’s how it might work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt; stores the real-time price updates for stocks, allowing the application to retrieve this data in milliseconds and send it to clients via WebSockets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kafka&lt;/strong&gt; manages the flow of data from external sources, streaming market data into the system and distributing it to different services, such as pricing engines, notification systems, and analytics modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; stores all the historical transaction data, allowing traders to access past information for analysis or reporting.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzsy819r8g30wsdu6yhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzsy819r8g30wsdu6yhm.png" alt="Trading App System Architecture" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By combining these tools, you can build an event-driven system that handles large volumes of real-time data while ensuring fast access and reliable storage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach allows you to scale effortlessly, maintaining high performance even as the number of users and the amount of data grow.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Thoughts
&lt;/h2&gt;

&lt;p&gt;At this point, I think we’ve covered some of the most common tools that can be used for a wide range of applications you might encounter in your journey as a developer. Naturally, different systems and applications will call for different solutions, and the databases we've discussed are just a few examples.&lt;/p&gt;

&lt;p&gt;So, I encourage you to continue your research, dig deeper, and explore other tools that may be a perfect fit for your specific needs.&lt;/p&gt;

&lt;p&gt;However, it's important to remember that none of this is set in stone. These recommendations aren’t meant to be absolute truths or universal solutions. &lt;strong&gt;The key is choosing the right tools for &lt;em&gt;your&lt;/em&gt; project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you're working on a small-scale application and you feel confident about using something like PostgreSQL to validate your idea, go for it! Just keep in mind the potential technical debt that might come with overengineering early on. Similarly, if you’re building an event-driven system and decide to rely on a traditional database for real-time data storage, that can be a viable choice—&lt;a href="https://www.timescale.com/learn/real-time-analytics-in-postgres" rel="noopener noreferrer"&gt;just be aware of the trade-offs that come with that decision&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;At the end of the day, it's all about finding the right balance for your system.&lt;/em&gt; Always research thoroughly, talk to people who have used these tools in the field, and seek advice from others in your industry. Understand how these technologies fit into your project and what works best for your particular needs.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;Thank you for reading! In this article, we’ve explored different databases suited for various types of applications, from small-scale prototypes to data-heavy, event-driven systems.&lt;/p&gt;

&lt;p&gt;If you have experiences to share or any thoughts on the article, feel free to drop them in the comments below.&lt;/p&gt;

&lt;p&gt;I’m always open to feedback and happy to engage in discussions that can help us all learn and grow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my&lt;/em&gt; &lt;a href="https://buttondown.com/koladev" rel="noopener noreferrer"&gt;&lt;em&gt;newsletter&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>database</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Talk to Non-Developers?</title>
      <dc:creator>Mangabo Kolawole</dc:creator>
      <pubDate>Sun, 06 Oct 2024 06:13:08 +0000</pubDate>
      <link>https://dev.to/koladev/how-to-talk-to-non-developers-1501</link>
      <guid>https://dev.to/koladev/how-to-talk-to-non-developers-1501</guid>
      <description>&lt;p&gt;Let’s face it—being a developer isn’t just about writing flawless code. It’s about &lt;strong&gt;collaboration&lt;/strong&gt;. But here’s the harsh truth: &lt;strong&gt;most developers suck at communicating with non-developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What happens when you’re trying to explain something to designers, QA testers, project managers, or marketing professionals? How many times have you seen blank stares or heard the dreaded, “I don’t get it”?&lt;/p&gt;

&lt;p&gt;It's not entirely their fault, nor yours, but you can make some efforts to make the communication clear.&lt;/p&gt;

&lt;p&gt;In today's article, explore some principles for communicating with non-developers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Personal Story
&lt;/h3&gt;

&lt;p&gt;In 2020, I worked at my first startup. In the beginning, the team was made up entirely of developers, all working hard to create the MVP.&lt;/p&gt;

&lt;p&gt;Two months before the product launch, our first non-technical teammate joined: a marketer.&lt;/p&gt;

&lt;p&gt;In a startup, &lt;strong&gt;understanding the product is crucial&lt;/strong&gt;. You might find yourself involved in areas that don’t directly relate to your job.&lt;/p&gt;

&lt;p&gt;One day you’re coding, and the next you’re learning about marketing strategies because the founders want your input. That’s why working in a startup is so rewarding—you get to learn a lot.&lt;/p&gt;

&lt;p&gt;Our marketer felt the same way. As she got more familiar with the product, she started making suggestions. But when it came time to implement some complex features, she asked me the toughest question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ari:&lt;/strong&gt; "Why?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; "Our WebSocket engine can’t handle that many requests. It’s complicated."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hnc8fm27sb3uyea1p7x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hnc8fm27sb3uyea1p7x.gif" width="480" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Her confusion was clear. That’s when I realized I needed to explain things in a simpler, clearer way. Thankfully, a more experienced developer stepped in with a better response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Him:&lt;/strong&gt; "We have a messaging system that sends notifications to consumers, developers, and riders. Right now, it’s not stable enough to add more recipients. But we could improve things by sending push notifications and listing orders directly in the app, instead of waiting for notifications to show up. What do you think?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I loved that answer because it gave me a blueprint for how to communicate with non-technical people:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep the language simple.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forget the technical details; focus on the requirements.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be patient and open to collaboration.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Another colleague of mine—a very technical person—learned a similar lesson. He was the classic “geeky” developer shown in movies and TV shows, always buried in code. In his first few months with us, he had to adjust one major habit: &lt;strong&gt;speaking in technical jargon&lt;/strong&gt; to the manager.&lt;/p&gt;

&lt;p&gt;He was a mobile developer, rewriting our app from React Native to Flutter. One day, when he was behind on an implementation, the manager asked why.&lt;/p&gt;

&lt;p&gt;Instead of giving a simple, abstract explanation, he dove into details about classes, proxies, and components. As a backend engineer with no knowledge of Flutter architecture, even I was confused. So, you can imagine how lost the manager was.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qvj2rzucngnq8ex254z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qvj2rzucngnq8ex254z.gif" width="426" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, another team member stepped in to save the day. He explained the situation without going too deep into technicalities:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Coworker:&lt;/strong&gt; "Flutter works differently from what we’ve used before. We assumed a part of the implementation would be the same, but there’s no support for it, so we have to write our own solution. That’s why it’s taking time. We can have it ready by [new date]. Does that sound okay?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He kept things simple, avoided unnecessary technical details, and &lt;strong&gt;shifted the focus to the requirements&lt;/strong&gt;. He also asked for feedback, which opened the door to collaboration. This made the conversation smoother and more productive.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Takeaway
&lt;/h3&gt;

&lt;p&gt;Being &lt;strong&gt;simple and abstract&lt;/strong&gt; is key when communicating with non-developers. They don’t need to know the technical complexities behind every issue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sharing too much technical detail can make the problem seem more complicated than it is, which might create unnecessary anxiety.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Simplicity is crucial&lt;/strong&gt;—start with an abstract explanation, and if they ask for more details, you can go deeper.&lt;/p&gt;

&lt;p&gt;Redirect the conversation to the &lt;strong&gt;requirements&lt;/strong&gt; and offer solutions or timelines when possible. This helps keep the focus on what matters most to non-technical teammates.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;always invite input&lt;/strong&gt;. Asking for their thoughts encourages discussion and fosters better collaboration.&lt;/p&gt;

&lt;p&gt;At the end of the day, it's not about proving technical expertise—it’s about ensuring that the team can work together to &lt;strong&gt;achieve the same goal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Share your experience in the comments below, ask any questions you have, and don’t forget to share this article with your network if you found it helpful.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this article and want more insights like this, subscribe to my &lt;a href="https://buttondown.com/koladev" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt; for weekly tips, tutorials, and stories delivered straight to your inbox!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
