<?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: Michael Gokey</title>
    <description>The latest articles on DEV Community by Michael Gokey (@michael-gokey).</description>
    <link>https://dev.to/michael-gokey</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%2F3080948%2Fd7cbe7bf-60ac-4bc9-a8c6-f1dac417df10.png</url>
      <title>DEV Community: Michael Gokey</title>
      <link>https://dev.to/michael-gokey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michael-gokey"/>
    <language>en</language>
    <item>
      <title>Common Naming Case Types</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Tue, 21 Oct 2025 14:48:31 +0000</pubDate>
      <link>https://dev.to/michael-gokey/common-naming-case-types-14bo</link>
      <guid>https://dev.to/michael-gokey/common-naming-case-types-14bo</guid>
      <description>&lt;p&gt;If you've worked across multiple languages or frameworks, you've probably noticed that naming conventions are everywhere, and they're not always consistent. Each project uses something different.  &lt;code&gt;camelCase&lt;/code&gt;, another prefers &lt;code&gt;snake_case&lt;/code&gt;, and suddenly you're context-switching between &lt;code&gt;PascalCase&lt;/code&gt; components and &lt;code&gt;kebab-case&lt;/code&gt; CSS classes.&lt;/p&gt;

&lt;p&gt;This is a quick reference I keep handy when I'm switching projects or reviewing code. It covers the most common naming conventions, where they're typically used, and why. It's nothing fancy; it's a cheat sheet that saves me from second-guessing myself when I'm deep in the work.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A quick reference guide to the naming conventions used across programming languages, documentation, and UI design.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Common Case Types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  camelCase
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The first word is lowercase, subsequent words are capitalized&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;myVariableName&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commonly used in:&lt;/strong&gt; JavaScript, Java, and for variables or function names&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  PascalCase
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every word is capitalized, including the first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;MyVariableName&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Often used for:&lt;/strong&gt; Class names, types, or components in many languages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  kebab-case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Words are lowercase and separated by hyphens (&lt;code&gt;-&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;my-variable-name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Often used in:&lt;/strong&gt; URLs, file names, CSS class names&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  snake_case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Words are lowercase and separated by underscores (&lt;code&gt;_&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;my_variable_name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common in:&lt;/strong&gt; Python, databases, and some configuration files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SCREAMING_SNAKE_CASE
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Like snake_case but all uppercase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;MY_VARIABLE_NAME&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Often used for:&lt;/strong&gt; Constants&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Train-Case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Like PascalCase but with hyphens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;My-Variable-Name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage:&lt;/strong&gt; Less common, sometimes used in URLs or documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  dot.case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Words separated by dots (&lt;code&gt;.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;my.variable.name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sometimes used in:&lt;/strong&gt; Config files or namespaces&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Title Case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Capitalize the first letter of most words (like a book title)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;My Variable Name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Often used in:&lt;/strong&gt; Headings, menu items, or UI text&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sentence case
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only the first word (and proper nouns) capitalized&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;My variable name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common in:&lt;/strong&gt; Normal text, documentation, and UI instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  lowercase
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Everything in lowercase, no separators&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;myvariablename&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage:&lt;/strong&gt; Rare, but sometimes used in URLs or legacy systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Notes and Patterns
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Many of these are interchangeable depending on context:&lt;/strong&gt; programming language, framework, or documentation style.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll often see a mix in modern projects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;camelCase&lt;/code&gt; for variables&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PascalCase&lt;/code&gt; for classes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SCREAMING_SNAKE_CASE&lt;/code&gt; for constants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Python:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;snake_case&lt;/code&gt; for functions and variables&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PascalCase&lt;/code&gt; for classes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SCREAMING_SNAKE_CASE&lt;/code&gt; for constants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CSS / HTML:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kebab-case&lt;/code&gt; for class names and IDs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Naming conventions matter more than they should, but they do matter. Consistency makes code easier to read, review, and maintain. It also makes onboarding smoother when you're working with a team or picking up someone else's work.&lt;/p&gt;

&lt;p&gt;If this helps you avoid one moment of "&lt;em&gt;wait, should this be camelCase or snake_case?&lt;/em&gt;" then it's done its job. Bookmark it, share it, or keep it handy. Whatever makes your workflow a little smoother.&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%2Flsgcry3z2gw6yja8chkh.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%2Flsgcry3z2gw6yja8chkh.png" alt="Image shows a few of the Common Naming Case Types" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>python</category>
    </item>
    <item>
      <title>How Social Media Feed Algorithms Work</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Thu, 02 Oct 2025 21:13:32 +0000</pubDate>
      <link>https://dev.to/michael-gokey/how-social-media-feed-algorithms-work-2cc8</link>
      <guid>https://dev.to/michael-gokey/how-social-media-feed-algorithms-work-2cc8</guid>
      <description>&lt;p&gt;A social media feed algorithm acts like a personal content curator, choosing which posts you see and in what order. Imagine it as a music playlist generator. It collects all possible songs (or posts), removes ones you've already heard, scores how much you might enjoy each, ranks them, adds some variety, and then gives you a playlist tailored just for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User Profiling System
&lt;/h3&gt;

&lt;p&gt;The algorithm builds detailed profiles of each user by tracking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interaction History&lt;/strong&gt;: What you like, share, comment on, and how long you view content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social Connections&lt;/strong&gt;: Who you follow, message, and interact with most&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Preferences&lt;/strong&gt;: Whether you prefer videos over text, news over memes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage Patterns&lt;/strong&gt;: When you're most active, what device you use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demographic Signals&lt;/strong&gt;: Age, location, language preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Content Scoring Engine
&lt;/h3&gt;

&lt;p&gt;Every potential post gets evaluated using machine learning models that consider hundreds of signals, but the main factors include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Relevance&lt;/strong&gt; to your interests and past behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship strength&lt;/strong&gt; with the content creator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content quality&lt;/strong&gt; and engagement from other users&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recency&lt;/strong&gt; and trending status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content type&lt;/strong&gt; match to your preferences&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Algorithm Process (Step-by-Step)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Collect Candidate Posts
&lt;/h3&gt;

&lt;p&gt;The system gathers potential content from multiple sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your Network&lt;/strong&gt;: Posts from friends, family, and accounts you follow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trending Content&lt;/strong&gt;: Popular posts in your region or globally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interest-Based&lt;/strong&gt;: Content matching your topics and hobbies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommended&lt;/strong&gt;: Posts from accounts similar to ones you follow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promoted&lt;/strong&gt;: Advertisements and sponsored content&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Filter Out Unwanted Content
&lt;/h3&gt;

&lt;p&gt;Before scoring, the algorithm removes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate posts you've already seen&lt;/li&gt;
&lt;li&gt;Content flagged as spam or inappropriate&lt;/li&gt;
&lt;li&gt;Posts from blocked or muted accounts&lt;/li&gt;
&lt;li&gt;Content that violates platform policies&lt;/li&gt;
&lt;li&gt;Posts outside your language/location preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Score Each Post
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens. For every remaining post, the algorithm calculates a "relevance score" using factors like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Engagement Signals&lt;/strong&gt;: Did you like, share, or comment on similar posts before?&lt;br&gt;
&lt;strong&gt;Relationship Strength&lt;/strong&gt;: How close are you to the author (DMs, likes, tags)?&lt;br&gt;
&lt;strong&gt;Content Type Preference&lt;/strong&gt;: Do you watch more videos than read text posts?&lt;br&gt;
&lt;strong&gt;Recency&lt;/strong&gt;: Is this new or old?&lt;br&gt;
&lt;strong&gt;Virality/Quality&lt;/strong&gt;: Is the post popular with others?&lt;/p&gt;

&lt;p&gt;The scoring formula looks something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score(post) = w1 × engagement_probability
            + w2 × relationship_strength  
            + w3 × content_type_match
            + w4 × recency_decay
            + w5 × global_quality
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where each "w" represents how much weight the platform gives to that factor.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Apply Machine Learning Prediction
&lt;/h3&gt;

&lt;p&gt;The algorithm uses trained neural networks or other ML models to predict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Probability you'll engage&lt;/strong&gt; (like, comment, share)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time you'll spend&lt;/strong&gt; viewing the content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Likelihood you'll find it valuable&lt;/strong&gt; based on similar users' behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Business Logic &amp;amp; Final Adjustments
&lt;/h3&gt;

&lt;p&gt;The raw ML scores get modified by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promoting paid content&lt;/strong&gt; (ads get score boosts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensuring diversity&lt;/strong&gt; (penalizing too much similar content)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boosting close friends&lt;/strong&gt; (recent posts from best friends get priority)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balancing content types&lt;/strong&gt; (mixing videos, photos, text posts)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Rank &amp;amp; Sort Posts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sort all posts by their final scores, highest first&lt;/li&gt;
&lt;li&gt;Apply diversity rules so you don't see 10 posts from the same person&lt;/li&gt;
&lt;li&gt;Insert promoted content at strategic intervals&lt;/li&gt;
&lt;li&gt;Mix content types for visual variety&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Build Final Feed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Take the top N posts (usually 50-100 for initial load)&lt;/li&gt;
&lt;li&gt;Add slight randomization to prevent identical feeds&lt;/li&gt;
&lt;li&gt;Log what was shown for future learning&lt;/li&gt;
&lt;li&gt;Display the personalized feed to you
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOCIAL MEDIA FEED ALGORITHM - PSEUDOCODE

FUNCTION generate_personalized_feed(user_id):

    // Step 1: Get user profile and preferences
    user_profile = get_user_profile(user_id)
    user_interests = extract_user_interests(user_profile)
    user_connections = get_user_connections(user_id)

    // Step 2: Gather candidate posts from multiple sources
    candidate_posts = empty_list()

    // Get posts from friends and followed accounts
    friend_posts = get_posts_from_connections(user_connections, time_limit=24_hours)
    candidate_posts.add(friend_posts)

    // Get trending/popular posts
    trending_posts = get_trending_posts(user_location, time_limit=6_hours)
    candidate_posts.add(trending_posts)

    // Get posts based on user interests
    interest_posts = get_posts_by_topics(user_interests, time_limit=12_hours)
    candidate_posts.add(interest_posts)

    // Step 3: Initial filtering
    filtered_posts = empty_list()
    FOR each post in candidate_posts:
        IF post is not spam AND 
           post is not inappropriate AND 
           user has not seen post AND
           post is not blocked content:
            filtered_posts.add(post)

    // Step 4: Feature engineering - calculate signals for each post
    scored_posts = empty_list()
    FOR each post in filtered_posts:
        post_features = calculate_post_features(post, user_profile)
        // Features include:
        // - recency_score = calculate_time_decay(post.timestamp)
        // - engagement_score = (likes + comments + shares) / followers
        // - relevance_score = match_user_interests(post.content, user_interests)
        // - relationship_score = connection_strength(post.author, user_id)
        // - content_type_score = user_preference_for_type(post.type, user_profile)

        scored_posts.add({post: post, features: post_features})

    // Step 5: Apply machine learning model to predict engagement
    FOR each scored_post in scored_posts:
        predicted_engagement = ml_model.predict(scored_post.features)
        scored_post.prediction_score = predicted_engagement

    // Step 6: Apply business logic and final adjustments
    FOR each scored_post in scored_posts:
        // Boost promoted content
        IF scored_post.post.is_promoted:
            scored_post.prediction_score *= 1.5

        // Ensure diversity - penalize similar content
        IF too_many_similar_posts_already_shown:
            scored_post.prediction_score *= 0.8

        // Boost recent posts from close friends
        IF scored_post.post.author in user.close_friends AND post_age &amp;lt; 2_hours:
            scored_post.prediction_score *= 1.3

    // Step 7: Sort and select final posts
    sorted_posts = sort_by_prediction_score(scored_posts, descending=True)
    final_feed = take_top_N_posts(sorted_posts, N=50)

    // Step 8: Add some randomization to prevent staleness
    final_feed = add_slight_randomization(final_feed, randomization_factor=0.1)

    // Step 9: Log interactions for future learning
    log_feed_generation(user_id, final_feed, timestamp=now())

    RETURN final_feed

// Helper functions would include:
// - get_user_profile(user_id)
// - calculate_time_decay(timestamp)
// - match_user_interests(content, interests)
// - connection_strength(author, user)
// - ml_model.predict(features)
// - etc.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Technical Architecture
&lt;/h2&gt;

&lt;p&gt;Most platforms use a &lt;strong&gt;multi-stage pipeline&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Candidate Generation&lt;/strong&gt; → Pulls thousands of potential posts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial Filtering&lt;/strong&gt; → Reduces to hundreds of viable options
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature Engineering&lt;/strong&gt; → Calculates scoring signals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML Ranking&lt;/strong&gt; → Applies trained models for predictions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business Rules&lt;/strong&gt; → Applies platform-specific adjustments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Assembly&lt;/strong&gt; → Creates the ordered feed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The system is always learning from what you do. Every like, scroll, and the time you spend viewing content helps improve the recommendations you see in the future.&lt;/p&gt;




&lt;h2&gt;
  
  
  Platform Differences
&lt;/h2&gt;

&lt;p&gt;While the core approach is similar, different platforms emphasize different signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instagram&lt;/strong&gt;: Heavily weighs visual engagement and story interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TikTok&lt;/strong&gt;: Prioritizes completion rates and rewatches for videos
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twitter/X&lt;/strong&gt;: Focuses on recency, trending topics, and real-time engagement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facebook&lt;/strong&gt;: Emphasizes social connections and meaningful interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt;: Prioritizes professional relevance and network connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fundamental goal remains the same: show you content that keeps you engaged, satisfied, and coming back to the platform.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>algorithms</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>Understanding BEM as a CSS Methodology for Modern Web Development</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Thu, 04 Sep 2025 12:49:22 +0000</pubDate>
      <link>https://dev.to/michael-gokey/understanding-bem-as-a-css-methodology-for-modern-web-development-8l8</link>
      <guid>https://dev.to/michael-gokey/understanding-bem-as-a-css-methodology-for-modern-web-development-8l8</guid>
      <description>&lt;p&gt;Maintaining clean, scalable, and maintainable CSS has become increasingly challenging in this ever-evolving landscape of web development. As projects grow in complexity and teams expand, the need for a consistent CSS architecture becomes critical. Enter BEM (Block Element Modifier), a naming methodology that has transformed how developers approach CSS organization.&lt;/p&gt;

&lt;p&gt;Whether you're working on a small personal project or a large-scale enterprise application, BEM provides a systematic approach to writing CSS that promotes code reusability, reduces conflicts, and improves collaboration among team members. This article will explore what BEM is, how it compares to other popular CSS approaches, and provide practical guidance for implementing it successfully in your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is BEM?
&lt;/h2&gt;

&lt;p&gt;BEM (Block Element Modifier) is a CSS naming methodology that helps create reusable, maintainable, and scalable stylesheets. It's one of the most popular CSS architecture patterns used in modern web development.&lt;/p&gt;

&lt;h3&gt;
  
  
  The BEM Structure
&lt;/h3&gt;

&lt;p&gt;BEM follows a specific naming convention with three main components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block&lt;/strong&gt;: A standalone component that is meaningful on its own&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;menu&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;card&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Element&lt;/strong&gt;: A part of a block that has no standalone meaning and is semantically tied to its block&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named using double underscores: &lt;code&gt;block__element&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;menu__item&lt;/code&gt;, &lt;code&gt;card__title&lt;/code&gt;, &lt;code&gt;button__icon&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Modifier&lt;/strong&gt;: A flag on a block or element that changes appearance, behavior, or state&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named using double hyphens: &lt;code&gt;block--modifier&lt;/code&gt; or &lt;code&gt;block__element--modifier&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;button--large&lt;/code&gt;, &lt;code&gt;menu__item--active&lt;/code&gt;, &lt;code&gt;card--featured&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  BEM Naming Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Block */
.card { }

/* Elements */
.card__header { }
.card__title { }
.card__content { }
.card__footer { }

/* Modifiers */
.card--featured { }
.card--large { }
.card__title--centered { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTML Structure Example
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Article Title&amp;lt;/h2&amp;gt;


&amp;lt;p&amp;gt;Article content goes here...&amp;lt;/p&amp;gt;


Read More
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Key Benefits of BEM
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Clarity&lt;/strong&gt;: Class names are self-documenting and clearly show the relationship between components&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Each block is independent and can be reused anywhere&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;: Easy to understand and modify without fear of breaking other components&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoiding CSS Conflicts&lt;/strong&gt;: Specific naming prevents accidental style overwrites&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Collaboration&lt;/strong&gt;: Consistent naming convention makes it easier for teams to work together&lt;/p&gt;

&lt;h2&gt;
  
  
  BEM vs Tailwind vs Sass/Less
&lt;/h2&gt;

&lt;p&gt;Neither Tailwind CSS nor Sass/Less are examples of BEM. They're different types of tools entirely. Understanding these distinctions is crucial for modern CSS development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BEM&lt;/strong&gt; is a &lt;em&gt;naming methodology/architecture pattern&lt;/em&gt;. It's about how you structure and name your CSS classes, regardless of what tool you use to write them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt; is a &lt;em&gt;utility-first CSS framework&lt;/em&gt; that takes a completely different approach from BEM. Instead of creating semantic component classes, Tailwind provides small, single-purpose utility classes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sass/Less&lt;/strong&gt; are &lt;em&gt;CSS preprocessors&lt;/em&gt;. They extend CSS with features like variables, nesting, mixins, and functions. You can use BEM naming with Sass/Less.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparing Approaches
&lt;/h3&gt;

&lt;h3&gt;
  
  
  BEM Approach:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card { }
.card__title { }
.card__content { }
.card--featured { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tailwind Approach:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="bg-white rounded-lg shadow-md p-6 border-l-4 border-blue-500"&amp;gt;
  &amp;lt;h2 class="text-xl font-bold text-gray-800 mb-4"&amp;gt;Article Title&amp;lt;/h2&amp;gt;
  &amp;lt;p class="text-gray-600"&amp;gt;Article content...&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  BEM with Sass:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card {
  background: white;
  border-radius: 8px;

  &amp;amp;__title {
    font-size: 1.25rem;
    font-weight: bold;
  }

  &amp;amp;__content {
    color: #666;
  }

  &amp;amp;--featured {
    border-left: 4px solid blue;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Differences
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;BEM&lt;/strong&gt;: Component-based, semantic naming, custom CSS for each component. &lt;br&gt;
&lt;strong&gt;Tailwind&lt;/strong&gt;: Utility-based, descriptive classes, pre-built styles. &lt;br&gt;
&lt;strong&gt;Sass/Less&lt;/strong&gt;: Tools that can work with either BEM or utility approaches&lt;/p&gt;

&lt;p&gt;Tailwind is actually quite different from BEM philosophically. BEM encourages creating reusable component classes, while Tailwind encourages composing styles from atomic utility classes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Best Practices and Common Pitfalls
&lt;/h2&gt;

&lt;p&gt;Successfully implementing BEM requires understanding not just its syntax, but also when and how to apply it effectively. Here are some key best practices and common mistakes to avoid.&lt;/p&gt;
&lt;h3&gt;
  
  
  When to Use BEM
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ideal Scenarios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component-based user interfaces&lt;/li&gt;
&lt;li&gt;Large-scale applications with multiple developers&lt;/li&gt;
&lt;li&gt;Projects requiring long-term maintenance&lt;/li&gt;
&lt;li&gt;Design systems and style guides&lt;/li&gt;
&lt;li&gt;When CSS specificity conflicts are a concern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consider Alternatives When:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building simple, static websites&lt;/li&gt;
&lt;li&gt;Working on prototypes or one-off projects&lt;/li&gt;
&lt;li&gt;Team strongly prefers utility-first approaches&lt;/li&gt;
&lt;li&gt;The existing codebase uses different methodologies extensively&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Common Pitfalls and How to Avoid Them
&lt;/h3&gt;
&lt;h3&gt;
  
  
  1. Over-Nesting Elements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card__header__title__text { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Right:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card__header { }
.card__title { }
.card__text { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BEM discourages deep nesting. Elements should be direct children of blocks, not nested within other elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Creating Elements Without a Clear Purpose
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card__div { }
.card__container { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Right:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card__content { }
.card__actions { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Elements should have semantic meaning and a clear purpose within the block.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Inconsistent Modifier Naming
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.button--big { }
.button--small-size { }
.button--color-red { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Right:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.button--large { }
.button--small { }
.button--danger { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use consistent, meaningful modifier names that describe state or variation, not implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Mixing BEM with Non-BEM Classes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Wrong:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="card featured-item"&amp;gt;
  &amp;lt;h2 class="card__title big-text"&amp;gt;Title&amp;lt;/h2&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Right:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="card card--featured"&amp;gt;
  &amp;lt;h2 class="card__title card__title--large"&amp;gt;Title&amp;lt;/h2&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maintain consistency within components by sticking to BEM naming throughout.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Organization Strategies
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Component-Based Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;styles/
  components/
    _card.scss
    _button.scss
    _navigation.scss
  base/
    _reset.scss
    _typography.scss
  utilities/
    _helpers.scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Block-Centric Approach
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;styles/
  blocks/
    card/
      _card.scss
      _card--featured.scss
    button/
      _button.scss
      _button--large.scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing Global Styles with BEM
&lt;/h3&gt;

&lt;p&gt;While BEM excels at component-level styling, you still need global styles for base elements, typography, and utilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Global base styles (not BEM)
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  line-height: 1.6;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 1rem 0;
  font-weight: 600;
}

// BEM components
.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  &amp;amp;__title {
    // Inherits from global h2 styles
    color: #333;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance Considerations
&lt;/h3&gt;

&lt;h3&gt;
  
  
  CSS Size Management
&lt;/h3&gt;

&lt;p&gt;BEM can lead to longer class names, which might increase the CSS file size. Mitigate this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using CSS minification in production&lt;/li&gt;
&lt;li&gt;Implementing purging of unused CSS&lt;/li&gt;
&lt;li&gt;Considering critical CSS extraction&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Specificity Benefits
&lt;/h3&gt;

&lt;p&gt;BEM naturally creates consistent, low specificity selectors, improving CSS performance and reducing cascade conflicts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Good: Low, consistent specificity */
.card { }                    /* 0,0,1,0 */
.card__title { }             /* 0,0,1,0 */
.card--featured { }          /* 0,0,1,0 */

/* Avoid: High specificity conflicts */
.sidebar .card .title { }    /* 0,0,3,0 */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Team Adoption Strategies
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;Create clear guidelines for your team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block naming conventions&lt;/li&gt;
&lt;li&gt;When to create new blocks vs. modifying existing ones&lt;/li&gt;
&lt;li&gt;Approved modifier patterns&lt;/li&gt;
&lt;li&gt;File organization standards&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Review Checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Are class names following BEM syntax correctly?&lt;/li&gt;
&lt;li&gt;Is the block/element relationship logical?&lt;/li&gt;
&lt;li&gt;Are modifiers descriptive and consistent?&lt;/li&gt;
&lt;li&gt;Could any elements be simplified or combined?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gradual Implementation
&lt;/h3&gt;

&lt;p&gt;Don't attempt to convert entire codebases overnight. Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with new components using BEM&lt;/li&gt;
&lt;li&gt;Refactor existing components during regular maintenance&lt;/li&gt;
&lt;li&gt;Establish BEM as the standard for new development&lt;/li&gt;
&lt;li&gt;Document the migration process and timeline&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;&lt;em&gt;BEM represents more than just a naming convention&lt;/em&gt;. It's a systematic approach to writing maintainable, scalable CSS that stands the test of time. By providing clear structure and meaningful relationships between components, BEM helps development teams create more predictable and debuggable stylesheets.&lt;/p&gt;

&lt;p&gt;While &lt;em&gt;BEM may seem wordy initially&lt;/em&gt;, its benefits become apparent as projects grow in complexity. The methodology's emphasis on clarity over brevity pays dividends in reduced debugging time, easier onboarding of new team members, and more confident refactoring.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;key to successful BEM implementation lies in understanding its core principles&lt;/em&gt; rather than rigidly following its syntax. Focus on creating logical, semantic relationships between your CSS classes, maintain consistency across your codebase, and don't hesitate to adapt the methodology to fit your specific project needs.&lt;/p&gt;

&lt;p&gt;As the web development landscape continues to evolve with new frameworks and tools, &lt;em&gt;BEM's foundational principles of modularity, clarity, and maintainability remain as relevant&lt;/em&gt; as ever. Whether you choose to adopt BEM wholesale or incorporate its concepts into your existing workflow, understanding this methodology will make you a more thoughtful and effective CSS developer.&lt;/p&gt;

&lt;p&gt;Remember: &lt;strong&gt;&lt;em&gt;the best CSS architecture is the one your team can consistently implement and maintain&lt;/em&gt;&lt;/strong&gt;. BEM provides an excellent foundation, but success ultimately depends on clear documentation, team buy-in, and consistent application of whatever standards you choose to adopt.&lt;/p&gt;

</description>
      <category>bem</category>
      <category>css</category>
      <category>sass</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Top 3 Web Security Vulnerabilities Every Developer Should Understand</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Fri, 29 Aug 2025 17:49:26 +0000</pubDate>
      <link>https://dev.to/michael-gokey/top-3-web-security-vulnerabilities-every-developer-should-understand-46hf</link>
      <guid>https://dev.to/michael-gokey/top-3-web-security-vulnerabilities-every-developer-should-understand-46hf</guid>
      <description>&lt;p&gt;Think about web security; it’s tempting to assume that firewalls, antivirus software, and strong passwords are enough. Yet most successful attacks don’t start at the network edge; they slip through cracks in the way applications are built. The real battleground for security is often in the very forms, queries, and scripts developers write every day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF)
&lt;/h3&gt;

&lt;p&gt;Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF) are two major web security threats. Both can cause serious damage to websites and users.&lt;/p&gt;

&lt;p&gt;XSS happens when bad actors put harmful code into trusted websites. When users visit these sites, the bad code runs in their web browser. This can steal cookies, passwords, or personal information. Think of it like someone hiding a virus in a letter that activates when you open it.&lt;/p&gt;

&lt;p&gt;CSRF is different. It tricks users who are already logged into a website into doing things they don't want to do. For example, an attacker might make you change your password or send money without knowing it. This happens because the website thinks the request came from you.&lt;/p&gt;

&lt;p&gt;To stop XSS attacks, you should clean all user inputs before using them. Use content security policies to control what scripts can run. Pick web frameworks that have built-in XSS protection. Always encode data before showing it to users.&lt;/p&gt;

&lt;p&gt;To prevent CSRF attacks, use special tokens that prove requests are real. Check where requests come from. Set your cookies to "SameSite" mode. Ask users to re-enter their password for important actions.&lt;/p&gt;

&lt;p&gt;Good session management helps with both threats. Use secure cookies that can't be accessed by scripts. Change session IDs regularly. Set timeouts so users get logged out after being inactive. Keep sensitive data on your servers, not in users' browsers.&lt;/p&gt;

&lt;p&gt;Finally, follow good coding practices. Test your security regularly. Keep your software updated. These simple steps will help protect your website and users.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Injection Attacks and Form Protection
&lt;/h3&gt;

&lt;p&gt;SQL injection is a serious web security threat. It happens when attackers put harmful database code into your website's input fields. They do this to steal, change, or destroy your data.&lt;/p&gt;

&lt;p&gt;This attack works when websites don't properly check user input before adding it to database commands. For example, an attacker might type ' OR '1'='1' -- into a login box. This trick code can let them log in without knowing the real password.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to Protect Your Forms
&lt;/h4&gt;

&lt;p&gt;The best way to stop SQL injection is to use parameterized queries. These are also called prepared statements. Instead of mixing user input directly into your database commands, you use placeholders.&lt;/p&gt;

&lt;p&gt;Here's the difference: Bad code looks like SELECT  FROM users WHERE username = '" + userInput + "'. Good code looks like SELECT  FROM users WHERE username = ? and sends the user input separately. This way, the database treats user input as data, not as commands.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other Ways to Stay Safe
&lt;/h4&gt;

&lt;p&gt;Check all user input carefully. Only allow letters, numbers, and symbols you expect. Use stored procedures when you can. Give database accounts only the permissions they actually need. Clean user input by escaping special characters. Add a web application firewall for extra protection.&lt;/p&gt;

&lt;p&gt;Many modern web frameworks have built-in tools called ORMs. These automatically use safe database queries. This makes it much easier to avoid SQL injection problems.&lt;/p&gt;

&lt;p&gt;Test your security often. Use both automated tools and manual checks. Find and fix problems before the bad guys do. Regular testing helps keep your website and data safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insecure Direct Object References (IDOR)
&lt;/h3&gt;

&lt;p&gt;Another common but often overlooked vulnerability is Insecure Direct Object References (IDOR). This occurs when an application exposes references to internal objects such as files, database records, or keys, without properly checking whether the user is authorized to access them. For example, imagine a URL like &lt;code&gt;/profile?id=1234&lt;/code&gt;. If the application doesn’t verify ownership, a malicious user could change the value to &lt;code&gt;1235&lt;/code&gt; and gain access to another user’s profile.&lt;/p&gt;

&lt;p&gt;To fix this, always check user permissions on the server before sharing sensitive data. Don’t use easy-to-guess IDs. Use random values like UUIDs instead. Make sure each user role can only access what they’re supposed to.&lt;/p&gt;

&lt;p&gt;Vulnerabilities like XSS, CSRF, SQL injection, and IDOR aren’t just theoretical. They are used by attackers all the time! The upside is that with secure coding, careful design, and regular testing, you can stop most of these problems before they reach production.&lt;/p&gt;

&lt;p&gt;Which of these vulnerabilities do you think developers forget, or struggle with the most, and why?&lt;/p&gt;

&lt;p&gt;🏷hashtags:&lt;br&gt;
&lt;strong&gt;#WebSecurity&lt;br&gt;
#CyberSecurity&lt;br&gt;
#AppSec&lt;br&gt;
#WebDevelopment&lt;br&gt;
#InfoSec&lt;br&gt;
#CodingBestPractices&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>websecurity</category>
      <category>codingbestpractices</category>
      <category>webdev</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>A Beginner DBA's Guide to SSRS Reports</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Mon, 23 Jun 2025 17:57:39 +0000</pubDate>
      <link>https://dev.to/michael-gokey/a-beginner-dbas-guide-to-ssrs-reports-24lh</link>
      <guid>https://dev.to/michael-gokey/a-beginner-dbas-guide-to-ssrs-reports-24lh</guid>
      <description>&lt;p&gt;Remember the first time someone asked you to "put that data in a report"? &lt;/p&gt;

&lt;p&gt;You probably stared at your perfectly good SQL query results and thought, "Isn't this already a report?" Then you realized they wanted something their boss could actually look at without squinting at raw data tables.&lt;/p&gt;

&lt;p&gt;Here's the thing nobody tells new DBAs: Writing great queries is only half the job. The other half is making that data speak to people who don't think in SELECT statements.&lt;/p&gt;

&lt;p&gt;That's where SSRS comes in. And no, it's not as scary as it sounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is SSRS Anyway?
&lt;/h2&gt;

&lt;p&gt;SSRS (SQL Server Reporting Services) is Microsoft's tool for turning your SQL query results into &lt;strong&gt;professional, interactive reports&lt;/strong&gt;. Think of it as a translator between your database and everyone else.&lt;/p&gt;

&lt;p&gt;You know that query you wrote to check which products are selling best? SSRS can turn that into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean, formatted tables&lt;/li&gt;
&lt;li&gt;Visual charts that tell a story&lt;/li&gt;
&lt;li&gt;Automated email reports&lt;/li&gt;
&lt;li&gt;Interactive dashboards where users can drill down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's powerful, and once you get the hang of it, surprisingly straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's Build Your First Report
&lt;/h2&gt;

&lt;p&gt;Here's exactly how I walk junior DBAs through their first SSRS report. No fluff, just the steps that matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Start With Good SQL
&lt;/h3&gt;

&lt;p&gt;This is your foundation. What story are you trying to tell with the data?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;ProductCategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Revenue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalRevenue&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;SalesData&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;ProductCategory&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;TotalRevenue&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you touch SSRS, make sure your query answers a clear business question. Like: &lt;em&gt;"Which product categories make us the most money?"&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Fire Up Report Builder
&lt;/h3&gt;

&lt;p&gt;If you're new to this, use &lt;strong&gt;Report Builder&lt;/strong&gt; instead of Visual Studio. It's free, and Microsoft built it specifically for people who aren't full-time report developers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new report&lt;/li&gt;
&lt;li&gt;Connect to your SQL database&lt;/li&gt;
&lt;li&gt;Add your query as a dataset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The wizard will walk you through it. Don't overthink this part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Pick Your Layout
&lt;/h3&gt;

&lt;p&gt;SSRS will ask you what kind of report you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Table&lt;/strong&gt; – when you need to show detailed rows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matrix&lt;/strong&gt; – think pivot table for grouping data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chart&lt;/strong&gt; – when patterns matter more than individual numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our revenue example, a bar chart makes the story obvious at a glance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Design It
&lt;/h3&gt;

&lt;p&gt;This is where you connect your data to the visual layout. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag columns where you want them&lt;/li&gt;
&lt;li&gt;Group related data together&lt;/li&gt;
&lt;li&gt;Add totals and calculations&lt;/li&gt;
&lt;li&gt;Make it look professional with formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Keep it simple. Your data should be the star, not fancy colors and fonts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Test Everything
&lt;/h3&gt;

&lt;p&gt;Use the &lt;strong&gt;Preview&lt;/strong&gt; tab religiously. Check your report with different data scenarios. Add parameters so users can filter by date range or region.&lt;/p&gt;

&lt;p&gt;Watch for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing or unexpected data&lt;/li&gt;
&lt;li&gt;Charts that look weird with small datasets&lt;/li&gt;
&lt;li&gt;Formatting that breaks with long text&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6: Share It With the World
&lt;/h3&gt;

&lt;p&gt;Deploy your report to the &lt;strong&gt;SSRS Web Portal&lt;/strong&gt;. Now your team can access it through any web browser.&lt;/p&gt;

&lt;p&gt;You can also set up &lt;strong&gt;subscriptions&lt;/strong&gt; to email reports automatically. Nothing makes you look more professional than having that monthly summary hit everyone's inbox right on schedule.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for Your Career
&lt;/h2&gt;

&lt;p&gt;As a DBA, you usually work behind the scenes. You tune queries, manage backups, keep the lights on. Important work, but invisible work.&lt;/p&gt;

&lt;p&gt;SSRS changes that dynamic. When you build reports that help people make better decisions, you become part of the conversation. You're not just maintaining data – you're translating it into insights.&lt;/p&gt;

&lt;p&gt;That moment when someone says "Can you show me that in a chart?" becomes your chance to shine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your Next Steps
&lt;/h2&gt;

&lt;p&gt;Ready to try this? Here's what I recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick one SQL query you run regularly&lt;/li&gt;
&lt;li&gt;Ask a colleague what data would make their job easier&lt;/li&gt;
&lt;li&gt;Turn that into a simple SSRS report&lt;/li&gt;
&lt;li&gt;Set it to email you every week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start small. Get comfortable with the process. You'll improve with each report you build.&lt;/p&gt;




&lt;h2&gt;
  
  
  Level Up Challenge
&lt;/h2&gt;

&lt;p&gt;Take your favorite SQL query and turn it into a parameterized SSRS report. Then schedule it to email you every Monday morning with fresh data.&lt;/p&gt;

&lt;p&gt;That's not just a report – that's automation. That's you becoming the person everyone comes to when they need data that actually makes sense.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to see this in action? I'm working on some starter templates and examples. Drop a comment if you'd like me to share the SQL and RDL files when they're ready.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dba</category>
      <category>sql</category>
      <category>ssrs</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Beginner’s Guide to SQL Server Stored Procedures</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Tue, 17 Jun 2025 01:39:04 +0000</pubDate>
      <link>https://dev.to/michael-gokey/beginners-guide-to-sql-server-stored-procedures-2o6a</link>
      <guid>https://dev.to/michael-gokey/beginners-guide-to-sql-server-stored-procedures-2o6a</guid>
      <description>&lt;p&gt;Imagine you're new to a software team.&lt;br&gt;
You notice the same chunk of database code (SQL) copied and pasted in five different places.&lt;br&gt;
Your lead developer says, "Hey, we should make this a 'stored procedure' instead."" You nod confidently, but inside you're thinking, "What exactly is a stored procedure, and why does everyone keep talking about them?" If you're a new developer or DBA who's heard the term thrown around but never quite understood the hype, you're in the right place. Let's demystify stored procedures and show you why they're one of the most powerful tools in your database toolkit.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR - The Quick Facts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What&lt;/strong&gt;: Reusable SQL code blocks stored in the database run faster than regular SQL&lt;br&gt;
&lt;strong&gt;Why&lt;/strong&gt;: Better performance, improved security, and cleaner application code&lt;br&gt;
&lt;strong&gt;When&lt;/strong&gt;: Use for complex business logic, frequently-used queries, and data validation operations&lt;/p&gt;
&lt;h2&gt;
  
  
  What are Stored Procedures?
&lt;/h2&gt;

&lt;p&gt;A stored procedure is essentially a named group of SQL statements that you can execute as a single unit. Instead of your program sending many separate database commands, it can just ask the stored procedure to do all the work.&lt;br&gt;
It's like creating a shortcut. Instead of giving someone detailed instructions for "Get the milk" every time, you just say "Get Milk" and they know all the steps involved. SQL Server saves and optimizes your procedure the first time it runs, so it executes faster with repeated calls.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving in, make sure you're comfortable with:&lt;br&gt;
Basic SQL SELECT, INSERT, UPDATE, DELETE statements&lt;br&gt;
Understanding of database tables and relationships&lt;br&gt;
Basic knowledge of SQL Server Management Studio (SSMS) or similar database tools&lt;/p&gt;
&lt;h2&gt;
  
  
  Copy-Paste Starter Template
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Template: Basic Stored Procedure with Error Handling&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;YourProcedureName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Parameter1&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;        &lt;span class="c1"&gt;-- Input parameter&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Parameter2&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;-- Input parameter with default value&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;OutputParameter&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;OUTPUT&lt;/span&gt;     &lt;span class="c1"&gt;-- Output parameter (optional)&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="c1"&gt;-- Prevent extra result sets from interfering with SELECT statements&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
        &lt;span class="c1"&gt;-- Your main logic goes here&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Replace this with your actual SQL logic'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;

        &lt;span class="c1"&gt;-- Set output parameter if using one&lt;/span&gt;
        &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;OutputParameter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;ROWCOUNT&lt;/span&gt;

    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
        &lt;span class="c1"&gt;-- Handle errors gracefully&lt;/span&gt;
        &lt;span class="n"&gt;PRINT&lt;/span&gt; &lt;span class="s1"&gt;'Error occurred: '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ERROR_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;-- Return error code&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Practical Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Basic Procedure (No Parameters)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;GetAllEmployees&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;EmployeeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Department&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;
    &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FirstName&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetAllEmployees&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 2: Procedure with Input Parameters&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;-- Validate input&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt;
        &lt;span class="n"&gt;PRINT&lt;/span&gt; &lt;span class="s1"&gt;'Department name cannot be empty'&lt;/span&gt;
        &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt;

    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;EmployeeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Salary&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt;
    &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Sales'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 3: Procedure with Input and Output Parameters&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;GetEmployeeCount&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeCount&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;OUTPUT&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Department&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Count&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeeCount&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Marketing'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Count&lt;/span&gt; &lt;span class="k"&gt;OUTPUT&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Count&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalEmployees&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 4: Complex Business Logic with Transaction&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;ProcessEmployeeRaise&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaisePercentage&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
        &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;

        &lt;span class="c1"&gt;-- Validate inputs&lt;/span&gt;
        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaisePercentage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaisePercentage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
        &lt;span class="k"&gt;BEGIN&lt;/span&gt;
            &lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Raise percentage must be between 0 and 50'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt;

        &lt;span class="c1"&gt;-- Get current salary&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Salary&lt;/span&gt;
        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;EmployeeID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt;

        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
        &lt;span class="k"&gt;BEGIN&lt;/span&gt;
            &lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Employee not found'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt;

        &lt;span class="c1"&gt;-- Calculate new salary&lt;/span&gt;
        &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaisePercentage&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;-- Update the salary&lt;/span&gt;
        &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;
        &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;Salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;LastModified&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;EmployeeID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt;

        &lt;span class="c1"&gt;-- Log the change&lt;/span&gt;
        &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;SalaryHistory&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OldSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NewSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChangeDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;

        &lt;span class="c1"&gt;-- Return success message&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Salary updated successfully'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;OldSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;NewSalary&lt;/span&gt;

    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
        &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;
        &lt;span class="n"&gt;PRINT&lt;/span&gt; &lt;span class="s1"&gt;'Error processing raise: '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ERROR_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Comparison: Before and After
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Without stored procedure (slower)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TotalAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create this stored procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- With stored procedure (faster)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;GetCustomerOrderStats&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;NOCOUNT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;SELECT&lt;/span&gt; 
        &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;OrderCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TotalAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;AverageAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TotalAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalAmount&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stored procedure version will be faster because SQL Server compiles and caches the execution plan, plus it reduces network traffic by sending one call instead of multiple queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Your Stored Procedures
&lt;/h2&gt;

&lt;p&gt;Always test your procedures step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test with valid data first&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Sales'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test edge cases&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Test with NULL&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;

&lt;span class="c1"&gt;-- Test with empty string&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;

&lt;span class="c1"&gt;-- Test with non-existent department&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;GetEmployeesByDepartment&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DepartmentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Unicorn Department'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test error conditions&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Test with invalid parameters&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;ProcessEmployeeRaise&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EmployeeID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;999999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaisePercentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Debugging Stored Procedures
&lt;/h2&gt;

&lt;p&gt;When your procedure isn't working:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add PRINT statements&lt;/strong&gt; to see what's happening:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt; &lt;span class="s1"&gt;'Current salary: '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use SELECT statements&lt;/strong&gt; to check variable values:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;CurrentSalary&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;CurrentSalary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;NewSalary&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;NewSalary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run sections individually&lt;/strong&gt; - comment out parts of your procedure and test smaller pieces&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Benefits
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: SQL Server saves and optimizes your procedure, making repeat calls faster than sending the same SQL over and over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: Procedures help prevent SQL injection attacks and let you grant execute permissions without giving direct table access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;: Business logic lives in one place in the database, making updates easier without changing application code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Efficiency&lt;/strong&gt;: Send one procedure call instead of multiple SQL statements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Talk: When NOT to Use Stored Procedures
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Simple CRUD Operations&lt;/strong&gt;: If you're just doing basic INSERT/UPDATE/DELETE on single tables, stored procedures might be overkill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microservices Architecture&lt;/strong&gt;: When each service manages its own data, stored procedures can create tight coupling between services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ORM-Heavy Applications&lt;/strong&gt;: If your application uses Entity Framework or similar ORMs effectively, stored procedures might complicate your data layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing Complexity&lt;/strong&gt;: Stored procedures can make unit testing more difficult since they're harder to mock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version Control Challenges&lt;/strong&gt;: Database objects are trickier to version control than application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version Control Tips for Teams
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always script your procedures&lt;/strong&gt;: Use SSMS to generate CREATE scripts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use ALTER instead of DROP/CREATE&lt;/strong&gt; when modifying existing procedures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include rollback scripts&lt;/strong&gt; for procedure changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document parameter changes&lt;/strong&gt; clearly in your commit messages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Error Messages and Solutions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Procedure 'X' expects parameter 'Y', which was not supplied"&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solution: Check your parameter names and make sure you're passing all required parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;"Invalid object name 'TableName'"&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solution: Verify the table exists and you have permissions to access it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;"String or binary data would be truncated"&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solution: Check your parameter sizes match the data you're passing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where Stored Procedures Run
&lt;/h2&gt;

&lt;p&gt;Stored procedures are specific to &lt;strong&gt;Microsoft SQL Server&lt;/strong&gt;. Other database systems have similar concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MySQL&lt;/strong&gt;: Also calls them stored procedures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt;: Has stored procedures and functions
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oracle&lt;/strong&gt;: Uses PL/SQL procedures and functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite&lt;/strong&gt;: Doesn't support stored procedures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try This Now
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Pick a common query&lt;/li&gt;
&lt;li&gt;Turn it into a stored procedure&lt;/li&gt;
&lt;li&gt;Add validation&lt;/li&gt;
&lt;li&gt;Test with various inputs&lt;/li&gt;
&lt;li&gt;Compare execution time&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;As you get comfortable with basic stored procedures, explore the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stored functions (return single values)&lt;/li&gt;
&lt;li&gt;Table-valued functions (return result sets)&lt;/li&gt;
&lt;li&gt;Triggers (procedures that run automatically)&lt;/li&gt;
&lt;li&gt;Dynamic SQL within stored procedures (advanced topic)&lt;/li&gt;
&lt;li&gt;Recursive procedures for hierarchical data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember: the best way to learn stored procedures is by writing them. Start simple, test thoroughly, and gradually add complexity as your confidence grows.&lt;/p&gt;

&lt;p&gt;Happy coding, and welcome to the world of stored procedures!&lt;/p&gt;

</description>
      <category>storedprocedures</category>
      <category>database</category>
      <category>sql</category>
      <category>dba</category>
    </item>
    <item>
      <title>Understanding T-SQL vs PL/SQL Database Curveballs</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Fri, 13 Jun 2025 16:46:32 +0000</pubDate>
      <link>https://dev.to/michael-gokey/understanding-t-sql-vs-plsql-database-curveballs-4cgo</link>
      <guid>https://dev.to/michael-gokey/understanding-t-sql-vs-plsql-database-curveballs-4cgo</guid>
      <description>&lt;p&gt;Picture this: You're troubleshooting an application that worked perfectly on SQL Server. Now it's being moved to Oracle, and everything suddenly seems out of order. The code looks familiar, but it's throwing errors left and right. Welcome to the world of database dialects.&lt;/p&gt;

&lt;p&gt;Here's the thing most people don't tell you: SQL isn't just SQL. Microsoft and Oracle each built their own flavor, and they're different enough to make your head spin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are We Even Talking About?
&lt;/h2&gt;

&lt;p&gt;T-SQL is Microsoft's procedural extension to SQL. It's what SQL Server speaks. PL/SQL is Oracle's procedural language. The same basic idea, a totally different execution.&lt;/p&gt;

&lt;p&gt;Think of it like American English vs British English. You'll understand most of it, but some words mean completely different things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stuff That'll Trip You Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting Up Variables
&lt;/h3&gt;

&lt;p&gt;In SQL Server (T-SQL), you declare and go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty straightforward, right?&lt;/p&gt;

&lt;p&gt;Oracle (PL/SQL) requires structured blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;DECLARE&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt; &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;BEGIN&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DBMS_OUTPUT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT_LINE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See that? Oracle wants everything wrapped in a structured block with declaration and execution sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Things Go Wrong
&lt;/h3&gt;

&lt;p&gt;SQL Server keeps it simple with try-catch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- your risky code here&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;TRY&lt;/span&gt;

&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;ERROR_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;CATCH&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oracle does its own thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- your risky code here&lt;/span&gt;

&lt;span class="n"&gt;EXCEPTION&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;OTHERS&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DBMS_OUTPUT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUT_LINE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SQLERRM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Here's where things get interesting.&lt;/p&gt;

&lt;p&gt;SQL Server compiles your code when you first run it. Then it remembers what it did. This works great for most situations.&lt;/p&gt;

&lt;p&gt;Oracle pre-compiles everything and stores it in the database. It's like meal prep for your database. More work upfront, but it can be faster for complex stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where You'll Find Each One
&lt;/h2&gt;

&lt;p&gt;You'll bump into T-SQL when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Working with Microsoft shops&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dealing with .NET applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Managing Azure databases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Companies want quick results&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PL/SQL shows up in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Big corporations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Banks and government systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Places where the database does heavy lifting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environments where performance is everything&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Migration Headaches
&lt;/h2&gt;

&lt;p&gt;Moving between these systems? Here's what'll bite you:&lt;/p&gt;

&lt;p&gt;Data types are different. Oracle uses VARCHAR2, and SQL Server uses VARCHAR. Oracle has NUMBER, SQL Server has INT, and DECIMAL.&lt;/p&gt;

&lt;p&gt;String concatenation is different. Oracle uses || to join strings together. SQL Server uses +.&lt;/p&gt;

&lt;p&gt;Dates are a nightmare. Oracle has SYSDATE. SQL Server has GETDATE(). They don't play nice together.&lt;/p&gt;

&lt;p&gt;Stored procedures work differently. Oracle bundles them together in packages. SQL Server treats each one separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for You
&lt;/h2&gt;

&lt;p&gt;Don't panic when you switch between systems. The core SQL stuff transfers over fine. It's the fancy programming bits that change.&lt;/p&gt;

&lt;p&gt;The trick is knowing which system you're working with. Then you can speak its language instead of fighting it.&lt;/p&gt;

&lt;p&gt;Most of your SQL knowledge still applies. You need to learn each database's personality quirks. Think of it like learning to drive different cars; the basics are the same, but every model has its own dashboard layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Both T-SQL and PL/SQL do the same job. They have different ways of getting there. Oracle is more formal and structured. SQL Server is more relaxed and flexible.&lt;/p&gt;

&lt;p&gt;Know which one you're dealing with, and you'll save yourself hours of head-scratching.&lt;/p&gt;

</description>
      <category>tsql</category>
      <category>plsql</category>
      <category>database</category>
      <category>dba</category>
    </item>
    <item>
      <title>Advanced NgRx Patterns for Enterprise Angular Applications</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Tue, 20 May 2025 03:59:55 +0000</pubDate>
      <link>https://dev.to/michael-gokey/advanced-ngrx-patterns-for-enterprise-angular-applications-5ki</link>
      <guid>https://dev.to/michael-gokey/advanced-ngrx-patterns-for-enterprise-angular-applications-5ki</guid>
      <description>&lt;p&gt;Welcome to the final installment of our NgRx deep-dive series! In Parts 1 and 2, we covered the &lt;a href="https://dev.to/michael-gokey/building-a-multi-module-angular-application-with-ngrx-11p6"&gt;Angular and NgRx fundamentals&lt;/a&gt; and &lt;a href="https://dev.to/michael-gokey/ngrx-state-management-across-angular-modules-264"&gt;intermediate state patterns&lt;/a&gt;. Now, we're tackling the juicy stuff; the advanced patterns that'll save your sanity when your enterprise Angular app starts growing.  &lt;em&gt;(⏱️ Est reading time: 9.5 min)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're dealing with complex state management challenges in large-scale applications, you've probably felt the pain of tangled observables, redundant calculations, and components that re-render for no good reason. Let's solve those problems together with some battle-tested NgRx patterns I've used across dozens of enterprise projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization with Selectors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Power of Memoized Selectors
&lt;/h3&gt;

&lt;p&gt;You'll use selectors to derive data without doing extra work and thanks to NgRx's memoization, your app stays fast even when the state grows. Think of selectors as your first line of defense against performance issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Feature state interface&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DashboardState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metric&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Basic selectors&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectDashboardState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createFeatureSelector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectAllMetrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectDashboardState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Derived selectors with memoization benefits&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectActiveMetrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectAllMetrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Complex calculations that won't recompute unnecessarily&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectMetricsSummary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectActiveMetrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This saves you from running expensive logic every time Angular blinks,&lt;/span&gt;
    &lt;span class="c1"&gt;// Especially important when rendering dashboards or charts&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;average&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
        &lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;activeMetrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;This prevents unnecessary component re-renders and keeps Angular's change detection lean. Your users will notice the difference when they're rapidly interacting with data-heavy interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selector Composition for Complex Data Transformations
&lt;/h3&gt;

&lt;p&gt;When your app's complexity increases, you'll want to create small, focused selectors that you can compose together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Combining data from multiple slices of state&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectUserPermissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;authSelectors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectCurrentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;roleSelectors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAllRoles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;roleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;userRole&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;||&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;span class="c1"&gt;// Building on existing selectors for dashboard-specific permissions&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectUserDashboardPermissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectUserPermissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&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;I've found this approach invaluable when different teams are working on different parts of the application. Each team can build on existing selectors without duplicating logic or stepping on each other's toes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Authentication and Security with NgRx
&lt;/h2&gt;

&lt;p&gt;Let's be real; authentication is one of those things that's simple in concept but gets messy fast. NgRx gives you a clean way to manage all the moving parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication State Design
&lt;/h3&gt;

&lt;p&gt;Here's a practical auth state that covers all the bases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastAuthAttempt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialAuthState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastAuthAttempt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authentication Actions
&lt;/h3&gt;

&lt;p&gt;I like to be specific with my auth actions so debugging is easier down the road:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Auth] Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loginSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Auth] Login Success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loginFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Auth] Login Failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkAuthStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Auth] Check Status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Auth] Logout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authentication Effects for Token Management
&lt;/h3&gt;

&lt;p&gt;Here's where the real magic happens; effects that handle the token lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthEffects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;login$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;exhaustMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="c1"&gt;// Note: exhaustMap is used here to avoid parallel login attempts&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Store token in secure storage&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;storeToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loginSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}),&lt;/span&gt;
          &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loginFailure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
            &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authentication failed&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;logout$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Clear token on logout&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Effect to check auth status on app initialization&lt;/span&gt;
  &lt;span class="nx"&gt;checkAuth$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkAuthStatus&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&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="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logout&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loginSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
          &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logout&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;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TokenService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&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;I've seen too many apps where tokens are handled inconsistently across components. This centralized approach gives you one source of truth for auth state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route Guards with NgRx State
&lt;/h2&gt;

&lt;p&gt;Guards are where your auth state becomes a security boundary. Here's how to hook them up to NgRx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectIsAuthenticated&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RoleGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRouteSnapshot&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requiredRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectUserRole&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userRole&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;userRole&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;requiredRole&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasAccess&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasAccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These guards are easily testable via mock store observables, which helps catch auth regressions. I can't tell you how many security holes I've prevented by having solid tests around these guards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entity Management for Data Collections
&lt;/h2&gt;

&lt;p&gt;If you're building an enterprise app, you're probably dealing with lots of collections, users, products, orders, you name it. The &lt;code&gt;@ngrx/entity&lt;/code&gt; package is your best friend here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Entity Adapters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;roleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;EntityState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;selectedUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createEntityAdapter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sortComparer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Optional sort by name&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInitialState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selectedUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup allows O(1) lookups and makes UI list rendering super cheap. Your users will thank you when they can scroll through thousands of records without lag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entity Reducers for Common Operations
&lt;/h3&gt;

&lt;p&gt;The adapter gives you helper methods that handle the heavy lifting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// Load operations&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadUsers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadUsersSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&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;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c1"&gt;// Add/update/remove operations&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c1"&gt;// Selection state&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;selectedUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&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;h3&gt;
  
  
  Entity Selectors for Efficient Data Access
&lt;/h3&gt;

&lt;p&gt;Here's where it all comes together, the adapter gives you optimized selectors out of the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;selectIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectEntities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectTotal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createFeatureSelector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Extended selectors&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectSelectedUserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;createFeatureSelector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedUserId&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectSelectedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectEntities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;selectSelectedUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectedId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;selectedId&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectActiveUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&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;I've worked on apps where we tried to roll our own entity management before discovering this pattern. Trust me, it's not worth reinventing this wheel!&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging &amp;amp; Troubleshooting NgRx Applications
&lt;/h2&gt;

&lt;p&gt;When things go wrong (and they will), you need visibility into your state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redux DevTools Integration
&lt;/h3&gt;

&lt;p&gt;The Redux DevTools Extension is an absolute must-have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;StoreModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;StoreDevtoolsModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Retains last 25 states&lt;/span&gt;
      &lt;span class="na"&gt;logOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;autoPause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Pauses recording actions when the browser tab is not active&lt;/span&gt;
      &lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Include stack trace for dispatched actions&lt;/span&gt;
      &lt;span class="na"&gt;traceLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Maximum stack trace frames to be stored&lt;/span&gt;
      &lt;span class="na"&gt;connectOutsideZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Connect outside Angular's zone for better performance&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will save you countless hours of debugging. Being able to travel through state changes is like having a superpower when tracking down bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Meta-Reducers for Logging and Debugging
&lt;/h3&gt;

&lt;p&gt;For those times when you need extra visibility, meta-reducers can be your secret weapon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionReducer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ActionReducer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`%c prev state`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color: #9E9E9E; font-weight: bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`%c action`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color: #03A9F4; font-weight: bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`%c next state`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color: #4CAF50; font-weight: bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupEnd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nextState&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metaReducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetaReducer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;debug&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;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;StoreModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;metaReducers&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've solved many tricky bugs by seeing exactly what changed between states. Just remember to disable this in production!&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending State Architecture as Apps Grow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Feature State Composition Pattern
&lt;/h3&gt;

&lt;p&gt;As your team grows, you'll want to split your state into manageable chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Root state interface&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterReducerState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Extended with lazy-loaded feature states&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;users&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;DashboardState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ReportState&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;h3&gt;
  
  
  Dynamic Module Federation with NgRx
&lt;/h3&gt;

&lt;p&gt;For large applications, you'll leverage NgRx's forFeature method in lazy-loaded modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;StoreModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userReducer&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;EffectsModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forFeature&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;UserEffects&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other module imports&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;UserListComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;UserDetailComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other components&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've found this approach invaluable on large teams. Each feature team can own their slice of state while still playing nicely with the global store.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Normalization for Complex Data Relationships
&lt;/h3&gt;

&lt;p&gt;If your data has complex relationships, normalization will save you tons of headaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of nested data:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;badlyNestedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;departments&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;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Engineering&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;employees&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;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;projects&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;projects&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;span class="p"&gt;]&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;span class="c1"&gt;// Use normalized state with references:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;departments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Engineering&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;employeeIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dept2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Marketing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;employeeIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp4&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;projectIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emp2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;projectIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// ...other employees&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;proj1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dashboard Redesign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// ...other projects&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;I've seen teams get into a world of pain with this nested state. Normalization might feel like extra work at first, but it pays massive dividends as your app evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Throughout this three-part series, we've gone from NgRx basics to these advanced patterns that will help your enterprise Angular applications scale gracefully. I've used these techniques on applications with hundreds of components and dozens of developers, and they've been crucial for keeping complexity under control.&lt;/p&gt;

&lt;p&gt;The real power comes when you combine these patterns: memoized selectors feeding normalized entity data to performant components, all while maintaining security with NgRx-powered auth state and guards. It's a beautiful thing when it all comes together!&lt;/p&gt;

&lt;p&gt;As your application grows, remember these key takeaways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use selectors strategically&lt;/strong&gt; to prevent unnecessary re-renders&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralize authentication logic&lt;/strong&gt; in NgRx effects to ensure consistent security&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage @ngrx/entity&lt;/strong&gt; for all your collection management needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep debugging tools configured&lt;/strong&gt; to catch issues early&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split your state&lt;/strong&gt; into feature modules as your application grows&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What patterns have you found most helpful in your NgRx journey? What anti-patterns have you seen pop up?&lt;br&gt;
I'd love to hear about your experiences in the comments. And if you found this series valuable, share it with a fellow Angular developer wrestling with state management!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>ngrx</category>
      <category>angular</category>
    </item>
    <item>
      <title>NgRx State Management Across Angular Modules</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Tue, 20 May 2025 03:58:41 +0000</pubDate>
      <link>https://dev.to/michael-gokey/ngrx-state-management-across-angular-modules-264</link>
      <guid>https://dev.to/michael-gokey/ngrx-state-management-across-angular-modules-264</guid>
      <description>&lt;p&gt;&lt;strong&gt;Part 2: Structuring Shared State in Large Applications&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Part 1, we explored the &lt;a href="https://dev.to/michael-gokey/building-a-multi-module-angular-application-with-ngrx-11p6"&gt;basics of NgRx&lt;/a&gt; and why a centralized state can help tame complexity in modern Angular applications.&lt;/p&gt;

&lt;p&gt;In Part 2, we’ll move beyond the fundamentals into the real-world challenge of &lt;strong&gt;sharing state across Angular modules&lt;/strong&gt; without creating tight coupling or a tangled mess of selectors and actions. &lt;em&gt;(⏱️ Estimated reading time: 4.5 minutes)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Understanding the Problem
&lt;/h2&gt;

&lt;p&gt;Imagine you're building a house with several rooms. Each room serves a different purpose, but everyone in the house needs to know if it’s day or night, hot or cold, or if someone’s at the door.&lt;/p&gt;

&lt;p&gt;In Angular, each &lt;strong&gt;feature module&lt;/strong&gt; is like a room, self-contained, but part of the same living space.&lt;/p&gt;

&lt;p&gt;Now imagine that instead of a shared thermostat or central lighting control, every room makes its &lt;em&gt;own guess&lt;/em&gt; about the time of day or the temperature. That’s what happens in Angular apps when modules try to manage state locally, in isolation; you get &lt;strong&gt;duplicate logic, inconsistent behavior, and poor user experience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;NgRx&lt;/strong&gt; shines. It gives your Angular app a &lt;strong&gt;centralized information desk&lt;/strong&gt; (aka the Store) that every module can subscribe to and contribute to, in a clean, consistent way.&lt;/p&gt;

&lt;p&gt;But here’s the catch:&lt;br&gt;
While NgRx makes centralized state management &lt;em&gt;possible&lt;/em&gt;, you still need &lt;strong&gt;intentional structure&lt;/strong&gt; to make it &lt;strong&gt;scalable&lt;/strong&gt; across multiple modules.&lt;/p&gt;


&lt;h2&gt;
  
  
  Review: NgRx Core Concepts
&lt;/h2&gt;

&lt;p&gt;Before we dive into cross-module concerns, let’s do a quick refresher on the building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt; – the single source of truth, holding your application’s state tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt; – plain objects that describe state changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducers&lt;/strong&gt; – pure functions that respond to actions and return new state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selectors&lt;/strong&gt; – reusable queries for retrieving slices of state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effects&lt;/strong&gt; – handling side effects like API calls or navigation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These concepts stay the same, but &lt;strong&gt;how you organize them&lt;/strong&gt; matters &lt;em&gt;a lot&lt;/em&gt; as your app scales.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Challenge: Sharing State Without Tangling Modules
&lt;/h2&gt;

&lt;p&gt;A common mistake in large Angular apps is allowing &lt;strong&gt;feature modules to directly reach into other modules' states.&lt;/strong&gt;&lt;br&gt;
This creates coupling and a nasty tangle when teams need to refactor or isolate functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal is shared understanding, not shared chaos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s what we want instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulated feature modules&lt;/strong&gt;, each managing its feature logic.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;core shared state slice&lt;/strong&gt;, defined in a neutral place (like &lt;code&gt;app.state.ts&lt;/code&gt; or a shared library).&lt;/li&gt;
&lt;li&gt;Well-named &lt;strong&gt;action contracts&lt;/strong&gt; and &lt;strong&gt;selectors&lt;/strong&gt; that modules can subscribe to without needing to know &lt;em&gt;who&lt;/em&gt; triggered the change.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Strategies for Cross-Module State
&lt;/h2&gt;

&lt;p&gt;Here are a few battle-tested approaches to organizing state across modules:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;Use Feature States Wisely&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each Angular module should define its own NgRx feature slice via &lt;code&gt;StoreModule.forFeature&lt;/code&gt;.&lt;br&gt;
Avoid trying to cram everything into a global root reducer.&lt;/p&gt;

&lt;p&gt;This keeps logic scoped, testable, and maintainable.&lt;/p&gt;

&lt;p&gt;But what if two modules need to interact?&lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;strong&gt;Create a Shared or Global Slice for Cross-Cutting Concerns&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes, multiple modules care about the same data, like user authentication, settings, or permissions.&lt;/p&gt;

&lt;p&gt;Put these into a &lt;strong&gt;shared state module&lt;/strong&gt; (e.g., &lt;code&gt;@app/state/core&lt;/code&gt;) and use &lt;code&gt;StoreModule.forRoot()&lt;/code&gt; to initialize it.&lt;/p&gt;

&lt;p&gt;Then expose clear selectors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectCurrentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectAuthState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other modules can import this shared selector without knowing how the data is stored or updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Use Facade Services to Hide Store Details&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You don’t want every component wiring up selectors and dispatching actions.&lt;br&gt;
Create a &lt;strong&gt;facade service&lt;/strong&gt; per module or domain, something like &lt;code&gt;UserFacade&lt;/code&gt; or &lt;code&gt;SettingsFacade&lt;/code&gt; to act as the single entry point.&lt;/p&gt;

&lt;p&gt;This service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wraps &lt;code&gt;select()&lt;/code&gt; calls into clean, reactive streams (like &lt;code&gt;currentUser$&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Dispatches actions behind readable method names (&lt;code&gt;loadUser()&lt;/code&gt;, &lt;code&gt;updatePreferences()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Decouples components from NgRx boilerplate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now your UI is easier to test and reason about.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Minimize Cross-Domain Dispatches&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Avoid letting one module dispatch actions that mutate another module’s state. Instead, use shared actions and let each reducer respond as needed; this keeps boundaries clear.&lt;/p&gt;




&lt;h2&gt;
  
  
  Case Study: AdminPortal State Structure
&lt;/h2&gt;

&lt;p&gt;In our AdminPortal app, we split our store into three key areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Core state&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;User profile&lt;/li&gt;
&lt;li&gt;App-level settings&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Feature state&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Each module (e.g., &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;dashboard&lt;/code&gt;, &lt;code&gt;reports&lt;/code&gt;) owns its slice&lt;/li&gt;
&lt;li&gt;Isolated selectors and reducers&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Shared utility state&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;UI loading flags&lt;/li&gt;
&lt;li&gt;Toaster notifications&lt;/li&gt;
&lt;li&gt;API error logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each module imports only the pieces it needs and uses facade services to access or update them.&lt;/p&gt;

&lt;p&gt;This keeps our modules independent, but still able to collaborate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up: Shared State Without the Pain
&lt;/h2&gt;

&lt;p&gt;Sharing state across Angular modules doesn’t have to feel like a plumbing nightmare.&lt;br&gt;
With the right NgRx structure, and some thoughtful use of shared slices, facades, and selectors, you can build apps that scale without getting brittle.&lt;/p&gt;

&lt;p&gt;NgRx isn’t just about centralizing data. It’s about creating &lt;strong&gt;clear boundaries&lt;/strong&gt;, &lt;strong&gt;predictable flows&lt;/strong&gt;, and &lt;strong&gt;confident teams&lt;/strong&gt; who know where things live and how they change.&lt;/p&gt;




&lt;h3&gt;
  
  
  Coming in Part 3:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;“&lt;a href="https://dev.to/michael-gokey/advanced-ngrx-patterns-for-enterprise-angular-applications-5ki"&gt;Optimizing NgRx for Performance and Developer Experience&lt;/a&gt;”&lt;/strong&gt;&lt;br&gt;
We’ll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memoized selectors and why they matter&lt;/li&gt;
&lt;li&gt;Lazy-loading state modules the right way&lt;/li&gt;
&lt;li&gt;Developer tooling, best practices, and debugging tips that make life easier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>redux</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Building a Multi-Module Angular Application with NgRx</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Tue, 20 May 2025 03:56:19 +0000</pubDate>
      <link>https://dev.to/michael-gokey/building-a-multi-module-angular-application-with-ngrx-11p6</link>
      <guid>https://dev.to/michael-gokey/building-a-multi-module-angular-application-with-ngrx-11p6</guid>
      <description>&lt;p&gt;Angular's modular design and NgRx state management allow for the maintainable, performant, and collaborative development of even intricate applications with varied user roles and features. &lt;em&gt;(Part 1, ⏱️ Estimated reading time: 5 minutes)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to the AdminPortal
&lt;/h2&gt;

&lt;p&gt;Meet &lt;strong&gt;AdminPortal&lt;/strong&gt;, a web application that helps organizations manage users and resources. Like many real-world apps, AdminPortal supports different areas for different people:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Administrators&lt;/strong&gt; need tools to manage users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managers&lt;/strong&gt; need dashboards to see team activity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular users&lt;/strong&gt; need access to their profiles and basic functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's not cram all of this into one big chunk of code. That'd be chaos. Instead, we broke the application into smaller, focused pieces called &lt;strong&gt;modules&lt;/strong&gt;. This improves maintainability, performance, and clarity.&lt;/p&gt;

&lt;p&gt;In this article, you'll get the high-level tour; a look at how AdminPortal is structured, how its pieces work together, and how NgRx ties it all up without going too deep into technical weeds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Application Architecture and Module Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Modules
&lt;/h3&gt;

&lt;p&gt;AdminPortal is built with five main modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Module&lt;/strong&gt;: The main shell that wires everything together, routing, bootstrap logic, and core services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Core Module&lt;/strong&gt;: Hosts essential singleton services used app-wide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication service&lt;/li&gt;
&lt;li&gt;HTTP interceptors (for auth tokens, error handling)&lt;/li&gt;
&lt;li&gt;Global error and session management&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Shared Module&lt;/strong&gt;: Reusable, stateless building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI components (buttons, cards, inputs)&lt;/li&gt;
&lt;li&gt;Pipes, directives&lt;/li&gt;
&lt;li&gt;TypeScript interfaces and helper models&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layout Module&lt;/strong&gt;: Defines the global layout (header, footer, sidebar).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Feature Modules&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auth Module&lt;/strong&gt;: Login, registration, password reset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard Module&lt;/strong&gt;: Role-based dashboards and user profiles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin Module&lt;/strong&gt;: Admin-only tools and user management&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Module Interaction and Lazy Loading
&lt;/h3&gt;

&lt;p&gt;The power of this structure lies in how the pieces fit:&lt;/p&gt;

&lt;p&gt;By implementing &lt;strong&gt;lazy loading&lt;/strong&gt;, feature modules are not loaded upfront but rather when they are navigated. This means that if a user never accesses the admin area, its code will not be loaded into the application.&lt;/p&gt;

&lt;p&gt;A key aspect is the &lt;strong&gt;limited sharing&lt;/strong&gt;; only Core and Shared modules are accessible throughout the application, ensuring that Feature modules remain isolated and do not directly depend on each other.&lt;/p&gt;

&lt;p&gt;NgRx for Centralized and Shared State. NgRx centralizes application-wide data (e.g., user authentication, roles) in a single store, leading to a shared state with well-defined boundaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Simplified Module Map:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App Module
├── Core Module (services, guards)
├── Layout Module (header, footer, sidebar)
├── Shared Module (components, pipes, models)
└── Feature Modules
 ├── Auth Module (login, registration)
 ├── Dashboard Module (user dashboard)
 └── Admin Module (user management)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Features and Role-Based Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication System
&lt;/h3&gt;

&lt;p&gt;Auth is handled through NgRx effects and a shared authentication service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users log in via the Auth Module&lt;/li&gt;
&lt;li&gt;Tokens are stored securely and used with API requests&lt;/li&gt;
&lt;li&gt;Session expiration is monitored; expired tokens trigger logout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authentication state is global:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Layout Module updates the header with the user profile&lt;/li&gt;
&lt;li&gt;Role-based routing and guards unlock or hide features&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Role-Based Access Control (RBAC)
&lt;/h3&gt;

&lt;p&gt;AdminPortal defines three main roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Administrators&lt;/strong&gt; – Full system access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managers&lt;/strong&gt; – Read-only access to team metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Users&lt;/strong&gt; – Personal profile and usage only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RBAC affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Navigation&lt;/strong&gt;: Sidebar and header options change per role&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing&lt;/strong&gt;: Unauthorized attempts trigger redirection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Features&lt;/strong&gt;: Certain buttons or views are hidden based on the role&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dashboards Tailored by Role
&lt;/h3&gt;

&lt;p&gt;Each user gets a personalized dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin Dashboard&lt;/strong&gt; – System-wide metrics, shortcuts to admin tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manager Dashboard&lt;/strong&gt; – Team statistics and limited admin features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Dashboard&lt;/strong&gt; – Personal usage, profile, recent activity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These dashboards reuse many components but differ in data and access logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  User Journeys
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Emily (Administrator)
&lt;/h3&gt;

&lt;p&gt;When Emily logs in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;She submits her credentials via the login form.&lt;/li&gt;
&lt;li&gt;The Auth Module verifies and stores her profile (including the admin role) in NgRx.&lt;/li&gt;
&lt;li&gt;She's redirected to the Admin Dashboard.&lt;/li&gt;
&lt;li&gt;The Layout Module updates to show admin-specific navigation.&lt;/li&gt;
&lt;li&gt;She clicks "User Management" to:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Edit user profiles&lt;/li&gt;
&lt;li&gt;Change permissions&lt;/li&gt;
&lt;li&gt;Disable accounts

&lt;ol&gt;
&lt;li&gt;Her changes are synced across the app via NgRx and backend API calls.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Siddarth (Regular User)
&lt;/h3&gt;

&lt;p&gt;When Siddarth logs in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;He logs in through the same Auth Module.&lt;/li&gt;
&lt;li&gt;His user role is stored in the NgRx store.&lt;/li&gt;
&lt;li&gt;He’s routed to the User Dashboard.&lt;/li&gt;
&lt;li&gt;The Layout Module hides admin links.&lt;/li&gt;
&lt;li&gt;He updates his profile and uses basic features.&lt;/li&gt;
&lt;li&gt;If he attempts to access &lt;code&gt;/admin&lt;/code&gt;, he’s redirected to &lt;code&gt;/dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Development Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clear Module Boundaries
&lt;/h3&gt;

&lt;p&gt;Each module focuses on one area:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth handles login and tokens&lt;/li&gt;
&lt;li&gt;Admin handles system-level features&lt;/li&gt;
&lt;li&gt;Dashboard manages user-specific views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes testing, maintenance, and team handoffs smoother.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared State with NgRx
&lt;/h3&gt;

&lt;p&gt;NgRx handles cross-cutting concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth state&lt;/li&gt;
&lt;li&gt;Current user profile&lt;/li&gt;
&lt;li&gt;Global settings (e.g., dark mode preference)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids tightly coupling feature modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route Guards &amp;amp; Smart Routing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each module has a route config&lt;/li&gt;
&lt;li&gt;Route guards enforce login and role-based access&lt;/li&gt;
&lt;li&gt;Lazy loading keeps the app lean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Visiting &lt;code&gt;/admin/users&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App checks login status&lt;/li&gt;
&lt;li&gt;Verifies admin role&lt;/li&gt;
&lt;li&gt;Grants or redirects accordingly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Shared Components &amp;amp; Design System
&lt;/h3&gt;

&lt;p&gt;The Shared Module powers UI consistency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buttons, inputs, cards, alerts&lt;/li&gt;
&lt;li&gt;Theming and accessibility&lt;/li&gt;
&lt;li&gt;Form controls behave the same across features&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Angular Modularity Principles in Action
&lt;/h2&gt;

&lt;p&gt;AdminPortal follows key design principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Responsibility&lt;/strong&gt;: One purpose per module/component/service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation&lt;/strong&gt;: Modules expose only what’s needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Components and services are flexible, not hardwired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Loading&lt;/strong&gt;: Users load only what they need&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;AdminPortal shows how modular Angular apps with NgRx can scale smoothly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams can work in parallel without stepping on each other&lt;/li&gt;
&lt;li&gt;Apps perform better with lazy loading&lt;/li&gt;
&lt;li&gt;Features are isolated, testable, and easier to maintain&lt;/li&gt;
&lt;li&gt;Role-based logic is secure and user-friendly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The takeaway?&lt;/strong&gt; Use Angular’s modular architecture &lt;em&gt;intentionally&lt;/em&gt;. Pair it with NgRx to manage a shared state without tight coupling. The result is a maintainable, real-world-ready application that evolves with your users and developer team.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>rxjs</category>
      <category>state</category>
    </item>
    <item>
      <title>The Algorithm of Critical Thinking: Teaching Devs to Think Before They Code</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Fri, 09 May 2025 01:06:28 +0000</pubDate>
      <link>https://dev.to/michael-gokey/the-algorithm-of-critical-thinking-teaching-devs-to-think-before-they-code-3j63</link>
      <guid>https://dev.to/michael-gokey/the-algorithm-of-critical-thinking-teaching-devs-to-think-before-they-code-3j63</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As junior developers begin their coding journeys, it's tempting to dive headfirst into the code, typing fast, googling snippets, and copying from Stack Overflow. While this kind of enthusiasm is great, the real secret to becoming a great developer isn’t just speed or syntax. It’s &lt;strong&gt;critical thinking&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This article explores how teaching developers to think &lt;em&gt;before&lt;/em&gt; they code can lead to cleaner, smarter, and more maintainable solutions. And to bring this to life, we'll use the creation of a &lt;strong&gt;Flashcard Game&lt;/strong&gt;, a simple card flipper built in HTML, CSS, and JavaScript as a working example. &lt;em&gt;⏱️ Estimated reading time: 2 minutes&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Think in Pseudocode
&lt;/h2&gt;

&lt;p&gt;Before you crack open your editor, pause. Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What exactly am I building?&lt;/li&gt;
&lt;li&gt;What are the parts?&lt;/li&gt;
&lt;li&gt;How will users interact with it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s apply this to our &lt;a href="https://dev.to/michael-gokey/flip-for-knowledge-building-a-flashcard-game-with-html-css-javascript-3o9j"&gt;Building a Flashcard Game with HTML, CSS &amp;amp; JavaScript&lt;/a&gt; and see the steps.&lt;br&gt;
You can go see &lt;a href="https://codepen.io/Michael-Gokey/pen/XJJPVZZ" rel="noopener noreferrer"&gt;FunCards in Action&lt;/a&gt; on CodePen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pseudocode Outline:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a container for flashcards
For each flashcard:
  - Show a question on the front
  - Show an answer on the back
  - Flip the card on click
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This level of clarity early on helps keep you grounded. It removes ambiguity, and forces you to think through the interaction model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Sketch the Architecture
&lt;/h2&gt;

&lt;p&gt;Every app, even a tiny one, has structure. Whether you’re working in a framework or plain vanilla HTML/JS/CSS, spend a minute mapping the architecture. Sketch the Architecture Mentally or Literally. Its a step in the right direction. &lt;/p&gt;

&lt;p&gt;In our Flashcard Game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt; creates the structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS&lt;/strong&gt; handles visual transitions, layout, and flipping animations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt; drives logic and user interaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding where each concern lives helps reduce messy code later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Think Like a User
&lt;/h2&gt;

&lt;p&gt;What’s the first thing a user will do? Click a card. What do they expect? A flip animation. Are they surprised by the content? Is it legible? Responsive?&lt;/p&gt;

&lt;p&gt;By simulating the user experience in your mind first, you can anticipate hiccups. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if someone clicks rapidly?&lt;/li&gt;
&lt;li&gt;What if they want to reset?&lt;/li&gt;
&lt;li&gt;Can it be extended to more cards or categories?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions don’t need answers immediately, but asking them shows maturity in your thinking process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Comment Before You Code
&lt;/h2&gt;

&lt;p&gt;Even before writing the actual logic, start with well-named &lt;code&gt;// comments&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Select container to hold all cards&lt;/span&gt;
&lt;span class="c1"&gt;// Loop through each flashcard item&lt;/span&gt;
&lt;span class="c1"&gt;// Create HTML structure for front and back&lt;/span&gt;
&lt;span class="c1"&gt;// Attach event listener for flip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This acts like scaffolding. It guides your build and makes the code more readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Build in Layers
&lt;/h2&gt;

&lt;p&gt;Start with a small slice of the functionality:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get one card to flip.&lt;/li&gt;
&lt;li&gt;Then expand to multiple cards.&lt;/li&gt;
&lt;li&gt;Then style and polish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Working this way teaches patience and reveals issues early, rather than snowballing complexity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the developer’s version of TDD (Test-Driven Development): &lt;em&gt;Think-Driven Development.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 6: Reflect and Refactor
&lt;/h2&gt;

&lt;p&gt;Once your Flashcard Game is functional, step back.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is your code reusable?&lt;/li&gt;
&lt;li&gt;Could this become a component or be extracted into a module?&lt;/li&gt;
&lt;li&gt;Are the HTML and CSS organized?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reflection is part of critical thinking. It’s where good devs separate from great ones.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts: "Thinking Is the Real Skill"
&lt;/h2&gt;

&lt;p&gt;The biggest value of this exercise isn’t the 10 flashcards or the flip animation. It’s learning how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Break a problem into parts.&lt;/li&gt;
&lt;li&gt;Think about user interaction.&lt;/li&gt;
&lt;li&gt;Build in small increments.&lt;/li&gt;
&lt;li&gt;Write code with intention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Flashcard Game&lt;/strong&gt; may look simple, but behind it is a layered thought process. And that’s the point.&lt;/p&gt;

&lt;p&gt;If you're a junior dev, or even a mid-level dev who wants to sharpen your instincts, remember:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Coding is just the output. Thinking is the real skill.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;🎮 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://codepen.io/Michael-Gokey/pen/XJJPVZZ" rel="noopener noreferrer"&gt;See the Flashcard Game on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📦 &lt;strong&gt;Code Repo:&lt;/strong&gt; &lt;a href="https://github.com/michael-gokey-architect-25/fun-cards-beginner/" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;Challenge:&lt;/strong&gt; Fork the CodePen and add a category filter, or track correct/incorrect answers.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>criticalthinking</category>
      <category>pseudocode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Flip for Knowledge: Building a Flashcard Game with HTML, CSS &amp; JavaScript</title>
      <dc:creator>Michael Gokey</dc:creator>
      <pubDate>Fri, 09 May 2025 00:32:29 +0000</pubDate>
      <link>https://dev.to/michael-gokey/flip-for-knowledge-building-a-flashcard-game-with-html-css-javascript-3o9j</link>
      <guid>https://dev.to/michael-gokey/flip-for-knowledge-building-a-flashcard-game-with-html-css-javascript-3o9j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Junior developers, bootcamp grads, and anyone who loves interactive learning. &lt;em&gt;⏱️ Estimated reading time: 2 minutes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Build a 10-card flashcard game from scratch, moving from pseudocode to production-ready code—explaining the &lt;em&gt;why&lt;/em&gt; behind each step.&lt;/p&gt;




&lt;h3&gt;
  
  
  💡 Why Flashcards?
&lt;/h3&gt;

&lt;p&gt;Flashcards are a great way to reinforce learning. They keep users engaged and help us explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM manipulation&lt;/li&gt;
&lt;li&gt;Event listeners&lt;/li&gt;
&lt;li&gt;Component reuse&lt;/li&gt;
&lt;li&gt;Separation of concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break this down into small wins.&lt;br&gt;
You can go see &lt;a href="https://codepen.io/Michael-Gokey/pen/XJJPVZZ" rel="noopener noreferrer"&gt;FunCards in Action&lt;/a&gt; and see the steps here. &lt;/p&gt;




&lt;h3&gt;
  
  
  🧾 Step 1: The Pseudocode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Create a container for flashcards.
2. Each flashcard has a front (question) and a back (answer).
3. Clicking a flashcard flips it.
4. Load 10 flashcards into the DOM.
5. Style the flashcards to animate the flip.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧱 Step 2: The HTML Skeleton
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"flashcard-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Cards will be injected here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧠 Step 3: Sample Flashcard Data (in JavaScript)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flashcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What does HTML stand for?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HyperText Markup Language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is the purpose of CSS?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;To style HTML content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ... add 8 more&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🛠️ Step 4: JavaScript to Create and Inject Flashcards
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flashcard-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;flashcards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cardDiv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cardDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;cardDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div class="card-inner"&amp;gt;
      &amp;lt;div class="card-front"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class="card-back"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;cardDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cardDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flipped&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardDiv&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;h3&gt;
  
  
  🎨 Step 5: CSS for Styling and Flip Animation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#flashcard-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card-inner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.6s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;preserve-3d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card.flipped&lt;/span&gt; &lt;span class="nc"&gt;.card-inner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;180deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card-front&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.card-back&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;backface-visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fefefe&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card-back&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffefd5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;180deg&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;h3&gt;
  
  
  🔍 Why We Built It This Way
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Componentization&lt;/strong&gt;  Even though we’re using plain JS, each card is its own mini-component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Binding&lt;/strong&gt;  Shows how to handle DOM events cleanly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animation with CSS&lt;/strong&gt;  Keeps it performant and easy to tweak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Data &amp;amp; View&lt;/strong&gt;  The flashcard content is kept separate from the DOM logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ What’s Next?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make the game track score (quiz style).&lt;/li&gt;
&lt;li&gt;Pull flashcards from a backend API.&lt;/li&gt;
&lt;li&gt;Let users add their own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎮 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://codepen.io/Michael-Gokey/pen/XJJPVZZ" rel="noopener noreferrer"&gt;See the Flashcard Game on CodePen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📦 &lt;strong&gt;Code Repo:&lt;/strong&gt; &lt;a href="https://github.com/michael-gokey-architect-25/fun-cards-beginner/" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gamedev</category>
      <category>criticalthinking</category>
      <category>pseudocode</category>
    </item>
  </channel>
</rss>
