<?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: Slavko Mihajlovic</title>
    <description>The latest articles on DEV Community by Slavko Mihajlovic (@omni_slavi).</description>
    <link>https://dev.to/omni_slavi</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F823072%2F8b93620c-f020-4ecc-96b6-19907cc7afc1.png</url>
      <title>DEV Community: Slavko Mihajlovic</title>
      <link>https://dev.to/omni_slavi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/omni_slavi"/>
    <language>en</language>
    <item>
      <title>The Pattern Purist's Delusion: When Dogma Destroys Software</title>
      <dc:creator>Slavko Mihajlovic</dc:creator>
      <pubDate>Tue, 16 Dec 2025 22:04:30 +0000</pubDate>
      <link>https://dev.to/omni_slavi/the-pattern-purists-delusion-when-dogma-destroys-software-2j6f</link>
      <guid>https://dev.to/omni_slavi/the-pattern-purists-delusion-when-dogma-destroys-software-2j6f</guid>
      <description>&lt;h2&gt;
  
  
  The Cost of Purity
&lt;/h2&gt;

&lt;p&gt;It started with a simple request: “Update the button tooltip text.” What should have been a one-line change instead required modifying 8 files: three services, two enums, a routing configuration, and two components. The culprit? A developer’s insistence on “pure pattern implementation.”&lt;/p&gt;

&lt;p&gt;We've turned GoF patterns into religious texts, and now we're sacrificing working software at the altar of theoretical correctness. Let me show you the wreckage—the frameworks that succeed by breaking the rules, the teams that ship by ignoring the priests, and the dirty secret that production code is where patterns go to get practical or get deleted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Myth of Pure Implementation
&lt;/h2&gt;

&lt;p&gt;Design patterns, as originally conceived, were never meant to be rigid templates. The Gang of Four described them as “descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.”&lt;/p&gt;

&lt;p&gt;Note the key words: &lt;strong&gt;customized **and **particular context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Somewhere along the way, patterns morphed from helpful guides into religious doctrine. The pattern purist emerged—someone who values theoretical correctness over practical utility, who would rather rebuild a system than violate an abstraction.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Real Frameworks Break “Pure” Patterns
&lt;/h2&gt;

&lt;p&gt;If pattern purity were essential, our most successful frameworks would be failing case studies. Instead, they thrive by adapting patterns to real constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angular Dependency Injection: The Pragmatic Hybrid&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Angular’s DI system demonstrates this balance beautifully. It offers constructor injection (pattern pure) alongside intentional “impurities”:&lt;/p&gt;

&lt;pre&gt;
// Service locator pattern – textbook anti-pattern
constructor(private injector: Injector) {
  const service = this.injector.get(MyService);
}

// Hard-coded dependency – the exact opposite of DI's goal
providers: [
  { provide: API_ENDPOINT, useValue: 'https://api.example.com' }
]
&lt;/pre&gt;

&lt;p&gt;Why would the Angular team include such &lt;strong&gt;blasphemies&lt;/strong&gt;?  Because real software needs escape hatches. Legal compliance, third-party integrations, and testing demands create scenarios where abstraction only adds friction. &lt;code&gt;useValue&lt;/code&gt; exists because sometimes you just need to wire A to B and move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Singleton? Not So Much
&lt;/h2&gt;

&lt;p&gt;The Singleton pattern is a purist favorite. But look at how real frameworks adapt it:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;React Context&lt;/strong&gt;: Each Provider creates its own instance scope that descendants inherit—hierarchical, not global. This is the Provider Pattern, taking the "single shared instance" concept but making it composable and overrideable.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Vue's Provide/Inject&lt;/strong&gt;: Creates a parent-to-child dependency chain where values can be provided at any level and overridden downstream. Again, hierarchical and context-aware rather than truly singleton.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Angular Services with providedIn: 'root'&lt;/strong&gt;: Creates a true app-wide singleton... unless you provide it again in a component or module, which creates a new instance for that scope. Even Angular's "singletons" aren't always singular.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;iOS/Swift Modern Practic&lt;/strong&gt;e: While Apple's frameworks use classic singletons (FileManager.default), the community increasingly prefers dependency injection through initializers. DI frameworks like Swinject provide singleton scoping without the global static access that makes testing painful.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Android with Dagger/Hilt&lt;/strong&gt;: &lt;a class="mentioned-user" href="https://dev.to/singleton"&gt;@singleton&lt;/a&gt; annotations create container-managed singletons—shared instances without the static instance variables and private constructors of the textbook pattern.&lt;/p&gt;

&lt;p&gt;None of these implement the classic GoF Singleton pattern. They take the core idea—"shared instance"—and adapt it to their frameworks' needs: testability, modularity, tree-shaking, or hierarchical composition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observer Pattern: From Textbook to RxJS
&lt;/h2&gt;

&lt;p&gt;Compare the Observer pattern in the GoF book to RxJS. While RxJS includes observer-like mechanics, it's fundamentally a different paradigm: reactive programming. RxJS added:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Operators and pipes&lt;/strong&gt; for functional data transformation (not in the pattern)&lt;br&gt;
• &lt;strong&gt;Hot vs. cold observables&lt;/strong&gt; for stream lifecycle management (pattern adaptation)&lt;br&gt;
• &lt;strong&gt;Multicasting and scheduling&lt;/strong&gt; for real-world performance optimization&lt;/p&gt;

&lt;p&gt;If RxJS had implemented only the 'pure' GoF Observer pattern—simple notification callbacks—we wouldn't have the powerful reactive ecosystem we rely on today. The framework adapted the core idea into something far more useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Costs of Pattern Zealotry
&lt;/h2&gt;

&lt;p&gt;The tooltip debacle revealed a painful irony: the pursuit of pattern purity often achieves the opposite of its intended goals.&lt;/p&gt;

&lt;p&gt;The purist wanted:&lt;br&gt;
    • Decoupled, maintainable code&lt;br&gt;
    • Testable components&lt;br&gt;
    • Clean separation of concerns&lt;br&gt;
What we got:&lt;br&gt;
    • A cage of abstractions we're now trapped in&lt;br&gt;
    • Tests so fragile they mock their own existence&lt;br&gt;
    • Architecture so 'clean' it needs committee approval for a text change&lt;/p&gt;

&lt;p&gt;This isn’t theoretical. It’s the daily reality in teams where pattern dogma overrides pragmatism.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five Realities Purists Ignore
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Business Logic Isn’t Academic&lt;/strong&gt;&lt;br&gt;
Legal requirements, compliance rules, and business constraints create unique, one-off needs. GDPR logging for EU users? A/B test tracking for experiment #247? These aren’t abstractable problems—they’re specific needs demanding specific solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Time Is a Finite Resource&lt;/strong&gt;&lt;br&gt;
Businesses pay for working software, not perfect architecture. The daily choice isn’t “perfect pattern vs. bad code” — it’s “ship today vs. ship never.” Over-engineering is just as destructive as under-engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Your Team Isn't Your Audience&lt;/strong&gt;&lt;br&gt;
That junior trying to fix a bug at 2 AM? They don't care about your beautiful pattern cathedral. The senior reviewing your code from another squad? They're not impressed by your pattern acrobatics. Good code explains itself; clever code just makes you feel smart while everyone else suffers."**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Performance Isn’t Abstract&lt;/strong&gt;&lt;br&gt;
Every abstraction layer has cost: bundle size, execution time, memory overhead. Virtual DOM wasn’t in any pattern book, but it made web apps usable on real devices. Pragmatism beats purity when users are waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Requirements Evolve&lt;/strong&gt;&lt;br&gt;
Today’s perfect abstraction becomes tomorrow’s constraint. Systems that can’t adapt to new requirements—because they’re too coupled to their own patterns—fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Mindset: Patterns as Lenses, Not Laws
&lt;/h2&gt;

&lt;p&gt;Instead of asking “How purely can we implement this pattern?”, try:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What’s the actual problem?&lt;/strong&gt;&lt;br&gt;
Not “How can we use the Strategy pattern?” but “We need to sort this list differently in three contexts.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What’s the simplest thing that works?&lt;/strong&gt;&lt;br&gt;
Sometimes a configuration object beats a factory. Sometimes an if statement beats a strategy. Simplicity is its own virtue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What will actually change?&lt;/strong&gt;&lt;br&gt;
Base decisions on your roadmap and user feedback, not hypothetical future needs. YAGNI isn’t laziness—it’s focus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Can our team maintain this?&lt;/strong&gt;&lt;br&gt;
The best abstraction is the one your team understands without a week of onboarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Maintenance Test
&lt;/h2&gt;

&lt;p&gt;The true test of code quality isn’t pattern purity—it’s maintainability. Imagine a developer joins your team six months from now. They need to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the purist codebase&lt;/strong&gt;: Understand the pattern landscape, trace inheritance hierarchies, and learn the “right” way to extend the system.&lt;br&gt;
&lt;strong&gt;In the pragmatic codebase&lt;/strong&gt;: Find the relevant code, make the change, verify it works.&lt;/p&gt;

&lt;p&gt;Which codebase is actually better engineered?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: From Religion to Engineering
&lt;/h2&gt;

&lt;p&gt;Patterns are invaluable—as inspiration, as shared vocabulary, as starting points for solutions. But the moment they become commandments, they start destroying the very things they promise to protect: working, maintainable, adaptable software.&lt;/p&gt;

&lt;p&gt;Look at the frameworks we actually use. They're not pure—they're practical.They give us escape hatches, pragmatic shortcuts, and context-aware solutions because they’re built by engineers who’ve faced real constraints.&lt;/p&gt;

&lt;p&gt;So next time someone starts preaching pattern purity, hit them with reality:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actual user cares about this purity?&lt;/strong&gt; (Spoiler: none of them)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many files do we touch to change a button label?&lt;/strong&gt; (Hint: if it's more than one, you've failed)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Show me one production system at scale that implements this 'purely'&lt;/strong&gt; (They can't—because they don't exist)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the actual cost?&lt;/strong&gt; Not in theory, but in missed deadlines, frustrated teams, and features that never ship&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember this&lt;/strong&gt;: users experience your software, not your architecture. They care if the button works, not how beautiful your seven-layer injection chain is.&lt;/p&gt;

&lt;p&gt;The engineers I respect aren't pattern priests. They're pragmatic problem-solvers who know when to use a pattern, when to adapt it, and—most importantly—when to tell it 'not this time, baby' and just write the damn code.&lt;/p&gt;

&lt;p&gt;That's not 'compromising on quality.' That's the difference between academic exercises and actual engineering. And I know which one I'd rather have in production.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>designpatterns</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The Complete Guide to SEO in Angular: How To Make Your App Discoverable Without Losing Your Sanity</title>
      <dc:creator>Slavko Mihajlovic</dc:creator>
      <pubDate>Thu, 04 Dec 2025 09:57:52 +0000</pubDate>
      <link>https://dev.to/omni_slavi/the-complete-guide-to-seo-in-angular-how-to-make-your-app-discoverable-without-losing-your-sanity-17nb</link>
      <guid>https://dev.to/omni_slavi/the-complete-guide-to-seo-in-angular-how-to-make-your-app-discoverable-without-losing-your-sanity-17nb</guid>
      <description>&lt;p&gt;Angular is fantastic at rendering dynamic, fast, interactive applications. It’s less fantastic at helping search engines understand what those applications contain. Anyone who has ever built a moderately complex Angular app has probably had that moment where the browser tab proudly displays “HomeComponent” instead of a real page title, or where every single shared link previews as the same generic description.&lt;/p&gt;

&lt;p&gt;The truth is simple: search engines aren’t mind readers, and Angular won’t fill in the blanks for you. If you want your app to show meaningful previews on social platforms, appear correctly in search results, or simply feel polished, you have to think about SEO from the beginning.&lt;/p&gt;

&lt;p&gt;And no, this doesn’t mean chasing keywords. In an Angular world, SEO mostly comes down to declaring the right metadata at the right time&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Angular Apps Need SEO Love
&lt;/h2&gt;

&lt;p&gt;Single-page apps don’t behave like old-school websites. The browser loads one document and then swaps content internally as users navigate. Search engines are built to understand traditional page loads, not virtual navigation. That’s why Angular apps so often end up with missing titles, outdated descriptions, or half-baked Open Graph tags. Even when Google can index your content, you still need to supply intentional metadata if you want a good representation of your site.&lt;/p&gt;

&lt;p&gt;The funny thing is that the metadata itself is extremely simple: a title, a description, an image if you want social previews. The hard part is keeping those things consistent across dozens of routes, dynamic parameters, lazy-loaded modules, and whatever creative architecture your team invented at 2 a.m.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Parts of SEO That Actually Matter for Angular
&lt;/h2&gt;

&lt;p&gt;At the heart of it, you’re dealing with just a few components. The page title is the single most important piece. You need one that changes with every meaningful view in your app. The meta description is the second. It’s not a ranking trick; it’s the text users read before deciding whether to click. Then come the Open Graph tags, which determine how your site looks when shared on Slack, LinkedIn, Discord, or Twitter. Every serious product ends up needing these.&lt;/p&gt;

&lt;p&gt;And outside the app itself, there are the quiet companions: &lt;strong&gt;robots.txt&lt;/strong&gt;—the file that tells crawlers what they’re allowed to explore—and &lt;strong&gt;sitemap.xml&lt;/strong&gt;, which gives them a map of your site instead of making them guess. Both are tiny files that developers tend to ignore until something breaks.&lt;/p&gt;

&lt;p&gt;None of these are complicated individually. The pain appears when you try to keep them all aligned with a growing Angular codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Angular Makes SEO More Annoying Than It Should Be
&lt;/h2&gt;

&lt;p&gt;If you’ve ever scattered &lt;code&gt;Title.setTitle()&lt;/code&gt; and &lt;code&gt;Meta.updateTag()&lt;/code&gt; across half a dozen components, you already know the problem. Everyone on the team eventually invents their own slightly different pattern. Dynamic routes make things even more awkward, because you need logic that depends on route parameters, and you have no central place where that logic should live.&lt;/p&gt;

&lt;p&gt;Angular gives you the low-level APIs, but no opinion about structure. So you either reinvent your own SEO system—or you end up with metadata duct-taped into whatever file was closest at the moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Patterns That Actually Work
&lt;/h2&gt;

&lt;p&gt;Over time, two approaches emerge as sane solutions.&lt;/p&gt;

&lt;p&gt;The first is a centralized, path-based configuration. You define your major routes in one place— &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;, &lt;code&gt;/pricing&lt;/code&gt;&lt;code&gt;,&lt;/code&gt;/blog` —and attach metadata to each of them. The entire SEO story becomes declarative. It’s perfect for sites with predictable routes.&lt;/p&gt;

&lt;p&gt;The second approach ties SEO directly to Angular’s routing system. You store metadata inside &lt;code&gt;route.data&lt;/code&gt;, right next to the component it belongs to. This is ideal for dynamic pages like blog posts, product detail views, or anything using parameters. The metadata can even be a function that receives the activated route, which makes it surprisingly elegant.&lt;/p&gt;

&lt;p&gt;The problem is that implementing either of these patterns requires wiring up a service, listening to navigation events, normalizing URLs, applying tags, and avoiding duplication. It’s not hard work, just tedious and repetitive. Exactly the kind of thing you shouldn’t be writing more than once in your life.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Cleaner Way: Automating SEO in Angular
&lt;/h2&gt;

&lt;p&gt;This is the point where a library like &lt;code&gt;@omnidyon/ngx-seo-meta&lt;/code&gt; steps in. It’s a lightweight meta-tag management system designed specifically for Angular 19 and beyond. Instead of scattering SEO logic around your app, you get a single service and a clean API that updates everything automatically whenever navigation occurs.&lt;/p&gt;

&lt;p&gt;You can install it in seconds:&lt;/p&gt;

&lt;pre&gt;
npm install @omnidyon/ngx-seo-meta
&lt;/pre&gt;

&lt;p&gt;Once it’s in your project, you choose the style you prefer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you like centralized config&lt;/strong&gt;&lt;br&gt;
Create a file mapping paths to metadata:&lt;/p&gt;

&lt;pre&gt;
export const SEO_CONFIG = {
  '/': {
    title: 'Home – My App',
    description: 'Welcome to the homepage.'
  },
  '/about': {
    title: 'About Us',
    description: 'Learn more about the team.'
  }
};
&lt;/pre&gt;

&lt;p&gt;Provide it when bootstrapping:&lt;/p&gt;

&lt;pre&gt;
bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideSeoMeta(SEO_CONFIG)
  ]
});
&lt;/pre&gt;

&lt;p&gt;That’s it. Every time the user navigates, the library normalizes the path, finds the matching entry, and updates the title and meta tags for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you prefer route-driven metadata&lt;/strong&gt;&lt;br&gt;
Attach metadata directly to the route definition:&lt;/p&gt;

&lt;pre&gt;
{
  path: 'blog/:slug',
  loadComponent: () =&amp;gt; import('./blog/blog.component'),
  data: {
    seo: (route) =&amp;gt; ({
      title: `Blog – ${route.paramMap.get('slug')}`,
      description: 'Reading article...'
    })
  }
}
&lt;/pre&gt;

&lt;p&gt;Enable the routing integration:&lt;/p&gt;

&lt;pre&gt;
provideSeoMetaRouting() 
&lt;/pre&gt;

&lt;p&gt;Now Angular will update your tags automatically on every navigation, using either the static object or the dynamic function you provided.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Get Beyond Titles and Descriptions
&lt;/h2&gt;

&lt;p&gt;The library also handles Open Graph and Twitter metadata using the same definition. If you supply &lt;code&gt;ogImage&lt;/code&gt;, &lt;code&gt;twitterCard&lt;/code&gt;, &lt;code&gt;ogUrl&lt;/code&gt;, or anything similar, it applies them consistently. This alone saves you from the “why does Slack show the wrong preview again” nightmare.&lt;/p&gt;

&lt;p&gt;It works for standalone apps and old-school NgModule setups, plays nicely with Angular 19+, and keeps all SEO logic where it belongs instead of smudged across your components.&lt;/p&gt;

&lt;h2&gt;
  
  
  And If You’re Wondering About SSR…
&lt;/h2&gt;

&lt;p&gt;Search engines can index client-rendered Angular apps, but SSR or prerendering is still useful for content-heavy sites, blogs, or anything competing in high-traffic search categories. Metadata remains important either way, and a centralized system prevents duplication across SSR and CSR builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;SEO for Angular isn’t glamorous. You don’t get fancy animations or performance boosts. What you do get is a site that shows up correctly in search results, generates clean social previews, and feels more professional.&lt;/p&gt;

&lt;p&gt;You could wire up your own solution for this, and many developers do. But if you'd rather stop rewriting the same title and meta boilerplate across every new Angular project, @omnidyon/ngx-seo-meta gives you a tidy, declarative, Angular-native way to manage everything in one place.&lt;/p&gt;

&lt;p&gt;You can find the library here:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@omnidyon/ngx-seo-meta" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@omnidyon/ngx-seo-meta&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>seo</category>
      <category>web</category>
      <category>webperf</category>
    </item>
  </channel>
</rss>
