<?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: Amirsaeed S Komjani</title>
    <description>The latest articles on DEV Community by Amirsaeed S Komjani (@amirsaeed_skomjani).</description>
    <link>https://dev.to/amirsaeed_skomjani</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%2F3437665%2F1642c12b-b1ba-4fe6-b4db-5e02bb4c8d13.jpeg</url>
      <title>DEV Community: Amirsaeed S Komjani</title>
      <link>https://dev.to/amirsaeed_skomjani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amirsaeed_skomjani"/>
    <language>en</language>
    <item>
      <title>10,000 Users. One Live Price. How Stale Is Too Stale?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Wed, 02 Sep 2026 08:44:22 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/10000-users-one-live-price-how-stale-is-too-stale-3jh9</link>
      <guid>https://dev.to/amirsaeed_skomjani/10000-users-one-live-price-how-stale-is-too-stale-3jh9</guid>
      <description>&lt;p&gt;Imagine you are building a platform where users can buy and sell gold, silver, commodities, or crypto.&lt;/p&gt;

&lt;p&gt;At first, everything looks fine. The system is responsive, the APIs are fast enough, and the database seems perfectly capable of handling the traffic. Then the number of users starts growing.&lt;/p&gt;

&lt;p&gt;Now a few thousand people are looking at the same market at almost the same time. Prices need to stay fresh, balances need to remain accurate, orders should not be placed against outdated data, and charts are constantly refreshing in the background.&lt;/p&gt;

&lt;p&gt;At this point, a very simple problem starts becoming expensive: the system keeps doing work it has already done.&lt;/p&gt;

&lt;p&gt;The same price is requested again. The same calculation runs again. The same query reaches the database again. The same downstream service is called again, even though the answer may not have changed at all.&lt;/p&gt;

&lt;p&gt;This is usually the moment when caching enters the conversation.&lt;/p&gt;

&lt;p&gt;And very often the first suggestion is something like: “Let’s put Redis in front of it.”&lt;/p&gt;

&lt;p&gt;That may help, but it does not really answer the important question.&lt;/p&gt;

&lt;p&gt;The real question is: &lt;strong&gt;which data are we actually allowed to cache?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A live gold price for two seconds may be acceptable in one system and completely unacceptable in another. An order book may tolerate only a fraction of a second. A product description can probably remain stale for several minutes without anyone noticing.&lt;/p&gt;

&lt;p&gt;But what about a user’s available balance?&lt;/p&gt;

&lt;p&gt;What about available credit?&lt;/p&gt;

&lt;p&gt;What about a price used to execute a financial transaction?&lt;/p&gt;

&lt;p&gt;If a user completes a trade based on data that is only a few seconds old, are we still dealing with a performance issue, or have we created a business problem?&lt;/p&gt;

&lt;p&gt;This is where I think caching becomes much more interesting than it first appears.&lt;/p&gt;

&lt;p&gt;The same problem exists in large e-commerce platforms. Thousands of users may open the same product page, and most of what they need is identical: the title, description, images, category information, and product specifications.&lt;/p&gt;

&lt;p&gt;There is no good reason to rebuild all of that from scratch for every request.&lt;/p&gt;

&lt;p&gt;But stock, price, discount, and availability are different. They may be changing while users are looking at the page.&lt;/p&gt;

&lt;p&gt;If you cache nothing, your infrastructure repeatedly performs work that could have been avoided.&lt;/p&gt;

&lt;p&gt;If you cache everything, you may show a product as available when it is already sold out, display an expired discount, or return financial information that is no longer correct.&lt;/p&gt;

&lt;p&gt;That is the point where caching stops being a simple performance optimization and becomes an architectural decision.&lt;/p&gt;

&lt;p&gt;And the problem is much bigger than Redis.&lt;/p&gt;

&lt;p&gt;A browser can cache. A CDN can cache. A reverse proxy can cache. The frontend can avoid duplicate requests and reuse already-fetched data. The application can cache expensive calculations, query results, or responses from external services.&lt;/p&gt;

&lt;p&gt;Every layer gives you an opportunity to reduce unnecessary work.&lt;/p&gt;

&lt;p&gt;But every layer can also create another version of your system’s state that may no longer match reality.&lt;/p&gt;

&lt;p&gt;That trade-off is the part I think is often underestimated.&lt;/p&gt;

&lt;p&gt;Writing &lt;code&gt;Cache::remember()&lt;/code&gt;&lt;br&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%2Fptfom694dgxsszyffyg9.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%2Fptfom694dgxsszyffyg9.PNG" alt=" " width="800" height="450"&gt;&lt;/a&gt; is easy.&lt;/p&gt;

&lt;p&gt;Deciding what deserves to be cached, where that cache should live, how long the data may remain stale, and who is responsible for invalidating it is much harder.&lt;/p&gt;

&lt;p&gt;TTL is not really an architecture either.&lt;/p&gt;

&lt;p&gt;Setting a value to expire after 60 seconds sounds simple, but what happens if the underlying data changes one second after it was cached? Are we comfortable serving outdated information for another 59 seconds?&lt;/p&gt;

&lt;p&gt;Sometimes the answer is yes.&lt;/p&gt;

&lt;p&gt;Sometimes it absolutely is not.&lt;/p&gt;

&lt;p&gt;And this decision usually has less to do with the caching technology itself and more to do with the meaning of the data.&lt;/p&gt;

&lt;p&gt;A product catalogue may tolerate 30 seconds of stale information without any meaningful business impact. A dashboard may tolerate a few minutes. A live market price may tolerate only a few seconds.&lt;/p&gt;

&lt;p&gt;A balance or credit limit may tolerate almost none.&lt;/p&gt;

&lt;p&gt;Once you reach this point, the conversation is no longer only about response times.&lt;/p&gt;

&lt;p&gt;It is about consistency, business semantics, and risk.&lt;/p&gt;

&lt;p&gt;There is another problem that tends to appear only when traffic becomes large enough: cache misses can become a performance problem themselves.&lt;/p&gt;

&lt;p&gt;Imagine that a heavily requested value expires while thousands of users are asking for it. Suddenly, a large number of requests may hit the database or pricing service at almost exactly the same time, all trying to rebuild the same cached value.&lt;/p&gt;

&lt;p&gt;The cache that was supposed to protect your system can temporarily create a spike against the very service it was meant to protect.&lt;/p&gt;

&lt;p&gt;This is where techniques such as request coalescing, background refresh, stale-while-revalidate, distributed locks, or jittered expiration times become useful.&lt;/p&gt;

&lt;p&gt;But again, I do not think the important lesson is the list of techniques.&lt;/p&gt;

&lt;p&gt;The important lesson is that caching introduces its own failure modes.&lt;/p&gt;

&lt;p&gt;More caching does not automatically mean more scalability.&lt;/p&gt;

&lt;p&gt;The same applies on the frontend.&lt;/p&gt;

&lt;p&gt;Modern applications can easily generate unnecessary traffic through repeated fetching, polling, tab changes, component remounting, or multiple parts of the interface asking for the same resource independently.&lt;/p&gt;

&lt;p&gt;It is very easy to solve one backend bottleneck while leaving the frontend constantly recreating it.&lt;/p&gt;

&lt;p&gt;This is why I do not see caching as a backend-only concern.&lt;/p&gt;

&lt;p&gt;It is a system-wide decision.&lt;/p&gt;

&lt;p&gt;The browser, frontend, CDN, application layer, and database may all participate in the caching strategy, but they should not all make that decision independently.&lt;/p&gt;

&lt;p&gt;At some point, someone needs to define what the source of truth is and how much distance from that truth each layer is allowed to have.&lt;/p&gt;

&lt;p&gt;That is probably the biggest change in how I think about caching.&lt;/p&gt;

&lt;p&gt;At the beginning of a developer’s career, caching often looks like a framework feature. Later, it becomes a performance tool.&lt;/p&gt;

&lt;p&gt;But once you deal with real scale, the question changes.&lt;/p&gt;

&lt;p&gt;It is no longer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should we cache this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which parts of our system’s reality are allowed to be outdated, and for how long?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And once you phrase the problem that way, many caching decisions suddenly become business decisions rather than purely technical ones.&lt;/p&gt;

&lt;p&gt;A stale product description is probably harmless.&lt;/p&gt;

&lt;p&gt;A stale balance may not be.&lt;/p&gt;

&lt;p&gt;A stale market price might be acceptable for a chart but unacceptable for transaction execution.&lt;/p&gt;

&lt;p&gt;The data can be identical, but the context in which it is used completely changes the risk.&lt;/p&gt;

&lt;p&gt;This is also why I do not believe every early-stage product needs a sophisticated caching architecture from day one.&lt;/p&gt;

&lt;p&gt;That would often be unnecessary complexity.&lt;/p&gt;

&lt;p&gt;But there is a big difference between prematurely caching everything and understanding early which parts of the system may eventually require explicit freshness and consistency rules.&lt;/p&gt;

&lt;p&gt;Waiting until the first serious performance crisis usually means these decisions are made under pressure.&lt;/p&gt;

&lt;p&gt;And under pressure, the solution often becomes something like:&lt;/p&gt;

&lt;p&gt;“Put it in Redis for 60 seconds and we’ll fix it later.”&lt;/p&gt;

&lt;p&gt;Sometimes that works.&lt;/p&gt;

&lt;p&gt;Sometimes it simply moves the problem from performance to consistency.&lt;/p&gt;

&lt;p&gt;For me, the more interesting question is not whether a system should use caching.&lt;/p&gt;

&lt;p&gt;It is when caching should stop being an implementation detail and become an explicit architectural decision.&lt;/p&gt;

&lt;p&gt;I’m curious to hear from CTOs and engineers who have dealt with real scale:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At what point in a product’s growth should caching become an explicit architectural decision, rather than something added after the first performance crisis?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>performance</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why Do So Many Teams Fail at Testing?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Fri, 12 Dec 2025 10:12:13 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/why-do-so-many-teams-fail-at-testing-399n</link>
      <guid>https://dev.to/amirsaeed_skomjani/why-do-so-many-teams-fail-at-testing-399n</guid>
      <description>&lt;h2&gt;
  
  
  Why Do So Many Teams Fail at Testing?
&lt;/h2&gt;

&lt;p&gt;Almost every team starts with the same optimism.&lt;/p&gt;

&lt;p&gt;At the beginning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TDD is declared “the right way”&lt;/li&gt;
&lt;li&gt;“Code without tests equals bugs” becomes a mantra&lt;/li&gt;
&lt;li&gt;Frameworks, runners, and pipelines are set up with care&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything looks mature and professional.&lt;/p&gt;

&lt;p&gt;Then a few months pass.&lt;/p&gt;

&lt;p&gt;Reality slowly shows up.&lt;/p&gt;

&lt;p&gt;Tests become painfully slow.&lt;br&gt;&lt;br&gt;
A small change breaks dozens of unrelated tests.&lt;br&gt;&lt;br&gt;
No one has time to refactor the test suite.&lt;br&gt;&lt;br&gt;
Test debt grows quietly.&lt;br&gt;&lt;br&gt;
Deadlines arrive, and management pressure increases: &lt;em&gt;“Ship first, fix later.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At that point, tests stop being a safety net.&lt;br&gt;&lt;br&gt;
They turn into a burden.&lt;/p&gt;

&lt;p&gt;Teams either abandon them entirely or keep them just to satisfy metrics.&lt;br&gt;&lt;br&gt;
Coverage numbers look fine, but confidence is gone.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Uncomfortable Truth About TDD
&lt;/h2&gt;

&lt;p&gt;Here is the controversial part.&lt;/p&gt;

&lt;p&gt;Classic TDD does not always work.&lt;/p&gt;

&lt;p&gt;Many teams adopt it with enthusiasm, but without the conditions it actually requires.&lt;br&gt;&lt;br&gt;
Velocity drops.&lt;br&gt;&lt;br&gt;
Deadlines get tighter.&lt;br&gt;&lt;br&gt;
And eventually, even the important tests stop being written.&lt;/p&gt;

&lt;p&gt;TDD works best when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The domain is well understood&lt;/li&gt;
&lt;li&gt;Uncertainty is low&lt;/li&gt;
&lt;li&gt;Discipline is consistently high&lt;/li&gt;
&lt;li&gt;The team treats tests as first-class code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most real-world projects do not meet these conditions.&lt;/p&gt;

&lt;p&gt;Requirements change.&lt;br&gt;&lt;br&gt;
Architecture evolves.&lt;br&gt;&lt;br&gt;
Time is limited.&lt;/p&gt;

&lt;p&gt;In those environments, strict TDD often creates more friction than value.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem Is Not Testing — It’s How We Think About It
&lt;/h2&gt;

&lt;p&gt;Tests are often treated as a ritual, not as software.&lt;/p&gt;

&lt;p&gt;But tests &lt;em&gt;are&lt;/em&gt; software.&lt;/p&gt;

&lt;p&gt;They have architecture.&lt;br&gt;&lt;br&gt;
They need maintenance.&lt;br&gt;&lt;br&gt;
They create coupling.&lt;br&gt;&lt;br&gt;
They accumulate debt.&lt;/p&gt;

&lt;p&gt;High coverage without meaningful assertions creates a false sense of security.&lt;br&gt;&lt;br&gt;
A thousand fragile tests are worse than ten reliable ones.&lt;/p&gt;

&lt;p&gt;If a test does not protect a business rule, a critical workflow, or a risky integration,&lt;br&gt;&lt;br&gt;
its value should be questioned.&lt;/p&gt;




&lt;h2&gt;
  
  
  A More Pragmatic Approach
&lt;/h2&gt;

&lt;p&gt;In practice, many teams succeed with a different mindset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design for testability first, not test-first by default&lt;/li&gt;
&lt;li&gt;Write tests after the design is clear enough to be stable&lt;/li&gt;
&lt;li&gt;Focus on boundaries: core logic, integrations, critical paths&lt;/li&gt;
&lt;li&gt;Accept that not everything deserves a test&lt;/li&gt;
&lt;li&gt;Measure confidence, not coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A mix of test-after and thoughtful design often produces more resilient systems than rigid dogma.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Testing is not about purity.&lt;br&gt;&lt;br&gt;
It is about trust.&lt;/p&gt;

&lt;p&gt;If your test suite slows you down, breaks constantly, or no longer gives confidence,&lt;br&gt;&lt;br&gt;
the problem is not a lack of discipline.&lt;br&gt;&lt;br&gt;
It is a lack of architectural thinking applied to tests.&lt;/p&gt;

&lt;p&gt;Sometimes, fewer tests — designed better — protect a system far more than perfect coverage ever could.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What has been your experience?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Does TDD genuinely help your team, or only under very specific conditions?&lt;br&gt;&lt;br&gt;
When deadlines hit, are tests part of the Definition of Done — or the first thing sacrificed?&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tdd</category>
      <category>architecture</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>From Framework Lock-in to Building Our Own ORM</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Sat, 08 Nov 2025 10:30:41 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/from-framework-lock-in-to-building-our-own-orm-3mjb</link>
      <guid>https://dev.to/amirsaeed_skomjani/from-framework-lock-in-to-building-our-own-orm-3mjb</guid>
      <description>&lt;p&gt;Why we decided to build a custom ORM in a real-world project&lt;/p&gt;

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

&lt;p&gt;In one of our enterprise projects, the core requirement was clear: &lt;strong&gt;the&lt;br&gt;
Core had to be fully independent from any framework&lt;/strong&gt; --- so that future&lt;br&gt;
migrations (to another framework or even another programming language)&lt;br&gt;
would not require rewriting the business logic.&lt;br&gt;
That requirement forced us to build the Core from scratch, without any&lt;br&gt;
framework dependencies. The biggest challenge? Designing a&lt;br&gt;
&lt;strong&gt;framework-agnostic Data Access Layer&lt;/strong&gt;, which naturally led us to&lt;br&gt;
build our own &lt;strong&gt;QueryBuilder/ORM&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Decouple domain logic from infrastructure and framework layers&lt;/li&gt;
&lt;li&gt;  Enable technology migration without rewriting domain code&lt;/li&gt;
&lt;li&gt;  Achieve full unit-testability without a real database&lt;/li&gt;
&lt;li&gt;  Gain fine-grained control over query generation and execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why existing ORMs didn't fit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Framework-Independent Data Layer&lt;/strong&gt; -- Most popular ORMs are deeply
tied to the lifecycle and conventions of their host framework.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Unit Testing without a real DB&lt;/strong&gt; -- We needed to test repositories
and queries with in-memory fakes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Modular Clauses&lt;/strong&gt; -- Each clause had to be composable and
replaceable without touching the Core.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Precise Execution Control&lt;/strong&gt; -- We required control over query
batching, timing, and transaction handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When "build" makes more sense than "buy"
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Domain requirements impose contracts that off-the-shelf ORMs can't
model cleanly.&lt;/li&gt;
&lt;li&gt;  Long-term architectural stability and Core independence outweigh
early speed.&lt;/li&gt;
&lt;li&gt;  The team has enough technical maturity and resources to maintain a
custom data layer.&lt;/li&gt;
&lt;li&gt;  Migration cost and framework lock-in risk are expected to be high
across the product's lifespan.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If these conditions aren't met, adopting a mature ORM is wiser.&lt;br&gt;
Reinventing the wheel only makes sense when the wheel you need doesn't&lt;br&gt;
exist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Design Foundations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Fluent Interface&lt;/strong&gt; -- A clean, chainable API for query
construction&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Clause Strategy + Factory&lt;/strong&gt; -- Each clause implemented as a
strategy; a factory orchestrates their composition&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Query Context&lt;/strong&gt; -- Carries state, bindings, and execution
metadata&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Collection Integration&lt;/strong&gt; -- Returns results as a collection object
supporting map, filter, paginate, and metadata&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ports &amp;amp; Adapters&lt;/strong&gt; --

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Ports:&lt;/em&gt; Repository and QueryService as Core contracts&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Adapters:&lt;/em&gt; Database drivers (PDO, MySQL, PostgreSQL) and
in-memory adapters for testing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Execution Pipeline&lt;/strong&gt; -- Staged SQL building, parameter binding,
secure execution, and mapping to domain models&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Error Mapping&lt;/strong&gt; -- Translates low-level DB errors into
application-level exceptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keys to Testability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;In-Memory Driver&lt;/strong&gt; -- Executes clauses in memory for unit tests&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Contract Tests&lt;/strong&gt; -- Guarantee adapter compliance with Core
interfaces&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Deterministic Hydration&lt;/strong&gt; -- Predictable mapping from raw data to
domain models&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Boundary Tests&lt;/strong&gt; -- Validate that infrastructure concerns never
leak into the domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance and Optimization
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Lazy vs. Eager Execution&lt;/strong&gt; -- Build queries lazily, execute
explicitly at defined boundaries&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Batching&lt;/strong&gt; -- Combine operations to reduce round-trips&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Index-Aware Hints&lt;/strong&gt; -- Inject DB-specific execution hints without
leaking them into Core logic&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Metrics Hooks&lt;/strong&gt; -- Measure runtime performance, record counts, and
detect N+1 issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Transactions and Concurrency
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Unit of Work (optional)&lt;/strong&gt; -- Track and commit grouped changes
atomically&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Explicit Transactions&lt;/strong&gt; -- Provide clear APIs for
begin/commit/rollback at the adapter layer&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Idempotency and Retries&lt;/strong&gt; -- Built-in hooks for retrying critical
operations safely&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pitfalls and Anti-patterns
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Reinventing Active Record&lt;/strong&gt; -- Mixing domain models with DB
operations defeats independence&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Infrastructure Leakage&lt;/strong&gt; -- No low-level types or exceptions
should cross Core boundaries&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Low-level APIs inside Core&lt;/strong&gt; -- The Core should talk through
domain contracts, not SQL or clauses&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ignoring Migration Paths&lt;/strong&gt; -- Always design for adapter and
database version evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison Snapshot
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Eloquent:&lt;/strong&gt; Excellent developer experience within Laravel, but
tightly coupled to it&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Doctrine:&lt;/strong&gt; Highly flexible and decoupled, but heavy and complex&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Custom ORM (ours):&lt;/strong&gt; Tailored to exact architectural needs, at the
cost of maintenance responsibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Outcome
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  A framework-agnostic Core, portable across frameworks or even
languages&lt;/li&gt;
&lt;li&gt;  Strong testability without relying on a physical database&lt;/li&gt;
&lt;li&gt;  Full control over query generation and execution paths&lt;/li&gt;
&lt;li&gt;  Greater architectural transparency and deeper engineering insight
within the team&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When not to take this path
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  The project is short-lived or framework lock-in is an acceptable
risk&lt;/li&gt;
&lt;li&gt;  The team is small and can't maintain a custom data layer&lt;/li&gt;
&lt;li&gt;  Existing ORMs already meet all functional and architectural
requirements&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Building a custom ORM is both a technical and economic decision --- not&lt;br&gt;
a vanity project.&lt;br&gt;
If Core independence, offline testability, and precise control over data&lt;br&gt;
access are your first-order priorities &lt;em&gt;and&lt;/em&gt; your team can sustain the&lt;br&gt;
maintenance cost, then this path is worth it.&lt;br&gt;
Otherwise, rely on proven ORMs and keep your focus on the domain.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>php</category>
      <category>designpatterns</category>
      <category>orm</category>
    </item>
    <item>
      <title>Framework Lock-In: Are you building a product—or just a framework extension?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Tue, 04 Nov 2025 21:36:33 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/framework-lock-in-are-you-building-a-product-or-just-a-framework-extension-1c4f</link>
      <guid>https://dev.to/amirsaeed_skomjani/framework-lock-in-are-you-building-a-product-or-just-a-framework-extension-1c4f</guid>
      <description>&lt;p&gt;Ever looked at code that feels more like a &lt;strong&gt;framework demo&lt;/strong&gt; than a real product?&lt;/p&gt;

&lt;p&gt;Many teams proudly say: “We’ve built an independent product.”&lt;br&gt;&lt;br&gt;
But when you dig deeper, you realize everything — from routing to authentication — is tightly bound to the framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why is this a problem?
&lt;/h2&gt;

&lt;p&gt;In that scenario, your product has &lt;strong&gt;no independent identity&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
If the framework gets deprecated tomorrow or the team shifts direction, you’ll end up &lt;strong&gt;rewriting everything from scratch&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;That’s the danger of &lt;strong&gt;Framework Lock-In&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The trade-off
&lt;/h2&gt;

&lt;p&gt;On the flip side, some teams intentionally give up freedom for &lt;strong&gt;development speed&lt;/strong&gt; and &lt;strong&gt;community support&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Fair enough… but is that truly a &lt;strong&gt;strategy&lt;/strong&gt;, or just &lt;strong&gt;convenience disguised as one&lt;/strong&gt;?&lt;/p&gt;




&lt;h2&gt;
  
  
  What often gets forgotten
&lt;/h2&gt;

&lt;p&gt;A real product should have its &lt;strong&gt;own architectural identity&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
A framework should remain a &lt;strong&gt;tool&lt;/strong&gt;, not the thing that defines your product.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The uncomfortable truth: many so-called “products” are really just framework extensions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Question
&lt;/h3&gt;

&lt;p&gt;Would your product survive without the framework,&lt;br&gt;&lt;br&gt;
or is it just a plug-in living on top of it?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What do you think?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Have you ever refactored a system that was too tied to its framework?&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwaredesign</category>
      <category>systemthinking</category>
      <category>developers</category>
    </item>
    <item>
      <title>Why is the line between juniors and seniors so often misunderstood?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Sat, 01 Nov 2025 14:01:58 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/why-is-the-line-between-juniors-and-seniors-so-often-misunderstood-5f62</link>
      <guid>https://dev.to/amirsaeed_skomjani/why-is-the-line-between-juniors-and-seniors-so-often-misunderstood-5f62</guid>
      <description>&lt;p&gt;In simpler CRUD-based projects, complex architecture quickly turns into &lt;strong&gt;technical debt&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Here, developers with a &lt;strong&gt;pragmatic, delivery-focused&lt;/strong&gt; approach (often juniors) tend to be more effective — because business reality values &lt;strong&gt;simplicity and speed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But once a project grows beyond CRUD into &lt;strong&gt;service-based or domain-heavy complexity&lt;/strong&gt;, that’s where &lt;strong&gt;seniors show their real value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The ability to define &lt;strong&gt;clear context boundaries&lt;/strong&gt;, design &lt;strong&gt;proper abstractions&lt;/strong&gt;, and think in terms of &lt;strong&gt;scalability and maintainability&lt;/strong&gt; isn’t something you gain just by writing code for years.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Real Difference
&lt;/h3&gt;

&lt;p&gt;The difference between a &lt;em&gt;junior&lt;/em&gt; and a &lt;em&gt;senior&lt;/em&gt; is &lt;strong&gt;not about years of experience&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It’s about &lt;strong&gt;maturity&lt;/strong&gt; — in architecture, long-term maintainability, system evolution, and even teamwork and collaboration.&lt;/p&gt;

&lt;p&gt;I’ve seen people with 3–4 years of experience act more mature in architecture and team interaction than someone who’s been coding for a decade.&lt;/p&gt;

&lt;p&gt;That’s why, instead of counting years on a résumé, we should assess &lt;strong&gt;engineering maturity&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Question for you
&lt;/h3&gt;

&lt;p&gt;Have you seen juniors shine in CRUD projects, or seniors saving the day in complex systems?&lt;/p&gt;

&lt;p&gt;Let’s discuss&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>career</category>
      <category>engineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Why Most Developers Misunderstand Clean Architecture</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Mon, 20 Oct 2025 10:37:52 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/why-most-developers-misunderstand-clean-architecture-e5p</link>
      <guid>https://dev.to/amirsaeed_skomjani/why-most-developers-misunderstand-clean-architecture-e5p</guid>
      <description>&lt;p&gt;For many, &lt;strong&gt;Clean Architecture&lt;/strong&gt; is just a checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A controller layer&lt;/li&gt;
&lt;li&gt;  A service layer&lt;/li&gt;
&lt;li&gt;  A repository for the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And they think they're done.&lt;br&gt;
But that's only the surface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes I've Observed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Misunderstanding dependency inversion&lt;/strong&gt;&lt;br&gt;
Core classes still depend on the database or framework, while the rule&lt;br&gt;
says everything should depend on business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring context&lt;/strong&gt;&lt;br&gt;
Developers add ten layers for a simple CRUD app --- resulting in&lt;br&gt;
over-engineering and unnecessary ceremony.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting business goals&lt;/strong&gt;&lt;br&gt;
Teams build architecture for engineering ego, not for solving real&lt;br&gt;
problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Real Clean Architecture Looks Like
&lt;/h2&gt;

&lt;p&gt;The core runs even without a database or framework.&lt;br&gt;
Tests execute fast, directly on the domain logic.&lt;br&gt;
Switching frameworks or databases doesn't break the system.&lt;/p&gt;




&lt;p&gt;From my experience, the cleanest projects had the fewest layers, but&lt;br&gt;
applied the &lt;strong&gt;Dependency Rule&lt;/strong&gt; and &lt;strong&gt;DIP&lt;/strong&gt; correctly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Question
&lt;/h3&gt;

&lt;p&gt;Have you seen teams add complexity in the name of Clean Architecture?&lt;br&gt;
Share your experience below.&lt;/p&gt;

</description>
      <category>cleanarchitecture</category>
      <category>architecture</category>
      <category>systemdesign</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Did you know your database schema might be leaking through error messages and stack traces?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Sat, 13 Sep 2025 08:08:08 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/did-you-know-your-database-schema-might-be-leaking-through-error-messages-and-stack-traces-2pe0</link>
      <guid>https://dev.to/amirsaeed_skomjani/did-you-know-your-database-schema-might-be-leaking-through-error-messages-and-stack-traces-2pe0</guid>
      <description>&lt;p&gt;AI is now smart enough to reconstruct your database from what looks like harmless errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL errors (constraint violations, duplicate entries)
&lt;/li&gt;
&lt;li&gt;ORM/Model exceptions (table names, class names, line numbers)
&lt;/li&gt;
&lt;li&gt;NoSQL hints (like MongoDB’s “document not found” or “index violation”)
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why is this dangerous?
&lt;/h2&gt;

&lt;p&gt;Attackers can gradually infer your schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL → table names, keys, relationships
&lt;/li&gt;
&lt;li&gt;NoSQL → collection names, document structures, indexes
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Insight
&lt;/h2&gt;

&lt;p&gt;Not all databases leak the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relational DBs often reveal too much detail.
&lt;/li&gt;
&lt;li&gt;NoSQL may leak less by default, but verbose logging or misconfiguration changes the game.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What can you do?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never expose raw errors in production.
&lt;/li&gt;
&lt;li&gt;Use generic error handling.
&lt;/li&gt;
&lt;li&gt;Regularly audit your API responses.
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;What about you?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have you ever seen a “simple” DB error reveal way too much?
&lt;/li&gt;
&lt;li&gt;If you had to choose: SQL with verbose errors or NoSQL with misconfig risks — which one feels safer to you, and why?
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cybersecurity</category>
      <category>database</category>
      <category>architecture</category>
      <category>ai</category>
    </item>
    <item>
      <title>Your API Security Assumptions Are Outdated: AI Isn’t Just a User — It’s an Attacker</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Tue, 02 Sep 2025 07:31:50 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/your-api-security-assumptions-are-outdated-ai-isnt-just-a-user-its-an-attacker-5g3k</link>
      <guid>https://dev.to/amirsaeed_skomjani/your-api-security-assumptions-are-outdated-ai-isnt-just-a-user-its-an-attacker-5g3k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI isn’t just a user — it can be an attacker.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most teams still think securing an API means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;strong&gt;JWT&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enforcing &lt;strong&gt;HTTPS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Applying &lt;strong&gt;Rate Limiting&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That used to be enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  But today’s reality is different:
&lt;/h2&gt;

&lt;p&gt;AI is &lt;strong&gt;reading and analyzing your responses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unlike human users, AI can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process &lt;strong&gt;millions of API responses&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Extract &lt;strong&gt;patterns from error messages&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse-engineer&lt;/strong&gt; your system faster than any human hacker&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Vulnerabilities
&lt;/h2&gt;

&lt;p&gt;Here’s how your API might already be leaking knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Raw stack traces&lt;/strong&gt;  → Reveal your &lt;strong&gt;framework&lt;/strong&gt; and &lt;strong&gt;version&lt;/strong&gt; → AI maps it to known CVEs in seconds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exposed SQL queries&lt;/strong&gt;  → Reveal your &lt;strong&gt;schema&lt;/strong&gt; and &lt;strong&gt;business logic&lt;/strong&gt; → Free blueprint for attackers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed validation errors&lt;/strong&gt;  → Help AI learn your &lt;strong&gt;internal rules&lt;/strong&gt; and &lt;strong&gt;edge cases&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📉 The Result?
&lt;/h2&gt;

&lt;p&gt;You’re handing over your system’s architecture to an intelligent attacker — for free.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡 Practical Steps to Protect Your API
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Obfuscation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Return &lt;strong&gt;generic error codes/messages&lt;/strong&gt; — not full details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Layer&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Sanitize and filter every outgoing response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI-aware Security&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Assume your API is consumed by a &lt;strong&gt;learning model&lt;/strong&gt;, not just a user.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 My Take
&lt;/h2&gt;

&lt;p&gt;Once we shifted our mindset from &lt;em&gt;"protecting data"&lt;/em&gt; to &lt;em&gt;"protecting knowledge"&lt;/em&gt;,&lt;br&gt;&lt;br&gt;
many risks &lt;strong&gt;simply disappeared&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do you think AI is becoming:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a helper for security?
&lt;/li&gt;
&lt;li&gt;or the next big threat?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s discuss in the comments 👇&lt;/p&gt;




&lt;p&gt;👉 Follow me for more insights on &lt;strong&gt;Software Architecture + Security in the AI Era&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>api</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Design Patterns Often Fail in Real Projects</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Mon, 25 Aug 2025 10:45:55 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/why-design-patterns-often-fail-in-real-projects-nh5</link>
      <guid>https://dev.to/amirsaeed_skomjani/why-design-patterns-often-fail-in-real-projects-nh5</guid>
      <description>&lt;p&gt;📉 Honestly, I’ve seen it many times: instead of helping, Design Patterns end up making projects worse.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Common reasons why they fail
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Copied directly from books/tutorials without understanding the &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt;.
&lt;/li&gt;
&lt;li&gt;Forcing every problem into a Pattern → pure over-engineering.
&lt;/li&gt;
&lt;li&gt;Team members interpret patterns differently → inconsistent, bloated code.
&lt;/li&gt;
&lt;li&gt;Architecture evolves, but rigid implementations stay stuck.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 How to make them work (from a CTO’s perspective)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A pattern is a tool, not the goal. Use it only when it solves a repeatable problem.
&lt;/li&gt;
&lt;li&gt;Align the chosen pattern with the &lt;strong&gt;architecture vision &amp;amp; product strategy&lt;/strong&gt;, not just personal taste.
&lt;/li&gt;
&lt;li&gt;Make sure the &lt;strong&gt;whole team understands why&lt;/strong&gt; this pattern was picked — otherwise, failure is guaranteed.
&lt;/li&gt;
&lt;li&gt;Keep the architecture flexible and refactor-friendly.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 My take? The most successful patterns I’ve seen were the ones that became a &lt;strong&gt;shared language&lt;/strong&gt; for the team — not a handcuff.  &lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Your turn:&lt;/strong&gt; Have you seen a Design Pattern cause more pain than value? &lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>cleanarchitecture</category>
      <category>systemdesign</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Why Most Refactors Fail — And How to Fix Them</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Sun, 17 Aug 2025 08:05:37 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/why-most-refactors-fail-and-how-to-fix-them-3adj</link>
      <guid>https://dev.to/amirsaeed_skomjani/why-most-refactors-fail-and-how-to-fix-them-3adj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“We should refactor the whole thing…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've heard this line more times than I can count — and honestly, &lt;strong&gt;most of those refactors failed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not because refactoring is a bad idea. But because &lt;strong&gt;they were done wrong&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📉 Why They Fail
&lt;/h2&gt;

&lt;p&gt;Here are the top reasons I’ve seen (and experienced):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No clear target architecture&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
“We just want it cleaner” is not a plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of test coverage&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you don’t have a safety net, every change is a risk.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Big-bang rewrites&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Trying to change everything at once = chaos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team misalignment&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If everyone has a different definition of “clean,” good luck.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ How to Do It Right
&lt;/h2&gt;

&lt;p&gt;If you want your refactor to succeed, start with these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define the end goal&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
What will the architecture look like after refactoring?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refactor incrementally&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Small, focused changes are easier to test, review, and roll back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write tests first&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Ensure you’re not breaking things while cleaning things up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Align the team on standards&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Agree on patterns, formatting, naming — everything.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 My Take
&lt;/h2&gt;

&lt;p&gt;The best refactors I’ve seen had these 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A clear &lt;strong&gt;vision&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A solid &lt;strong&gt;test suite&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A well-communicated &lt;strong&gt;plan&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Refactoring without those? You’re just rewriting code and hoping for the best.&lt;/p&gt;




&lt;h2&gt;
  
  
  🙋 Your Turn
&lt;/h2&gt;

&lt;p&gt;Have you ever done a big refactor?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was it painful or satisfying?
&lt;/li&gt;
&lt;li&gt;Did you have the plan and tests?
&lt;/li&gt;
&lt;li&gt;Or was it more like “rip it out and hope”?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s share some refactor war stories in the comments. 👇&lt;/p&gt;




</description>
      <category>refactoring</category>
      <category>cleancode</category>
      <category>softwaredesign</category>
      <category>programming</category>
    </item>
    <item>
      <title>Repository Layer: Decoration or Real Architecture?</title>
      <dc:creator>Amirsaeed S Komjani</dc:creator>
      <pubDate>Fri, 15 Aug 2025 17:17:02 +0000</pubDate>
      <link>https://dev.to/amirsaeed_skomjani/repository-layer-decoration-or-real-architecture-2hmf</link>
      <guid>https://dev.to/amirsaeed_skomjani/repository-layer-decoration-or-real-architecture-2hmf</guid>
      <description>&lt;p&gt;Many developers add a &lt;strong&gt;Repository Layer&lt;/strong&gt; to make their projects look cleaner and more professional.  &lt;/p&gt;

&lt;p&gt;But in reality, if all repositories are silently coupled to a single driver like &lt;strong&gt;Laravel Eloquent&lt;/strong&gt;, this layer becomes decorative and useless.  &lt;/p&gt;

&lt;p&gt;In this post, I’ll explain why that happens, the architectural risks behind it, and how to design a Repository Layer that &lt;em&gt;actually&lt;/em&gt; delivers on its promise.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;The issue surfaces when you need to &lt;strong&gt;switch databases&lt;/strong&gt; or introduce a new driver.  &lt;/p&gt;

&lt;p&gt;Instead of swapping drivers smoothly, you’re forced into a &lt;strong&gt;major refactor&lt;/strong&gt; because your Repository Layer is tightly bound to one specific ORM or database driver.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Purpose of the Repository Layer
&lt;/h2&gt;

&lt;p&gt;A well-designed Repository Layer should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow replacing or adding multiple drivers &lt;strong&gt;without touching your services or controllers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Keep your application &lt;strong&gt;multi-driver&lt;/strong&gt; and even &lt;strong&gt;multi-tenant&lt;/strong&gt; ready.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When implemented correctly, it becomes the &lt;strong&gt;abstraction boundary&lt;/strong&gt; between your domain logic and your data sources — not just an extra file to look “professional.”&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Fix It — Adapter Pattern to the Rescue
&lt;/h2&gt;

&lt;p&gt;To truly decouple your dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define Repository Interfaces&lt;/strong&gt; in your domain layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create Adapter Classes&lt;/strong&gt; that translate interface methods into driver-specific implementations.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Dependency Injection&lt;/strong&gt; so your services/controllers depend on the interface, not the concrete driver.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example in Laravel/PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepositoryInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;findByEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EloquentUserRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserRepositoryInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;findByEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, swapping to another driver (e.g., MongoDB) means creating a new adapter without touching the rest of your codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Question for You
&lt;/h2&gt;

&lt;p&gt;How do you implement your Repository Layer?&lt;br&gt;
Do you leverage the Adapter Pattern to truly decouple your dependencies, or is your layer just decorative?&lt;/p&gt;




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

&lt;p&gt;A Repository Layer is not just for aesthetics — it’s a key architectural tool for flexibility and scalability.&lt;br&gt;
When paired with the Adapter Pattern, it gives you the freedom to change persistence layers with minimal effort.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;💬 Have you ever had to refactor a whole project just to change the database driver? Share your experience in the comments!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>cleanarchitecture</category>
      <category>adapterpattern</category>
    </item>
  </channel>
</rss>
