<?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: Grant Watson</title>
    <description>The latest articles on DEV Community by Grant Watson (@grantwatsondev).</description>
    <link>https://dev.to/grantwatsondev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F294613%2F7f1c6002-9358-46cd-b426-114605c70ce3.PNG</url>
      <title>DEV Community: Grant Watson</title>
      <link>https://dev.to/grantwatsondev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grantwatsondev"/>
    <language>en</language>
    <item>
      <title>Graph Theory in C#</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Sat, 15 Aug 2026 16:30:51 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/graph-theory-in-c-5h83</link>
      <guid>https://dev.to/grantwatsondev/graph-theory-in-c-5h83</guid>
      <description>&lt;p&gt;Using graph search to solve real-world problems in C#&lt;br&gt;
Most day-to-day C# work involves flat collections: filter a list, sort a table, look something up by key. Those shapes are well served by LINQ and a dictionary. But some problems are about relationships rather than records, and flat collections handle them badly.&lt;/p&gt;

&lt;p&gt;A few examples that show up in real systems:&lt;/p&gt;

&lt;p&gt;Which permissions does a user inherit through nested role groups?&lt;br&gt;
Which build targets need to rebuild when this one file changes?&lt;br&gt;
Which accounts are linked, directly or indirectly, to this flagged account?&lt;br&gt;
What is the shortest referral chain between two users?&lt;br&gt;
Each of these is a reachability question, and reachability is what graph search answers.&lt;/p&gt;

&lt;p&gt;Prerequisites&lt;br&gt;
Working knowledge of C# generics and collections&lt;br&gt;
.NET 8 or later (the code here was compiled and run against .NET 8)&lt;br&gt;
No prior graph theory is assumed. The vocabulary is small and introduced as it is needed.&lt;/p&gt;

&lt;p&gt;The vocabulary you actually need&lt;br&gt;
A graph is a set of nodes connected by edges. In an undirected graph, an edge runs both ways: if Alice and Bob are friends, each is a friend of the other. In a directed graph, edges run one way: if module A imports module B, that says nothing about B importing A.&lt;/p&gt;

&lt;p&gt;This distinction is not academic. Getting it wrong is the single most common bug in hand-rolled graph code, and it fails silently. Your traversal returns a plausible-looking result that is missing half the graph.&lt;/p&gt;

&lt;p&gt;Traversal means visiting nodes by following edges. Two orders dominate:&lt;/p&gt;

&lt;p&gt;Breadth-first search (BFS) visits everything one hop away, then everything two hops away, and so on. Because it expands in rings, the first time it reaches a node it has done so by the fewest possible hops. That property makes BFS the correct choice for shortest-path-by-hop-count.&lt;br&gt;
Depth-first search (DFS) follows one branch as far as it goes before backtracking. It is the natural fit for cycle detection, topological sorting, and anything that needs to know when a subtree is fully explored.&lt;br&gt;
Dijkstra's algorithm and A* extend this to graphs where edges carry different costs. They are out of scope here. If your edges are all equivalent, which covers most of the cases listed above, BFS and DFS are what you want.&lt;/p&gt;

&lt;p&gt;Representing the graph&lt;br&gt;
An adjacency list is the standard representation: a map from each node to the set of nodes it connects to. Sparse graphs, which is nearly all real-world graphs, use far less memory this way than with an adjacency matrix.&lt;/p&gt;

&lt;p&gt;Four decisions in the implementation below are worth calling out before the code:&lt;/p&gt;

&lt;p&gt;HashSet rather than List for neighbors. Adding the same edge twice is common when ingesting data, and a list would happily store duplicates, inflating traversal work and skewing any degree calculation.&lt;br&gt;
AddEdge is bidirectional by default, with an opt-out. Undirected is the more common case and the one people forget to handle, so it is the default. Directed callers pass bidirectional: false explicitly, which makes the intent visible at the call site.&lt;br&gt;
Both endpoints get registered as nodes. If only the source node becomes a dictionary key, the target exists as a neighbor but has no entry of its own, and traversals starting from it return nothing.&lt;br&gt;
An optional IEqualityComparer. For string nodes, case sensitivity decides whether "Alice" and "alice" are one person or two. That belongs to the caller, not the data structure.&lt;br&gt;
using System;&lt;br&gt;
using System.Collections.Generic;&lt;/p&gt;

&lt;p&gt;public class Graph where T : notnull&lt;br&gt;
{&lt;br&gt;
    private readonly Dictionary&amp;gt; _adjacency;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public Graph(IEqualityComparer&amp;lt;T&amp;gt;? comparer = null)
{
    Comparer = comparer ?? EqualityComparer&amp;lt;T&amp;gt;.Default;
    _adjacency = new Dictionary&amp;lt;T, HashSet&amp;lt;T&amp;gt;&amp;gt;(Comparer);
}

private IEqualityComparer&amp;lt;T&amp;gt; Comparer { get; }

public IReadOnlyCollection&amp;lt;T&amp;gt; Nodes =&amp;gt; _adjacency.Keys;

public void AddNode(T node)
{
    if (!_adjacency.ContainsKey(node))
        _adjacency[node] = new HashSet&amp;lt;T&amp;gt;(Comparer);
}

public void AddEdge(T from, T to, bool bidirectional = true)
{
    AddNode(from);
    AddNode(to);

    _adjacency[from].Add(to);

    if (bidirectional)
        _adjacency[to].Add(from);
}

public IReadOnlySet&amp;lt;T&amp;gt; Neighbors(T node) =&amp;gt;
    _adjacency.TryGetValue(node, out var set)
        ? set
        : (IReadOnlySet&amp;lt;T&amp;gt;)new HashSet&amp;lt;T&amp;gt;(Comparer);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
Breadth-first search&lt;br&gt;
BFS uses a queue. Pull a node, record it, enqueue any unvisited neighbors, repeat.&lt;/p&gt;

&lt;p&gt;The detail that matters most is when a node is marked visited. Marking on enqueue, as below, guarantees each node enters the queue exactly once. Marking on dequeue instead lets a node be enqueued several times before it is first processed, which on a dense graph degrades badly.&lt;/p&gt;

&lt;p&gt;public List BreadthFirst(T start)&lt;br&gt;
{&lt;br&gt;
    var order = new List();&lt;br&gt;
    if (!_adjacency.ContainsKey(start))&lt;br&gt;
        return order;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var visited = new HashSet&amp;lt;T&amp;gt;(Comparer) { start };
var queue = new Queue&amp;lt;T&amp;gt;();
queue.Enqueue(start);

while (queue.Count &amp;gt; 0)
{
    var node = queue.Dequeue();
    order.Add(node);

    foreach (var neighbor in _adjacency[node])
    {
        if (visited.Add(neighbor))
            queue.Enqueue(neighbor);
    }
}

return order;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
HashSet.Add returns false when the item was already present, so the check and the insert happen in one operation rather than a Contains followed by an Add.&lt;/p&gt;

&lt;p&gt;Depth-first search, without the recursion&lt;br&gt;
DFS is usually taught recursively, and the recursive version is genuinely more readable. It is also a production hazard: the call stack depth tracks the longest path in the graph. A chain of a few hundred thousand nodes, which is unremarkable for an import graph or an org hierarchy, will throw StackOverflowException. That exception cannot be caught in .NET. The process dies.&lt;/p&gt;

&lt;p&gt;An explicit Stack moves the frames onto the heap and removes the failure mode entirely:&lt;/p&gt;

&lt;p&gt;public List DepthFirst(T start)&lt;br&gt;
{&lt;br&gt;
    var order = new List();&lt;br&gt;
    if (!_adjacency.ContainsKey(start))&lt;br&gt;
        return order;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var visited = new HashSet&amp;lt;T&amp;gt;(Comparer);
var stack = new Stack&amp;lt;T&amp;gt;();
stack.Push(start);

while (stack.Count &amp;gt; 0)
{
    var node = stack.Pop();

    if (!visited.Add(node))
        continue;

    order.Add(node);

    foreach (var neighbor in _adjacency[node])
    {
        if (!visited.Contains(neighbor))
            stack.Push(neighbor);
    }
}

return order;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
Note the difference from BFS: here nodes are marked visited on pop, not on push, because the same node can legitimately be pushed by several neighbors before it is reached. The if (!visited.Add(node)) continue; line absorbs those duplicates.&lt;/p&gt;

&lt;p&gt;{{CJ_AD_SLOT_2}}&lt;/p&gt;

&lt;p&gt;Finding every connected component&lt;br&gt;
A connected component is a maximal set of nodes where every node is reachable from every other node in the set. Maximal matters: if you can add another reachable node to the set, it was not a component to begin with.&lt;/p&gt;

&lt;p&gt;A single traversal finds the one component containing your start node. Finding all of them means looping over every node and starting a fresh traversal from each one not yet seen:&lt;/p&gt;

&lt;p&gt;public List&amp;gt; ConnectedComponents()&lt;br&gt;
{&lt;br&gt;
    var components = new List&amp;gt;();&lt;br&gt;
    var seen = new HashSet(Comparer);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;foreach (var node in _adjacency.Keys)
{
    if (seen.Contains(node))
        continue;

    var component = BreadthFirst(node);
    components.Add(component);

    foreach (var member in component)
        seen.Add(member);
}

return components;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
This is correct for undirected graphs only. In a directed graph, mutual reachability is a stricter condition called a strongly connected component, and plain traversal does not compute it. A directed edge A to B means BFS from A finds B, but BFS from B may never find A, so the two are not in the same SCC even though one traversal groups them. Strongly connected components need Kosaraju's or Tarjan's algorithm. Running the code above on a directed graph and calling the output "components" is a real and easy-to-miss error.&lt;/p&gt;

&lt;p&gt;Shortest path by hop count&lt;br&gt;
Because BFS reaches every node by the fewest hops, recording how you arrived at each node yields the shortest path for free. Store a cameFrom map during traversal, then walk it backwards from the goal:&lt;/p&gt;

&lt;p&gt;public List? ShortestPath(T start, T goal)&lt;br&gt;
{&lt;br&gt;
    if (!_adjacency.ContainsKey(start) || !_adjacency.ContainsKey(goal))&lt;br&gt;
        return null;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (Comparer.Equals(start, goal))
    return new List&amp;lt;T&amp;gt; { start };

var cameFrom = new Dictionary&amp;lt;T, T&amp;gt;(Comparer);
var visited = new HashSet&amp;lt;T&amp;gt;(Comparer) { start };
var queue = new Queue&amp;lt;T&amp;gt;();
queue.Enqueue(start);

while (queue.Count &amp;gt; 0)
{
    var node = queue.Dequeue();

    foreach (var neighbor in _adjacency[node])
    {
        if (!visited.Add(neighbor))
            continue;

        cameFrom[neighbor] = node;

        if (Comparer.Equals(neighbor, goal))
            return Reconstruct(cameFrom, start, goal);

        queue.Enqueue(neighbor);
    }
}

return null;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;private List Reconstruct(Dictionary cameFrom, T start, T goal)&lt;br&gt;
{&lt;br&gt;
    var path = new List { goal };&lt;br&gt;
    var current = goal;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while (!Comparer.Equals(current, start))
{
    current = cameFrom[current];
    path.Add(current);
}

path.Reverse();
return path;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
Returning null distinguishes "no path exists" from an empty result. The nullable return type forces callers to handle the disconnected case rather than discovering it at runtime.&lt;/p&gt;

&lt;p&gt;A worked example&lt;br&gt;
Nine users, two friendship clusters, and one account with no connections:&lt;/p&gt;

&lt;p&gt;var graph = new Graph(StringComparer.OrdinalIgnoreCase);&lt;/p&gt;

&lt;p&gt;graph.AddEdge("Alice", "Bob");&lt;br&gt;
graph.AddEdge("Bob", "Carol");&lt;br&gt;
graph.AddEdge("Carol", "Dave");&lt;br&gt;
graph.AddEdge("Alice", "Erin");&lt;br&gt;
graph.AddEdge("Erin", "Dave");&lt;/p&gt;

&lt;p&gt;graph.AddEdge("Frank", "Grace");&lt;br&gt;
graph.AddEdge("Grace", "Heidi");&lt;/p&gt;

&lt;p&gt;graph.AddNode("Ivan");&lt;/p&gt;

&lt;p&gt;Console.WriteLine(string.Join(" -&amp;gt; ", graph.BreadthFirst("Alice")));&lt;br&gt;
Console.WriteLine(string.Join(" -&amp;gt; ", graph.DepthFirst("Alice")));&lt;/p&gt;

&lt;p&gt;foreach (var component in graph.ConnectedComponents())&lt;br&gt;
    Console.WriteLine(string.Join(", ", component));&lt;/p&gt;

&lt;p&gt;var path = graph.ShortestPath("Alice", "Dave");&lt;br&gt;
Console.WriteLine(path is null ? "no path" : string.Join(" -&amp;gt; ", path));&lt;br&gt;
Output:&lt;/p&gt;

&lt;p&gt;Breadth-first from Alice:&lt;br&gt;
  Alice -&amp;gt; Bob -&amp;gt; Erin -&amp;gt; Carol -&amp;gt; Dave&lt;/p&gt;

&lt;p&gt;Depth-first from Alice:&lt;br&gt;
  Alice -&amp;gt; Erin -&amp;gt; Dave -&amp;gt; Carol -&amp;gt; Bob&lt;/p&gt;

&lt;p&gt;Connected components:&lt;br&gt;
  1: Alice, Bob, Erin, Carol, Dave&lt;br&gt;
  2: Frank, Grace, Heidi&lt;br&gt;
  3: Ivan&lt;/p&gt;

&lt;p&gt;Shortest path Alice to Dave:&lt;br&gt;
  Alice -&amp;gt; Erin -&amp;gt; Dave (2 hops)&lt;/p&gt;

&lt;p&gt;Shortest path Alice to Frank:&lt;br&gt;
  no path&lt;br&gt;
Three things in that output are worth reading carefully.&lt;/p&gt;

&lt;p&gt;Ivan appears as his own single-node component, which is correct and is a case that breaks naive implementations. Alice reaches Dave in two hops through Erin, not three through Bob and Carol, confirming BFS found the shorter of the two available routes. And Alice to Frank returns no path, because the two clusters are genuinely disconnected.&lt;/p&gt;

&lt;p&gt;One caveat on ordering: HashSet does not guarantee enumeration order, so the relative position of same-distance siblings (Bob and Erin above) is an implementation detail and should not be asserted in tests. The distances are deterministic; the tie-breaking is not. If you need stable ordering, sort each neighbor set before enumerating.&lt;/p&gt;

&lt;p&gt;{{CJ_AD_SLOT_3}}&lt;/p&gt;

&lt;p&gt;Complexity and where it stops working&lt;br&gt;
All four traversals run in O(V + E) time and O(V) space, where V is nodes and E is edges. Every node is visited once and every edge is examined once.&lt;/p&gt;

&lt;p&gt;That is fast, and it is also the ceiling. The practical limits:&lt;/p&gt;

&lt;p&gt;Memory is the binding constraint. O(V) for the visited set plus the adjacency structure itself means the whole graph lives in RAM. Somewhere in the low millions of nodes, depending on T, this stops being viable in a single process.&lt;br&gt;
BFS peak queue size scales with the widest level. On a graph with high fan-out, such as a follower network with celebrity accounts, the queue can hold a large fraction of all nodes at once. The average case looks fine and the worst case does not.&lt;br&gt;
Repeated queries recompute everything. If you are answering the same reachability question against a slow-changing graph many times, cache the components rather than re-traversing.&lt;br&gt;
Weighted edges need different algorithms. The moment edges carry costs, BFS gives you the fewest-hops path, which is not the cheapest path. That is Dijkstra's territory.&lt;br&gt;
Cycles, worth noting, are not a problem here. The visited set handles them by construction. Cyclic graphs terminate correctly:&lt;/p&gt;

&lt;p&gt;Cyclic graph BFS from 1: 1 -&amp;gt; 2 -&amp;gt; 3&lt;br&gt;
Cycles only cause infinite loops in implementations that omit visit tracking, which is why the visited set is present from the first version rather than added as an optimization.&lt;/p&gt;

&lt;p&gt;When to use a library instead&lt;br&gt;
The code above is roughly 120 lines and it is worth writing yourself when the graph is a small part of a larger system, when you want no extra dependency, or when you are learning the algorithms.&lt;/p&gt;

&lt;p&gt;Reach for QuikGraph instead when you need weighted algorithms, topological sort, minimum spanning trees, maximum flow, or graph serialization. Reimplementing Dijkstra correctly, including the priority queue behavior, is more error-prone than most people expect.&lt;/p&gt;

&lt;p&gt;If the graph is the system rather than a component of it, and especially if it needs to be queried and persisted, a graph database such as Neo4j is a better fit than any in-process structure.&lt;/p&gt;

&lt;p&gt;Summary&lt;br&gt;
The four operations above cover a large share of practical graph work in C#: BFS for shortest hops, DFS for exhaustive exploration, component detection for clustering, and path reconstruction for explaining a result. The implementation is small enough to read in one sitting and to test thoroughly.&lt;/p&gt;

&lt;p&gt;The failure modes to watch are the quiet ones. Directed edges where you assumed undirected, recursion depth on long chains, and calling a directed traversal result a connected component. None of the three throws an exception. All three produce answers that look reasonable and are wrong.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Implementing CORS in ASP.NET Core Applications</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Sat, 27 Jun 2026 23:00:33 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/implementing-cors-in-aspnet-core-applications-1825</link>
      <guid>https://dev.to/grantwatsondev/implementing-cors-in-aspnet-core-applications-1825</guid>
      <description>&lt;p&gt;This and all my other articles can be found at &lt;a href="//www.grantwatson.dev/blog"&gt;GWS Blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As web developers, we're familiar with the challenges of cross-origin resource sharing (CORS). In this guide, we'll show you how to implement CORS in ASP.NET Core applications, ensuring your API is secure and accessible to clients from different domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;.NET 6.0 or later&lt;/li&gt;
&lt;li&gt;Visual Studio Code or your preferred IDE&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Microsoft.AspNetCore.Http&lt;/code&gt; NuGet package (installed via the Package Manager Console)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;CORS allows web servers to specify which domains are allowed to access their resources, preventing cross-site scripting (XSS) attacks and ensuring data integrity. In this guide, we'll walk you through implementing CORS in ASP.NET Core.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring CORS
&lt;/h3&gt;

&lt;p&gt;To enable CORS in your ASP.NET Core application, create a new instance of the &lt;code&gt;CorsOptions&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;corsOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CorsOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, configure the &lt;code&gt;AllowAnyOrigin&lt;/code&gt;, &lt;code&gt;Allow Any Method&lt;/code&gt;, and &lt;code&gt;AllowAnyHeaders&lt;/code&gt; properties to control which origins, methods, and headers are allowed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;corsOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowAnyOrigin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;corsOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowAnyMethod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;corsOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowAnyHeader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;corsOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can configure CORS using a policy file (&lt;code&gt;cors-policies.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowAnyOrigin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowAnyMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowAnyHeader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Pitfalls and Edge Cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Handling preflight requests:&lt;/strong&gt; When setting options for a request that is not allowed by the browser, it should include an &lt;code&gt;Origin&lt;/code&gt; header. The server must respond with the correct headers to allow the browser to make the actual request.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithOptions&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;p&gt;&lt;br&gt;
csharp&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuring allowed origins:&lt;/strong&gt; By default, only origins specified in the policy are allowed. To include wildcard domains (e.g., &lt;code&gt;*.example.com&lt;/code&gt;), use the &lt;code&gt;AllowAnyOrigin&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;corsOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowAnyOrigin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;However, be cautious when using this approach as it may increase security risks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Error handling:&lt;/strong&gt; Implement error handling to catch and handle CORS-related errors. You can use a custom exception handler or a middleware that handles exceptions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseExceptionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Handle the exception&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alternatively, you can use the built-in `System.Web.HttpException` class to create a CORS-related exception.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Logging and monitoring:&lt;/strong&gt; Implement logging and monitoring mechanisms to track CORS-related requests and errors. This will help you identify potential security issues and improve your application's overall security posture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;In this guide, we covered implementing CORS in ASP.NET Core applications using the &lt;code&gt;CorsOptions&lt;/code&gt; class and configuring CORS policies using a policy file. We also discussed common pitfalls and edge cases to ensure your application is secure and accessible to clients from different domains.&lt;/p&gt;

&lt;p&gt;Remember to always verify that your implementation aligns with best practices and industry standards. Always consult official documentation and reputable sources for guidance on implementing security measures in your applications.&lt;/p&gt;

</description>
      <category>cors</category>
      <category>aspnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React Performance for Senior Developers (Practical, No Cargo Culting)</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Fri, 01 May 2026 16:03:10 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/react-performance-for-senior-developers-practical-no-cargo-culting-1l02</link>
      <guid>https://dev.to/grantwatsondev/react-performance-for-senior-developers-practical-no-cargo-culting-1l02</guid>
      <description>&lt;p&gt;👉 &lt;a href="https://www.grantwatson.dev/blog/react-performance-for-senior-developers-practical-no-cargo-culting" rel="noopener noreferrer"&gt;Read the full article on my site&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📚 &lt;a href="https://www.grantwatson.dev/blog" rel="noopener noreferrer"&gt;Browse all my articles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author: Grant Watson&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Published: 2026-02-21&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Category: React / Frontend Performance&lt;/em&gt;&lt;/p&gt;




&lt;h5&gt;
  
  
  Recommended Deals
&lt;/h5&gt;

&lt;p&gt;👉 &lt;a href="https://www.dpbolvw.net/8d102ar-xrzEOIINGJKEGIONLHFN" rel="noopener noreferrer"&gt;Claim a Book-A-Million 15% coupon here&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The performance mindset (the part people skip)
&lt;/h2&gt;

&lt;p&gt;Performance work fails for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No baseline (you never proved it was slow)
&lt;/li&gt;
&lt;li&gt;Wrong bottleneck (you optimized the wrong layer)
&lt;/li&gt;
&lt;li&gt;No regression protection (you fixed it once and it came back)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Process: &lt;strong&gt;measure → isolate → fix highest leverage → add guardrails&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1) Measure first: React Profiler + why-did-you-render
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What to look for in the Profiler
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commit duration
&lt;/li&gt;
&lt;li&gt;Which components re-rendered
&lt;/li&gt;
&lt;li&gt;Why they re-rendered
&lt;/li&gt;
&lt;li&gt;Frequency vs cost
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Optimize frequency first, then cost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Render counter hook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;function&lt;/span&gt; &lt;span class="nf"&gt;useRenderCount&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&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="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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;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;`[render] &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="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;h2&gt;
  
  
  2) The #1 cause of slow apps: unnecessary re-renders
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem: unstable props
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&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;filters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&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;onRowClick&lt;/span&gt; &lt;span class="o"&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="nf"&gt;setSelected&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onRowClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onRowClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fix: stabilize identity when it matters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onRowClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="nf"&gt;setSelected&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;p&gt;Memo hooks are &lt;strong&gt;identity stabilizers&lt;/strong&gt;, not magic speed boosts.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) React.memo: use it on expensive components
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; — &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Memo only works if the props are stable.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) State architecture: colocate hot state
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setForm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Sidebar&lt;/span&gt; &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preview&lt;/span&gt; &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;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;h3&gt;
  
  
  Fix
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Main&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setForm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;setForm&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setForm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preview&lt;/span&gt; &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;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;Keep frequently changing state deep.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Lists: virtualization beats memo spam
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i react-window
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FixedSizeList&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-window&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;VirtualizedUsers&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;itemCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;itemSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;
      &lt;span class="na"&gt;itemData&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;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;High ROI change: fewer DOM nodes, less layout, less memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  6) Memoize derived data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&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;x&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;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;expensive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&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;data&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;code&gt;select&lt;/code&gt; in TanStack Query.&lt;/p&gt;




&lt;h2&gt;
  
  
  7) Avoid context re-render storms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BigTree&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fix: split contexts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LocaleContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BigTree&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;LocaleContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8) Concurrent React: keep typing responsive
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&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;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&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;isPending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="nf"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Users care about input responsiveness more than filter latency.&lt;/p&gt;




&lt;h2&gt;
  
  
  9) Bundle performance matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code split heavy routes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AdminPanel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./AdminPanel&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;
  
  
  Dynamic import heavy utilities
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsPDF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jspdf&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;p&gt;If it’s not needed on first paint, don’t ship it.&lt;/p&gt;




&lt;h2&gt;
  
  
  10) Images: silent performance killers
&lt;/h2&gt;

&lt;p&gt;Best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responsive sizes
&lt;/li&gt;
&lt;li&gt;AVIF/WebP
&lt;/li&gt;
&lt;li&gt;Lazy load below the fold
&lt;/li&gt;
&lt;li&gt;Set width/height to prevent CLS
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
  &lt;span class="na"&gt;decoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"async"&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11) Guardrails against regressions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Track bundle size in CI
&lt;/li&gt;
&lt;li&gt;Add render sanity checks for critical screens
&lt;/li&gt;
&lt;li&gt;Don’t ship multi‑MB JS for simple views
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The practical checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Profile first
&lt;/li&gt;
&lt;li&gt;Fix frequency re-renders
&lt;/li&gt;
&lt;li&gt;Virtualize large lists
&lt;/li&gt;
&lt;li&gt;Split contexts and colocate hot state
&lt;/li&gt;
&lt;li&gt;Code split heavy bundles
&lt;/li&gt;
&lt;li&gt;Add guardrails
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Performance is a process, not a one-time refactor.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
      <category>react</category>
    </item>
    <item>
      <title>How to Identify and Remove Code Smells in Modern Codebases</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Fri, 01 May 2026 15:54:01 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/how-to-identify-and-remove-code-smells-in-modern-codebases-5gep</link>
      <guid>https://dev.to/grantwatsondev/how-to-identify-and-remove-code-smells-in-modern-codebases-5gep</guid>
      <description>&lt;h1&gt;
  
  
  Code Smells in Real-World Systems: How to Identify, Prioritize, and Eliminate Them Without Slowing Your Team Down
&lt;/h1&gt;




&lt;h2&gt;
  
  
  Continue Reading
&lt;/h2&gt;

&lt;p&gt;If you want the full deep dive with expanded examples and breakdowns:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://www.grantwatson.dev/blog/how-to-identify-and-remove-code-smells-in-modern-codebases" rel="noopener noreferrer"&gt;Read the complete article here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Looking for more content like this?&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;&lt;a href="https://www.grantwatson.dev/blog" rel="noopener noreferrer"&gt;Explore all articles on grantwatson.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction: When “Working Code” Becomes the Problem
&lt;/h2&gt;

&lt;p&gt;Every engineer has worked in a system that technically works—but feels hostile.&lt;/p&gt;

&lt;p&gt;You open a file to fix a small bug and realize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The method is 200 lines long&lt;/li&gt;
&lt;li&gt;You need to understand three unrelated concerns&lt;/li&gt;
&lt;li&gt;Changing one line might break something you don’t fully understand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you hesitate. You move slower. You over-test. You double-check everything.&lt;/p&gt;

&lt;p&gt;Nothing is broken. But everything is expensive.&lt;/p&gt;

&lt;p&gt;That’s the real impact of code smells.&lt;/p&gt;

&lt;p&gt;They don’t show up in logs. They don’t trigger alerts. They don’t crash your app.&lt;br&gt;&lt;br&gt;
They quietly erode your ability to change the system.&lt;/p&gt;

&lt;p&gt;And over time, that erosion becomes the defining characteristic of the codebase.&lt;/p&gt;

&lt;p&gt;This article is not about textbook definitions. It is about what actually happens inside production systems—and how experienced engineers deal with it.&lt;/p&gt;







&lt;h2&gt;
  
  
  Recommended Gear Deal
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Oakley Clearance: Up to 50% Off Selected Products + Free Shipping&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re looking for performance eyewear, outdoor gear, or everyday Oakley products, this promotion is worth checking while it is active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.anrdoezrs.net/click-9338145-15153860" rel="noopener noreferrer"&gt;View Oakley Clearance Deals →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.tkqlhce.com/click-9338145-11608973" rel="noopener noreferrer"&gt;Explore More Oakley Products →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Affiliate disclosure: This article may contain affiliate links. If you purchase through these links, I may earn a commission at no additional cost to you.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  What Code Smells Actually Are
&lt;/h2&gt;

&lt;p&gt;Code smells are not bugs.&lt;/p&gt;

&lt;p&gt;They are signals.&lt;/p&gt;

&lt;p&gt;They indicate that the structure of the code is working against you—even if the behavior is correct.&lt;/p&gt;

&lt;p&gt;A helpful way to think about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bug is a failure of correctness
&lt;/li&gt;
&lt;li&gt;A code smell is a failure of design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can ship code with smells. Teams do it every day.&lt;br&gt;&lt;br&gt;
But each smell increases the cost of the next change.&lt;/p&gt;

&lt;p&gt;That’s why experienced engineers care. Not because the code is “ugly,” but because it is becoming harder to evolve.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Cost of Code Smells in Production
&lt;/h2&gt;

&lt;p&gt;In isolation, most smells are harmless. The problem is how they interact.&lt;/p&gt;

&lt;p&gt;A long method by itself is manageable.&lt;br&gt;&lt;br&gt;
A long method that is duplicated, poorly named, and tightly coupled becomes dangerous.&lt;/p&gt;

&lt;p&gt;Now every change requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding multiple responsibilities at once&lt;/li&gt;
&lt;li&gt;Modifying logic in multiple places&lt;/li&gt;
&lt;li&gt;Risking side effects in unrelated areas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shows up in very real ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A “simple change” takes half a day instead of 30 minutes
&lt;/li&gt;
&lt;li&gt;A bug fix introduces a regression somewhere else
&lt;/li&gt;
&lt;li&gt;Pull requests get larger because nothing is isolated
&lt;/li&gt;
&lt;li&gt;New developers avoid touching certain files
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, the system is not just complex—it is resisting change.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Safe Refactoring Loop (What Actually Works)
&lt;/h2&gt;

&lt;p&gt;Refactoring advice often sounds simple: “make small changes.”&lt;br&gt;&lt;br&gt;
In practice, it’s constrained by deadlines, missing tests, and incomplete understanding.&lt;/p&gt;

&lt;p&gt;A realistic refactoring loop looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identify the smell&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not every imperfection matters. Focus on code that is actively causing friction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understand current behavior&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Before changing structure, understand what the code actually does—not what you think it does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stabilize behavior (tests or observation)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If tests exist, use them.&lt;br&gt;&lt;br&gt;
If they don’t, create lightweight checks—logs, manual verification, or characterization tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refactor in small, reversible steps&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Extract a method. Rename a variable. Introduce a boundary.&lt;br&gt;&lt;br&gt;
Avoid large, sweeping changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate constantly&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After every change, confirm behavior is preserved.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This loop is not about perfection. It is about controlled improvement.&lt;/p&gt;




&lt;h1&gt;
  
  
  Deep Dive: The Most Dangerous Code Smells
&lt;/h1&gt;




&lt;h2&gt;
  
  
  Long Methods
&lt;/h2&gt;

&lt;p&gt;Long methods are rarely intentional. They accumulate.&lt;/p&gt;

&lt;p&gt;A method starts small. A feature gets added. Then another. Over time, unrelated concerns end up in the same place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&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="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&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="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&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="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_emailService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerEmail&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;
  
  
  What’s Actually Wrong
&lt;/h3&gt;

&lt;p&gt;This method combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Business rules&lt;/li&gt;
&lt;li&gt;Persistence&lt;/li&gt;
&lt;li&gt;External communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these evolves independently. Keeping them together creates friction.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;ApplyDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;NotifyAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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;The improvement isn’t cosmetic. It reduces cognitive load.&lt;br&gt;&lt;br&gt;
A developer can now understand the method in seconds instead of minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  God Classes
&lt;/h2&gt;

&lt;p&gt;God classes form when teams prioritize convenience over boundaries.&lt;/p&gt;

&lt;p&gt;Instead of creating a new component, functionality is added to an existing service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ExportReport&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;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;This class owns multiple responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain logic&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;Reporting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each has different change patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketService&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketNotificationService&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketReportingService&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces coupling and allows independent evolution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Duplicate Logic
&lt;/h2&gt;

&lt;p&gt;Duplication is rarely intentional. It’s usually the fastest path under pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.1m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repeated across the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Now the discount rule exists in multiple places.&lt;br&gt;&lt;br&gt;
Change the rule once, and you risk inconsistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;CalculateDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;total&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="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.1m&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.05m&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;One rule. One place. Predictable behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Primitive Obsession
&lt;/h2&gt;

&lt;p&gt;Using primitives for everything feels simple—but it removes constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Nothing prevents invalid values.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Inactive&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Types communicate intent and enforce rules at compile time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Long Parameter Lists
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;CreateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Hard to read, easy to misuse, difficult to extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;CreateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUserRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grouping related data reduces complexity and improves clarity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Boolean Flags
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;SaveOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;The meaning of “true” is implicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;SaveOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;SaveOrderAndNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicit methods remove ambiguity and reduce misuse.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deep Nesting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&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="n"&gt;b&lt;/span&gt;&lt;span class="p"&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="n"&gt;c&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Understanding requires tracking multiple conditions simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flattening logic reduces mental overhead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tight Coupling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;The class is tied to a specific implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables testing, flexibility, and replacement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Poor Naming
&lt;/h2&gt;

&lt;p&gt;Names are the primary way developers understand code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activeOrders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetActiveCustomerOrders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good naming removes the need for explanation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comment-Driven Code
&lt;/h2&gt;

&lt;p&gt;Comments often compensate for unclear code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// check if active&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clear code eliminates the need for explanatory comments.&lt;/p&gt;




&lt;h1&gt;
  
  
  Repository-Level Code Smells
&lt;/h1&gt;

&lt;p&gt;Most articles stop at code. Real problems often exist at the repository level.&lt;/p&gt;

&lt;p&gt;Common patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No consistent architecture&lt;/li&gt;
&lt;li&gt;Mixed concerns across folders&lt;/li&gt;
&lt;li&gt;Configuration scattered across files&lt;/li&gt;
&lt;li&gt;No CI enforcement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These issues affect the entire team—not just individual files.&lt;/p&gt;

&lt;p&gt;A well-structured repository reduces friction at scale.&lt;/p&gt;




&lt;h1&gt;
  
  
  How to Prioritize Code Smells
&lt;/h1&gt;

&lt;p&gt;Trying to fix everything is a mistake.&lt;/p&gt;

&lt;p&gt;Focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code you are actively modifying&lt;/li&gt;
&lt;li&gt;Areas with frequent bugs&lt;/li&gt;
&lt;li&gt;High-complexity modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach—often called “refactor where you touch”—keeps progress continuous without slowing delivery.&lt;/p&gt;




&lt;h1&gt;
  
  
  Tooling (And Its Limits)
&lt;/h1&gt;

&lt;p&gt;Tools like SonarQube, Roslyn analyzers, and ESLint help identify issues.&lt;/p&gt;

&lt;p&gt;But tools do not understand context.&lt;/p&gt;

&lt;p&gt;They can flag:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long methods&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Duplication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They cannot decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether a refactor is worth the cost&lt;/li&gt;
&lt;li&gt;Whether a smell is intentional&lt;/li&gt;
&lt;li&gt;Whether the system’s behavior is preserved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools assist. Engineers decide.&lt;/p&gt;




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

&lt;p&gt;When reviewing code, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can I understand this quickly?&lt;/li&gt;
&lt;li&gt;Does this method do one thing?&lt;/li&gt;
&lt;li&gt;Is logic duplicated?&lt;/li&gt;
&lt;li&gt;Are names meaningful?&lt;/li&gt;
&lt;li&gt;Is behavior obvious without comments?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If not, the code needs work.&lt;/p&gt;




&lt;h1&gt;
  
  
  Common Refactoring Mistakes
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring without understanding behavior
&lt;/li&gt;
&lt;li&gt;Large, risky pull requests
&lt;/li&gt;
&lt;li&gt;Introducing abstractions too early
&lt;/li&gt;
&lt;li&gt;Cleaning code without addressing underlying problems
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refactoring is not about making code look better.&lt;br&gt;&lt;br&gt;
It is about making it easier to change.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Clean code is often misunderstood as an aesthetic pursuit—something subjective, even optional. In reality, it is a discipline rooted in economics and risk management. The structure of your codebase determines how quickly your team can respond to change, how confidently you can deploy, and how effectively new engineers can contribute. Poor structure introduces friction; over time, that friction compounds into hesitation, workarounds, and ultimately stagnation.&lt;/p&gt;

&lt;p&gt;The goal is not to eliminate every imperfection. That mindset leads to over-engineering and missed deadlines. Instead, the objective is to continuously reduce unnecessary complexity in the areas that matter most—where your system is evolving, where your business logic lives, and where your team spends the majority of its time. Small, deliberate improvements create leverage. They make future changes cheaper, safer, and faster.&lt;/p&gt;

&lt;p&gt;Refactoring, done correctly, is not a rewrite. It is a series of controlled, behavior-preserving decisions that improve clarity and isolate responsibility. It requires discipline, judgment, and restraint. Most importantly, it requires an understanding that today’s shortcuts become tomorrow’s constraints.&lt;/p&gt;

&lt;p&gt;The best engineering teams are not those who write perfect code. They are the ones who consistently make their code easier to work with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Leave the code better than you found it. Clean code is not clever code. It is code that allows change without fear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Applied consistently, that principle transforms not just codebases—but the way teams build software.&lt;/p&gt;




</description>
    </item>
    <item>
      <title>Earned Complexity: A Disciplined, Evidence-Based Framework</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Mon, 19 Jan 2026 01:10:28 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/earned-complexity-a-disciplined-evidence-based-framework-54pn</link>
      <guid>https://dev.to/grantwatsondev/earned-complexity-a-disciplined-evidence-based-framework-54pn</guid>
      <description>&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Modern software engineering organizations increasingly struggle not because of insufficient technical skill or innovation, but due to a systemic over-accumulation of complexity that is introduced faster than it can be justified, understood, governed, or operated. This phenomenon—often mislabeled as &lt;em&gt;technical ambition&lt;/em&gt;, &lt;em&gt;future-proofing&lt;/em&gt;, or &lt;em&gt;scalability planning&lt;/em&gt;—has been repeatedly identified as a root cause of degraded system reliability, declining delivery velocity, organizational burnout, and unsustainable maintenance cost.&lt;/p&gt;

&lt;p&gt;This paper formalizes &lt;strong&gt;Earned Complexity&lt;/strong&gt;, an evidence-based decision framework designed explicitly for &lt;strong&gt;software teams&lt;/strong&gt; to determine &lt;em&gt;when&lt;/em&gt; architectural or systemic complexity is warranted and &lt;em&gt;how&lt;/em&gt; such complexity must be constrained, monitored, and revisited over time. The framework synthesizes principles from well-established engineering literature, including &lt;em&gt;Choose Boring Technology&lt;/em&gt;, &lt;em&gt;You Are Not Google&lt;/em&gt;, and the maxim &lt;em&gt;Code Is Read More Than It Is Written&lt;/em&gt;, alongside operational insights from reliability engineering, systems thinking, and organizational psychology.&lt;/p&gt;

&lt;p&gt;By reframing complexity as a &lt;strong&gt;scarce resource that must be earned and continuously paid for&lt;/strong&gt;, this work proposes a practical, repeatable discipline that aligns technical decision-making with long-term organizational performance. The intended outcome is not minimalism for its own sake, but &lt;strong&gt;sustained peak execution through disciplined restraint&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Introduction: Why Complexity Requires Study
&lt;/h2&gt;

&lt;p&gt;Software systems do not fail randomly. They fail predictably, following well-understood patterns associated with unmanaged complexity: cascading failures, brittle abstractions, opaque behavior, and disproportionate operational overhead. Despite decades of industry experience, many teams continue to repeat the same mistakes, introducing advanced architectures prematurely and assuming that sophistication is synonymous with professionalism.&lt;/p&gt;

&lt;p&gt;The study of complexity in software engineering is not new. Brooks’ &lt;em&gt;No Silver Bullet&lt;/em&gt; established early that essential complexity cannot be eliminated, only managed &lt;sup id="fnref1"&gt;1&lt;/sup&gt;. However, modern development practices—cloud infrastructure, distributed systems, and rapidly evolving frameworks—have dramatically lowered the &lt;em&gt;activation energy&lt;/em&gt; required to introduce complexity, while simultaneously increasing the cost of operating it.&lt;/p&gt;

&lt;p&gt;This asymmetry has created an environment in which teams can add complexity far more easily than they can remove it.&lt;/p&gt;

&lt;p&gt;The motivation for this study is therefore pragmatic: &lt;strong&gt;how can software teams systematically distinguish between necessary complexity and optional complexity, and how can they govern the latter to prevent long-term harm?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Intellectual Origins of Earned Complexity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Choose Boring Technology
&lt;/h3&gt;

&lt;p&gt;Dan McKinley’s essay &lt;em&gt;Choose Boring Technology&lt;/em&gt; articulates a central insight: most business problems do not require novel solutions, and novelty disproportionately increases risk relative to its benefit. McKinley argues that mature organizations succeed not by adopting cutting-edge tools, but by selecting technologies that are well-understood, widely supported, and operationally predictable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If the problem you are solving is not unique, your solution should probably not be either.”&lt;br&gt;&lt;br&gt;
— McKinley, &lt;em&gt;Choose Boring Technology&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://mcfunley.com/choose-boring-technology" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://mcfunley.com/choose-boring-technology" rel="noopener noreferrer"&gt;https://mcfunley.com/choose-boring-technology&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This work establishes the foundational idea that &lt;strong&gt;engineering maturity manifests as restraint&lt;/strong&gt;, not maximal sophistication.&lt;/p&gt;




&lt;h3&gt;
  
  
  2.2 You Are Not Google
&lt;/h3&gt;

&lt;p&gt;The essay commonly referred to as &lt;em&gt;You Are Not Google&lt;/em&gt; (popularized through multiple iterations and talks) critiques the widespread tendency for organizations to emulate the architectures of hyperscale technology companies without possessing the corresponding scale, staffing, or operational maturity.&lt;/p&gt;

&lt;p&gt;The key contribution of this perspective is the concept of &lt;strong&gt;scale proportionality&lt;/strong&gt;: architectural decisions must be justified by &lt;em&gt;actual constraints&lt;/em&gt;, not aspirational ones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Premature scaling is just another form of premature optimization.”&lt;br&gt;&lt;br&gt;
&lt;a href="https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb" rel="noopener noreferrer"&gt;https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This work directly informs the &lt;em&gt;Evidence Gate&lt;/em&gt; in the Earned Complexity framework.&lt;/p&gt;




&lt;h3&gt;
  
  
  2.3 Code Is Read More Than It Is Written
&lt;/h3&gt;

&lt;p&gt;The assertion that &lt;em&gt;code is read more than it is written&lt;/em&gt; reframes software as a long-lived communicative artifact rather than a short-lived construction task. While often attributed informally, this principle is supported by empirical research showing that maintenance accounts for the majority of software lifecycle cost &lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Readable, predictable code reduces onboarding time, error rates, and recovery time during incidents. Conversely, clever or opaque implementations amplify cognitive load and slow organizational response.&lt;/p&gt;

&lt;p&gt;This principle informs the framework’s emphasis on &lt;strong&gt;cognitive cost&lt;/strong&gt; as a first-class consideration.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Complexity as an Organizational Liability
&lt;/h2&gt;

&lt;p&gt;Complexity introduces costs that are frequently underestimated or ignored during design discussions. These costs fall into four primary categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive Load&lt;/strong&gt; – The mental effort required to understand, modify, and debug a system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Load&lt;/strong&gt; – The ongoing effort required to deploy, monitor, and recover the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure Surface Area&lt;/strong&gt; – The number of distinct ways a system can fail, including partial or silent failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Risk&lt;/strong&gt; – The fragility introduced by external libraries, platforms, vendors, or coordination mechanisms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Importantly, these costs &lt;strong&gt;compound over time&lt;/strong&gt;. Each additional layer of abstraction increases the difficulty of future changes, often non-linearly.&lt;/p&gt;

&lt;p&gt;Research in systems engineering consistently demonstrates that increased system complexity correlates with decreased reliability unless mitigated by proportional investment in controls and expertise &lt;sup id="fnref3"&gt;3&lt;/sup&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Law of Earned Complexity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Complexity must be earned by measurable pain, and paid for with controls.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This law formalizes two necessary conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Justification Condition:&lt;/strong&gt; A demonstrable, current problem exists that cannot be addressed through simpler means.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance Condition:&lt;/strong&gt; The organization is willing and able to fund the mechanisms required to safely operate the added complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If either condition is unmet, complexity should not be introduced.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Earned Complexity Framework
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Gate 0: Problem Definition
&lt;/h3&gt;

&lt;p&gt;Teams must articulate proposed complexity in a single sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We propose adding &lt;strong&gt;X&lt;/strong&gt; to address &lt;strong&gt;Y&lt;/strong&gt;, measured by &lt;strong&gt;Z&lt;/strong&gt;, with rollback &lt;strong&gt;R&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This constraint enforces clarity and prevents ambiguity-driven scope creep.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.2 Gate 1: Evidence of Pain
&lt;/h3&gt;

&lt;p&gt;Acceptable evidence includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recurrent production incidents&lt;/li&gt;
&lt;li&gt;SLO or error-budget violations&lt;/li&gt;
&lt;li&gt;Quantified performance ceilings&lt;/li&gt;
&lt;li&gt;Measured delivery bottlenecks&lt;/li&gt;
&lt;li&gt;Documented compliance requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speculative future needs are explicitly excluded.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.3 Gate 2: Alternatives Analysis
&lt;/h3&gt;

&lt;p&gt;Teams must demonstrate that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Procedural remedies were attempted&lt;/li&gt;
&lt;li&gt;Localized technical optimizations were evaluated&lt;/li&gt;
&lt;li&gt;Architectural escalation is unavoidable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This step enforces &lt;strong&gt;graduated response&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.4 Gate 3: Cost Modeling
&lt;/h3&gt;

&lt;p&gt;Each proposal is scored across four dimensions (0–5):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cognitive Load&lt;/li&gt;
&lt;li&gt;Operational Load&lt;/li&gt;
&lt;li&gt;Failure Modes&lt;/li&gt;
&lt;li&gt;Dependency Risk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total Cost Score: 0–20&lt;/p&gt;




&lt;h3&gt;
  
  
  5.5 Gate 4: Benefit Modeling
&lt;/h3&gt;

&lt;p&gt;Benefits are similarly scored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliability Improvement&lt;/li&gt;
&lt;li&gt;Performance or Cost Efficiency&lt;/li&gt;
&lt;li&gt;Delivery Velocity&lt;/li&gt;
&lt;li&gt;Security or Compliance Risk Reduction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total Benefit Score: 0–20&lt;/p&gt;




&lt;h3&gt;
  
  
  5.6 Gate 5: Controls Requirement
&lt;/h3&gt;

&lt;p&gt;Complexity must ship with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Observability (metrics, logs, traces)&lt;/li&gt;
&lt;li&gt;Alerting aligned to user impact&lt;/li&gt;
&lt;li&gt;Rollback and kill-switch mechanisms&lt;/li&gt;
&lt;li&gt;Named ownership and runbooks&lt;/li&gt;
&lt;li&gt;Failure-mode testing&lt;/li&gt;
&lt;li&gt;A stated complexity budget&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Decision Rule
&lt;/h2&gt;

&lt;p&gt;Complexity may be approved only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evidence and Alternatives gates pass, and&lt;/li&gt;
&lt;li&gt;Benefit − Cost ≥ +4, &lt;strong&gt;or&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Compliance mandates the change and controls are funded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Otherwise, the proposal is rejected or deferred.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Practical Team Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 Architecture Reviews
&lt;/h3&gt;

&lt;p&gt;Replace subjective debates with structured scoring and evidence review.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 Code Reviews
&lt;/h3&gt;

&lt;p&gt;Use the framework to challenge unnecessary abstractions early.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Incident Retrospectives
&lt;/h3&gt;

&lt;p&gt;Tie complexity reduction directly to incident prevention.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.4 Engineering Governance
&lt;/h3&gt;

&lt;p&gt;Adopt Earned Complexity as a formal policy or ADR requirement.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Case Study: Microservices Adoption
&lt;/h2&gt;

&lt;p&gt;A mid-sized team experiencing deployment conflicts considered migrating to microservices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evidence: No scaling constraints, no incident correlation&lt;/li&gt;
&lt;li&gt;Alternatives: Modular monolith not attempted&lt;/li&gt;
&lt;li&gt;Cost: High operational and cognitive load&lt;/li&gt;
&lt;li&gt;Decision: Rejected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outcome: Delivery velocity improved after refactoring boundaries without architectural escalation.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Sustaining Peak Performance
&lt;/h2&gt;

&lt;p&gt;Peak engineering performance is not achieved through maximal output or technical bravado. It emerges from &lt;strong&gt;predictable systems, calm operations, and disciplined decision-making&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Earned Complexity provides teams with a repeatable mechanism to protect these outcomes.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Conclusion
&lt;/h2&gt;

&lt;p&gt;Complexity is neither inherently good nor bad. It is &lt;strong&gt;expensive&lt;/strong&gt;. Like any scarce organizational resource, it must be justified, governed, and revisited.&lt;/p&gt;

&lt;p&gt;By adopting Earned Complexity as a formal discipline, software teams can align technical ambition with operational reality—achieving sustainable excellence without unnecessary risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ieeexplore.ieee.org/document/1663532" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://ieeexplore.ieee.org/document/1663532" rel="noopener noreferrer"&gt;https://ieeexplore.ieee.org/document/1663532&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Brooks, F. P. (1987). &lt;em&gt;No Silver Bullet—Essence and Accidents of Software Engineering&lt;/em&gt;. IEEE Computer.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Lehman, M. M. (1980). &lt;em&gt;Programs, Life Cycles, and Laws of Software Evolution&lt;/em&gt;. Proceedings of the IEEE.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Perrow, C. (1984). &lt;em&gt;Normal Accidents: Living with High-Risk Technologies&lt;/em&gt;. Basic Books.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>learning</category>
    </item>
    <item>
      <title>12 Powerful React Libraries Every Developer Should Master in 2025</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Mon, 21 Jul 2025 16:52:21 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/12-powerful-react-libraries-every-developer-should-master-in-2025-4po</link>
      <guid>https://dev.to/grantwatsondev/12-powerful-react-libraries-every-developer-should-master-in-2025-4po</guid>
      <description>&lt;h1&gt;
  
  
  12 Powerful React Libraries Every Developer Should Master in 2025
&lt;/h1&gt;

&lt;p&gt;React continues to lead the frontend world in 2025, but with its simplicity comes the challenge of choosing the right tools. Whether you're a solo developer or working on a team, these 12 libraries will help you work faster, write better code, and build more dynamic web apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. React Router
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Declarative routing for single-page React apps.&lt;/p&gt;

&lt;p&gt;React Router is still the industry standard for managing routes in React. It supports nested layouts, lazy loading, and dynamic route parameters.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://reactrouter.com/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Zustand
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Minimal state management using hooks.&lt;/p&gt;

&lt;p&gt;Zustand is gaining popularity for being tiny, fast, and avoiding boilerplate. It works great for global state in small-to-medium apps.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://docs.pmnd.rs/zustand" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. React Hook Form
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Performant, hook-based form management.&lt;/p&gt;

&lt;p&gt;React Hook Form simplifies validation and reduces re-renders in complex forms. It’s a must-have for building accessible, fast forms.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://react-hook-form.com/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. TanStack Query (React Query)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Fetch, cache, and sync server state.&lt;/p&gt;

&lt;p&gt;React Query (now TanStack Query) helps you manage API requests with automatic caching, background updates, and retry logic.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tanstack.com/query/latest" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Framer Motion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Declarative animations for React.&lt;/p&gt;

&lt;p&gt;Framer Motion is a high-performance library for creating animations, gestures, and transitions without writing CSS keyframes.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.framer.com/motion/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. React Helmet
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Control your document’s &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;React Helmet lets you dynamically set meta tags, page titles, and social tags—essential for SEO in single-page apps.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/nfl/react-helmet" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7. React Markdown
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Render Markdown content as React components.&lt;/p&gt;

&lt;p&gt;Perfect for blogs, docs, or CMS-driven sites where content is stored in Markdown. It supports plugins like remark-gfm.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/remarkjs/react-markdown" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. React Testing Library
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Tests components like a user would interact with them.&lt;/p&gt;

&lt;p&gt;It encourages good testing practices by focusing on user behavior, not implementation details.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Recharts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Charting with React components.&lt;/p&gt;

&lt;p&gt;If you need bar, line, or pie charts quickly without dealing with D3 directly, Recharts is clean and customizable.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://recharts.org/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Formik
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Form state management with validation support.&lt;/p&gt;

&lt;p&gt;Formik provides a structured way to handle form inputs, validation, and submission logic—often used with Yup.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://formik.org/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  11. React Icons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Use icon packs (FontAwesome, Material, etc.) as components.&lt;/p&gt;

&lt;p&gt;React Icons makes it easy to import and style only the icons you need. Works great with Tailwind and other styling libraries.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://react-icons.github.io/react-icons/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  12. React DnD
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Drag-and-drop interface with full control.&lt;/p&gt;

&lt;p&gt;Built by the React community, this gives you precise control over draggable interfaces like Kanban boards.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://react-dnd.github.io/react-dnd/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;The React ecosystem is thriving, but that also means constant change. The libraries above are ones you can trust—actively maintained, battle-tested, and developer-friendly.&lt;/p&gt;

&lt;p&gt;Save this post, revisit it throughout the year, and let me know which libraries you’re using in production!&lt;/p&gt;




&lt;p&gt;📝 Originally published at &lt;a href="https://www.grantwatson.dev/blog/12-powerful-react-libraries-every-developer-should-master-in-2025" rel="noopener noreferrer"&gt;grantwatson.dev/blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mastering Automation: 5 Real-World n8n Workflow Examples (With Step-by-Step Guides)</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Mon, 21 Jul 2025 16:42:09 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/mastering-automation-5-real-world-n8n-workflow-examples-with-step-by-step-guides-fmc</link>
      <guid>https://dev.to/grantwatsondev/mastering-automation-5-real-world-n8n-workflow-examples-with-step-by-step-guides-fmc</guid>
      <description>&lt;h1&gt;
  
  
  Mastering Automation: 5 Real-World n8n Workflow Examples (With Step-by-Step Guides)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.grantwatson.dev/blog" rel="noopener noreferrer"&gt;This and other articles of mine can be found here&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  📌 Overview
&lt;/h2&gt;

&lt;p&gt;n8n is an open-source workflow automation tool that allows you to connect services (APIs, webhooks, databases, CRMs, and more) into powerful automations without writing boilerplate glue code. Whether you're a beginner or seasoned power user, this article provides &lt;strong&gt;5 comprehensive, real-world workflows&lt;/strong&gt; to launch your n8n journey or deepen your automation chops.&lt;/p&gt;

&lt;p&gt;Each example includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use case breakdown&lt;/li&gt;
&lt;li&gt;Step-by-step setup&lt;/li&gt;
&lt;li&gt;Real-world benefits&lt;/li&gt;
&lt;li&gt;JSON download (optional)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔧 Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install n8n (self-hosted Docker or cloud-based)&lt;/li&gt;
&lt;li&gt;Have credentials ready (e.g., Gmail, Notion, GitHub)&lt;/li&gt;
&lt;li&gt;Know how to use the &lt;a href="https://docs.n8n.io" rel="noopener noreferrer"&gt;n8n Editor UI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Workflow 1: Automatic Lead Collection from Typeform to Notion CRM
&lt;/h2&gt;

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

&lt;p&gt;You want to capture leads from a Typeform form and store them in your Notion CRM database automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: Typeform Trigger&lt;/li&gt;
&lt;li&gt;Action: Notion node (Database row creation)&lt;/li&gt;
&lt;li&gt;Optional: Email confirmation via Gmail&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Step-by-Step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Typeform&lt;/strong&gt; with fields like Name, Email, Company.&lt;/li&gt;
&lt;li&gt;In n8n:

&lt;ul&gt;
&lt;li&gt;Add &lt;strong&gt;Typeform Trigger&lt;/strong&gt; → Select your form&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;Notion&lt;/strong&gt; node:

&lt;ul&gt;
&lt;li&gt;Choose your database&lt;/li&gt;
&lt;li&gt;Map &lt;code&gt;answers.fields&lt;/code&gt; from Typeform to Notion properties&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(Optional) Add &lt;strong&gt;Gmail&lt;/strong&gt; node to email the lead a thank-you note.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates manual copy-pasting.&lt;/li&gt;
&lt;li&gt;Keeps your CRM always up-to-date.&lt;/li&gt;
&lt;li&gt;Saves time for your sales team.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗓 Workflow 2: Google Calendar Event → Slack Notification + Mattermost Alert
&lt;/h2&gt;

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

&lt;p&gt;Notify your team in both Slack and Mattermost whenever a new calendar event is added.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: Google Calendar node (polling)&lt;/li&gt;
&lt;li&gt;Actions: Slack, Mattermost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Step-by-Step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;strong&gt;Google Calendar&lt;/strong&gt; node (polling every 10 minutes)&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Slack&lt;/strong&gt; node:

&lt;ul&gt;
&lt;li&gt;Format: "New Event: &lt;code&gt;{{summary}}&lt;/code&gt; at &lt;code&gt;{{start}}&lt;/code&gt;"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;Mattermost&lt;/strong&gt; node:

&lt;ul&gt;
&lt;li&gt;Webhook URL&lt;/li&gt;
&lt;li&gt;Use same message template&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensures every team member is notified, no matter their preferred chat app.&lt;/li&gt;
&lt;li&gt;Prevents missed meetings.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📝 Workflow 3: GitHub Issue → Create Jira Ticket → Email Developer
&lt;/h2&gt;

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

&lt;p&gt;New GitHub issues automatically create Jira tasks and notify the assigned dev by email.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: GitHub (Webhook)&lt;/li&gt;
&lt;li&gt;Actions: Jira Software, Gmail&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Step-by-Step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;strong&gt;GitHub Trigger&lt;/strong&gt; → Connect webhook to repo&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Jira node&lt;/strong&gt; to create an issue:

&lt;ul&gt;
&lt;li&gt;Project, Summary, Description from GitHub payload&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Gmail node&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Subject: &lt;code&gt;New Issue Assigned: {{issue.title}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Body: Include GitHub and Jira links&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;DevOps automation: from bug discovery to tracking in one sweep.&lt;/li&gt;
&lt;li&gt;Instant communication loop.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧾 Workflow 4: Daily Digest of New RSS Articles to Email
&lt;/h2&gt;

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

&lt;p&gt;Receive a curated daily email of tech news articles from multiple RSS feeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: Schedule (Daily)&lt;/li&gt;
&lt;li&gt;Actions: Multiple RSS Feed nodes, Merge, Gmail&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Step-by-Step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;strong&gt;Schedule node&lt;/strong&gt;: daily at 8 AM&lt;/li&gt;
&lt;li&gt;Add multiple &lt;strong&gt;RSS Feed Read nodes&lt;/strong&gt; (e.g., Ars Technica, Hacker News, TechCrunch)&lt;/li&gt;
&lt;li&gt;Merge them using &lt;strong&gt;Merge node&lt;/strong&gt; (combine mode)&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Set node&lt;/strong&gt; to format email body with titles + links&lt;/li&gt;
&lt;li&gt;Send email via &lt;strong&gt;Gmail&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Daily inbox summaries, no feed bloat.&lt;/li&gt;
&lt;li&gt;Saves hours of scrolling.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧮 Workflow 5: Auto Backup New Notion Pages to Google Drive as Markdown
&lt;/h2&gt;

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

&lt;p&gt;When a new page is created in Notion, export and save it as a Markdown file on Google Drive.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧱 Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: Notion Trigger&lt;/li&gt;
&lt;li&gt;Actions: Notion → HTTP node (for Markdown conversion), Google Drive&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠 Step-by-Step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;strong&gt;Notion Trigger&lt;/strong&gt; for new pages in a workspace&lt;/li&gt;
&lt;li&gt;Retrieve content using &lt;strong&gt;Notion Content node&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;HTTP node&lt;/strong&gt; to convert content to Markdown (or use JS function to clean format)&lt;/li&gt;
&lt;li&gt;Save the &lt;code&gt;.md&lt;/code&gt; file using &lt;strong&gt;Google Drive&lt;/strong&gt; upload node&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ✅ Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Version-controlled documentation.&lt;/li&gt;
&lt;li&gt;Local backups for regulatory or compliance reasons.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Bonus Ideas for Advanced Users
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Auto-post job listings from RSS to LinkedIn&lt;/td&gt;
&lt;td&gt;RSS → HTTP (LinkedIn API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily DB backup to S3&lt;/td&gt;
&lt;td&gt;PostgreSQL node → AWS S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync rows between Airtable &amp;amp; Google Sheets&lt;/td&gt;
&lt;td&gt;Airtable → Google Sheets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT Summarizer for new YouTube uploads&lt;/td&gt;
&lt;td&gt;YouTube → HTTP (OpenAI) → Email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger webhook from Mattermost slash command&lt;/td&gt;
&lt;td&gt;Webhook → Custom Logic → Response&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  📥 Best Practices for Workflow Building
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Namespaces&lt;/strong&gt; – Name every node clearly (&lt;code&gt;getIssueDetails&lt;/code&gt;, &lt;code&gt;sendSlackAlert&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group with Notes&lt;/strong&gt; – Add descriptive notes to each logic block.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt; – Use the &lt;strong&gt;Error Trigger&lt;/strong&gt; to catch and report errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Control&lt;/strong&gt; – Export workflows as JSON to Gitea or GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; – Never expose credentials in plain text. Use secrets and environment variables.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🎓 Where to Learn More
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/" rel="noopener noreferrer"&gt;n8n Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.n8n.io/" rel="noopener noreferrer"&gt;n8n Community Forum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ivov/n8n-resources" rel="noopener noreferrer"&gt;Awesome n8n GitHub List&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;n8n is more than just a no-code tool—it's a &lt;strong&gt;logic engine&lt;/strong&gt; that empowers creators, developers, and teams to build &lt;strong&gt;tailored automations&lt;/strong&gt; that match their workflows precisely. Whether you’re building a SaaS platform, syncing internal tools, or just automating your morning, these workflows give you a strong launchpad.&lt;/p&gt;

&lt;p&gt;Save this article. Build from these. Then go create something remarkable.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>programming</category>
    </item>
    <item>
      <title>Sell Yourself as a Developer: Creating a Personal Brand That Stands Out</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Tue, 27 May 2025 22:37:47 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/sell-yourself-as-a-developer-creating-a-personal-brand-that-stands-out-mmf</link>
      <guid>https://dev.to/grantwatsondev/sell-yourself-as-a-developer-creating-a-personal-brand-that-stands-out-mmf</guid>
      <description>&lt;p&gt;In a world full of portfolios, GitHub profiles, and online résumés, it’s easy to feel like one developer in a sea of sameness. But here’s the truth: if you want better opportunities, better projects, and more control over your career—you need to sell yourself. And that starts with a personal brand.&lt;/p&gt;

&lt;p&gt;You might think “branding” is just for influencers and startups. Not true. As a developer, your brand is your reputation made visible.&lt;/p&gt;

&lt;p&gt;Here’s how to build it, own it, and let it open doors.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🧭 Know What You Want to Be Known For&lt;/p&gt;

&lt;p&gt;Before you can create a personal brand, you need clarity. Ask yourself:&lt;br&gt;
    • What kind of problems do I love solving?&lt;br&gt;
    • Which technologies excite me most?&lt;br&gt;
    • Do I want to be known for front-end creativity, backend mastery, architecture, teaching, or something else?&lt;/p&gt;

&lt;p&gt;Your brand should be a reflection of both your skills and your passions. You can’t be the “everything” dev. Be the dev people remember for something specific.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🌐 Build a Home for Your Work&lt;/p&gt;

&lt;p&gt;Every strong brand needs a place to live. For developers, this is your personal website or blog. It should include:&lt;br&gt;
    • A clean, focused portfolio with 2–4 strong projects&lt;br&gt;
    • A professional “About Me” section that shows personality and clarity&lt;br&gt;
    • Links to your GitHub, LinkedIn, Twitter, and blog&lt;/p&gt;

&lt;p&gt;If you want bonus points? Add a blog. Write about the things you’re learning or building. Teach what you know. It reinforces your brand and builds trust.&lt;/p&gt;

&lt;p&gt;Developers who blog consistently get noticed. Not just for what they build, but for how they think.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;📣 Talk About What You Do (Even If No One’s Listening Yet)&lt;/p&gt;

&lt;p&gt;Share progress on Twitter, LinkedIn, or dev communities. You don’t need to have a massive audience—you’re documenting your journey for future you and for the one person watching who might open a door.&lt;br&gt;
    • Share a cool solution to a problem you hit&lt;br&gt;
    • Post a demo or screenshot of a feature in progress&lt;br&gt;
    • Reflect on a challenge and how you overcame it&lt;/p&gt;

&lt;p&gt;This isn’t bragging. It’s visibility.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;💼 LinkedIn and GitHub: Signal vs. Noise&lt;/p&gt;

&lt;p&gt;Too many developers ignore or underuse these platforms.&lt;/p&gt;

&lt;p&gt;LinkedIn:&lt;br&gt;
    • Keep your headline crisp: “C# Backend Developer | Blazor + .NET Enthusiast” is better than “Software Engineer.”&lt;br&gt;
    • Fill out your “About” with what you do best and what you want next&lt;br&gt;
    • Share articles, comment on posts, be visible&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
    • Pin 3–6 repos that best reflect your skills&lt;br&gt;
    • Keep READMEs sharp and clean&lt;br&gt;
    • Avoid noisy commit histories on weak toy projects&lt;/p&gt;

&lt;p&gt;These platforms aren’t just your résumé—they’re your billboard.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🔍 Be Searchable, and Make It Easy to Connect&lt;/p&gt;

&lt;p&gt;Use your full name consistently across platforms (or your brand handle). Make sure people can find you by name, GitHub handle, or blog title.&lt;/p&gt;

&lt;p&gt;Add contact forms. Post a professional email. Link to your site in your GitHub bio. Make it easy for someone to reach out after they see your work.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;💥 The X-Factor: Authenticity&lt;/p&gt;

&lt;p&gt;The strongest brands aren’t fake. They’re focused. You don’t need to pretend to be a 10x genius or tweet in memes. You just need to show up consistently, share your work, and make your value obvious.&lt;/p&gt;

&lt;p&gt;Let people see:&lt;br&gt;
    • What you care about&lt;br&gt;
    • What problems you solve well&lt;br&gt;
    • Why you’re worth working with&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🚀 Final Thought&lt;/p&gt;

&lt;p&gt;Your brand is already forming, whether you’re shaping it or not. Every project you ship, every post you write, and every way you show up online adds to that signal.&lt;/p&gt;

&lt;p&gt;The question is—are you curating it? Or leaving it to chance?&lt;/p&gt;

&lt;p&gt;If you want to stand out as a developer, don’t just write good code.&lt;/p&gt;

&lt;p&gt;Sell it. Shape it. Share it.&lt;/p&gt;

&lt;p&gt;That’s your personal brand.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>One Way Binding in Blazor Components</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Sun, 25 Jul 2021 03:36:49 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/one-way-binding-in-blazor-components-1j3o</link>
      <guid>https://dev.to/grantwatsondev/one-way-binding-in-blazor-components-1j3o</guid>
      <description>&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/blazor-components-one-way-binding" rel="noopener noreferrer"&gt;ORIGINAL POST&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Blazor Components: One Way Data Binding
&lt;/h2&gt;

&lt;p&gt;One of the major roles of a developer is on how they can make a static page either in a desktop, mobile or web application dynamic, or even if it needs to be. Binding data is a fundamental task in any single page applications (SPAs). At some point every application needs to either display data in form of labels, or receive data in the form of input fields and select boxes. &lt;/p&gt;

&lt;p&gt;While most SPA frameworks have similar concepts for data binding, either one way binding or two way binding, the way they work and are implemented varies widely. In this post, we're going to have a good look at how one way and two way binding work in Blazor.&lt;/p&gt;

&lt;h3&gt;
  
  
  One Way Binding
&lt;/h3&gt;

&lt;p&gt;One way bindings have a unidirectional flow, meaning that updates to the value only flow one way. A couple of examples of one way binding are rendering a label dynamically or dynamically outputting a CSS class name in markup. &lt;/p&gt;

&lt;p&gt;One way bindings can be constant and not change, but often the value will have a reason to be updated. Otherwise it would probably be better to avoid using a bound value altogether and just type the value out directly. &lt;/p&gt;

&lt;p&gt;In Blazor, when modifying a one way binding the application is going to be responsible for making the change. This could be in response to user action or event such as a button click. The point being, that the user will never be able to modify the value directly, hence one way binding.&lt;/p&gt;

&lt;p&gt;Now that we have a rudimentary idea of what one way binding is, let’s take a look of it in the form of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;@Title&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;@code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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="s"&gt;"Banging Title Mate!"&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;In the code above, we have a component which displays a heading. The contents of that heading, Title, is a one way bound value. In order to bind one way values we use the @ symbol followed by the property, the field or even the method we want to bind too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;@Title&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;@onclick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"UpdateTitle"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Click&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;@code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateTitle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Greeting, Blazor Friends!"&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;In the first example the value is set and never changed, in this example we've added a method which updates the value of Title when the button is clicked. &lt;/p&gt;

&lt;p&gt;As we talked about previously, values can only be updated in one direction and here we can see that in action. When the buttons onclick event is triggered the UpdateTitle method is called and Title property is updated to the new value. Executing event handlers in Blazor triggers a re-render which updates the UI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One Way Binding Between Components&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous examples, we looked at one way binding inside of a component. But what if we want one way binding across components? Using our previous example, say we wanted to display the title of a parent component in a child component, how could we achieve this? By using component parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;@Title&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;@onclick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"UpdateTitle"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChildComponent&lt;/span&gt; &lt;span class="n"&gt;ParentsTitle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;@code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateTitle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, Blazor!"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Child&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;@ParentsTitle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;@code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ParentsTitle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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;In the example, the parent component is passing its title into the child component via the child components ParentsTitle component parameter. When then components are first rendered the headings will be the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Child&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Update Title button is pressed then the output will become the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Blazor&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;Child&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Blazor&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to what happened with the earlier example inside a single component. The button click event calls the UpdateTitle method and the Title property is updated. Then the running of the event handler triggers a re-render of the parent component. &lt;/p&gt;

&lt;p&gt;This also updates the Title parameter passed to the child component. Updating the component parameter triggers a re-render of the child component, updating its UI with the new title.&lt;/p&gt;

&lt;p&gt;I cannot wait to start working on the next post for 2 way binding. If you would like to have me as your personal coach for learning how to program, feel free to email me &lt;a href="https://www.grantwatson.app/contact" rel="noopener noreferrer"&gt;here&lt;/a&gt; or email me directly at &lt;a href="mailto:info@grantwatson.dev"&gt;info@grantwatson.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>blazor</category>
      <category>microsoft</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Blazor Components</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Tue, 20 Jul 2021 21:22:47 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/blazor-components-3fa</link>
      <guid>https://dev.to/grantwatsondev/blazor-components-3fa</guid>
      <description>&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/blazor-components" rel="noopener noreferrer"&gt;ORIGINAL POST&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Blazor Components Basics and Simple Structure:
&lt;/h1&gt;

&lt;h3&gt;
  
  
  What are Blazor components?
&lt;/h3&gt;

&lt;p&gt;A Blazor component is an independent part of the Blazor Application. These entities can be as simple or as complex as the application calls for. Blazor applications are made utilizing parts that are adaptable, lightweight, and can be settled, reused, and shared between ventures. A component is the base component of the Blazor application, i.e., each page is considered as a segment in Blazor.&lt;/p&gt;

&lt;p&gt;It utilizes the mix of Razor, HTML, and C# code as a part. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;@page&lt;/span&gt; &lt;span class="s"&gt;"/counter"&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;@currentCount&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="nc"&gt;btn&lt;/span&gt; &lt;span class="n"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="s"&gt;" onclick="&lt;/span&gt;&lt;span class="n"&gt;@IncrementCount&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;Click me&amp;lt;/button&amp;gt;
&lt;/span&gt;
&lt;span class="n"&gt;@functions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;currentCount&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="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;IncrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;currentCount&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;Blazor segments are executed in *.cshtml records utilizing a mix of C# and HTML markup. The UI for a segment is characterized utilizing HTML while dynamic delivering rationale like circles, conditionals, articulations are included utilizing an installed C# language structure called Razor.&lt;/p&gt;

&lt;p&gt;In the work square, we can characterize all the properties that are utilized in see markup, and the techniques are bound with control as an occasion.&lt;/p&gt;

&lt;p&gt;At the point when a Blazor application is assembled, the HTML markup and C# delivering rationale are changed over into a part class, and the name of the produced class coordinates the name of the record.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Members
&lt;/h3&gt;

&lt;p&gt;Individuals from the segment class are characterized in a @functions square, and you can utilize more than one @functions obstruct in a part. In the @functions square, segment states, for example, properties and fields are determined alongside strategies for occasion taking care of or for characterizing other part rationales. Segment individuals would then be able to be utilized as a major aspect of the part's delivering rationale utilizing C# articulations that start with &lt;em&gt;@&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All rendered Blazor views descend from the ComponentBase class, this includes Layouts, Pages, and also Components.&lt;/p&gt;

&lt;p&gt;A Blazor page is essentially a component with a &lt;em&gt;@page&lt;/em&gt; directive that specifies the URL the browser must navigate to in order for it to be rendered. In fact, if we compare the generated code for a component and a page there is very little difference. The following generated source code can be found in &lt;em&gt;Counter.razor.g.cs&lt;/em&gt; in the folder &lt;em&gt;obj\Debug\netcoreapp3.0\Razor\Pages&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;SomeBlazorApp.Client.Pages&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AspNetCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LayoutAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MainLayout&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AspNetCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RouteAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/counter"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AspNetCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ComponentBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;BuildRenderTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AspNetCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderTree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderTreeBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Code omitted for simplicity&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;IncrementCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;counter&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;&lt;em&gt;[Microsoft.AspNetCore.Components.RouteAttribute("/counter")]&lt;/em&gt; identifies the URL for the page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Microsoft.AspNetCore.Components.LayoutAttribute(typeof(MainLayout))]&lt;/em&gt; identifies which layout to use.&lt;/p&gt;

&lt;p&gt;In fact, because pages are merely components decorated with additional attributes, if you alter the Pages/Index.razor file of a default Blazor app, it is possible to embed the Counter page as a component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;@page&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;!&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;Welcome&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When embedding a page within another page, Blazor treats it as a component. The LayoutAttribute on the embedded page is ignored because Blazor already has an explicit container – the parent component that contains it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Components
&lt;/h2&gt;

&lt;p&gt;Depending on your hosting service, and whether you chose Blazor WebAssembly or Blazor Server, the following may be ambiguous. But let’s say for simplicity sake, your main solution has 3 projects: Client/Server/Shared.&lt;/p&gt;

&lt;h4&gt;
  
  
  Under the Client Project:
&lt;/h4&gt;

&lt;p&gt;Make a new folder called Components. This name can be anything that you wish it to be, for it is not a special or “needed” name. Once you have create the folder, create a file within the folder and name it ComponentOne.razor and the following markup is the starting point of any new component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Section 1&lt;/span&gt;
&lt;span class="n"&gt;@page&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;

&lt;span class="c1"&gt;//Section 2&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;Welcome&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;//Section 3&lt;/span&gt;
&lt;span class="n"&gt;@code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//empty code block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s stop for a quick moment to discuss what each section is. If you have ever worked in ReactJS or Angular, this may look familiar to you, and feel free to go forward. If this is your first time working in a front end framework, let’s go over some basics:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Section 1:&lt;/em&gt;&lt;br&gt;
For clarity and simplicity over the structure/architecture of a component, this is where you will post and dictate your using statements for your components. There is a _Import.razor file to where you can place your using statements, but this is beyond the scope of this article. When you need to declare another file from your solution into you component, put them at the top of your component here. This is also where you can call your Nuget packages you specifically want to use in your component.&lt;/p&gt;

&lt;p&gt;The next area you see here is the @page “/”&lt;/p&gt;

&lt;p&gt;Similar with routing in React, we dictate the routing of this particular component as “/”. Again, routing is outside the scope of this article, I will have another article covering this in the future.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Section 2:&lt;/em&gt;&lt;br&gt;
This area should look “easy” to you. Especially if your component is a simple display component. This area is where you place your HTML code inside the component.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Section 3:&lt;/em&gt;&lt;br&gt;
This area is the fun part of the component in my opinion. This is where we combine C# syntax into the component itself. May it be service calls, httpClient and JSON calls to APIs. In this code block, you as the developer can make you component perform magic here.&lt;/p&gt;

&lt;p&gt;In the next few articles, I will go into more in the depth and breadth of components, and the following is what I am considering covering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One Way Binding in Components&lt;/li&gt;
&lt;li&gt;Two Way Binding in Components&lt;/li&gt;
&lt;li&gt;Component Literals, Expressions, and Directives&lt;/li&gt;
&lt;li&gt;Browser DOM and Component Events&lt;/li&gt;
&lt;li&gt;Cascading Values&lt;/li&gt;
&lt;li&gt;Code Generated HTML Attributes&lt;/li&gt;
&lt;li&gt;Capturing Unexpected Parameters&lt;/li&gt;
&lt;li&gt;Replacing Attributes on child components&lt;/li&gt;
&lt;li&gt;Component Lifecycles&lt;/li&gt;
&lt;li&gt;Multi-threaded rendering &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If there is a topic that you would like for me to cover with Blazor, or any language that you would like to see, please feel free to contact me through email at &lt;a href="mailto:info@grantwatson.dev"&gt;info@grantwatson.dev&lt;/a&gt; or on Twitter @granticusdev&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>blazor</category>
      <category>microsoft</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Programming Languages That Will Dominate</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Mon, 29 Mar 2021 01:31:36 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/programming-languages-that-will-dominate-1kh9</link>
      <guid>https://dev.to/grantwatsondev/programming-languages-that-will-dominate-1kh9</guid>
      <description>&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/top-programming-languages-2021" rel="noopener noreferrer"&gt;Original Post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Forecasting the world’s most popular programming languages over the next few years is a difficult task. Oftentimes, bold predictions about a language’s dominance won’t pan out; then you have the languages that seem to come out of nowhere to seize a significant niche (often with a bit of a boost from a major tech company). &lt;/p&gt;

&lt;p&gt;Every so often, though, a language’s spike in popularity makes it easier to predict its rosy future. It’s all about the long term—and you should structure your learning (and mastery) appropriately. “I’d recommend deciding what’s important and building your working culture around it rather than worrying about whether you’re missing out by not using a new language,” he adds. “If you’re an individual engineer and want to know how you can help yourself, double down on the fundamentals of how the languages you currently work in interact with the underlying operating system or runtime. A little focus on the fundamentals goes a long way here, and the fundamentals will still be the same in 2030.”&lt;/p&gt;

&lt;p&gt;So which programming languages will continue to dominate in 2021? &lt;/p&gt;

&lt;h2&gt;
  
  
  Python
&lt;/h2&gt;

&lt;p&gt;Artur Yolchan, Senior Software Engineer and owner of the website Coding Skills, says: “Python will probably be the most favorite programming language for developers in 2021.” &lt;/p&gt;

&lt;p&gt;The increased use of Python in a specialized context has a lot to do with that, suggests Alex Yelenevych, CMO of CodeGym: “In the development of artificial intelligence systems, Python has proven itself. In addition, many modern and safe sites are written in Python, and it is also very often learned in schools. The language is pleasant and quite simple for beginners, so its popularity will only grow.”&lt;/p&gt;

&lt;p&gt;It takes a lot to erode the usage of older, more generalist programming languages, even when newer languages begin to attract a lot of buzz, adds Matt Pillar, VP of Engineering at OneSignal: “Python is an old favorite, and it’s not going away anytime soon. While incumbents like Rust and TypeScript are occupying more and more mindshare, taking some attention away from Python, Python continues to be one of the most loved and most utilized programming languages. With its strong connection to data science toolkits, Python is being taught at an increasing number of programming bootcamps and is well poised to be a favorite first language for developers in the years to come.”&lt;/p&gt;

&lt;p&gt;If you’re totally new to Python, start your learning journey by heading over to Python.org, which offers a handy beginner’s guide. Microsoft has a video series, “Python for Beginners,” with dozens of short, Python-related lessons. There’s also a variety of Python tutorials and books (some of which will cost a monthly fee) that will teach you the nuances of the programming language (and don’t forget your IDEs).&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;p&gt;Michael O’Connell, Chief Analytics Officer at TIBCO Software, doesn’t think the ultra-popular JavaScript is going anywhere, especially when it comes to dominating developers’ mindshare in 2021:&lt;/p&gt;

&lt;p&gt;The maturation of JavaScript as a design and development environment has been phenomenal and will accelerate in 2021. Whether you are working on the front-end with JavaScript, apps and frameworks with React, Angular and vue.js, desktop apps with Electron.js, or backend with Node.js, JavaScript is the ticket! You can even develop machine learning with Tensorflow.js. &lt;/p&gt;

&lt;p&gt;I see the worlds of self-service BI and visual analytics becoming ever more mashed up in 2021 with (a) BI and analytics vendors providing seamless experiences for extending their graphics palettes as simple-to-modify native capabilities and deployment; and (b) marketplaces for sharing extensions across broad communities of practice. The maturation of Vega (from the d3 pioneers) as a visualization grammar and platform will help standardize and enforce best practices across these communities.&lt;/p&gt;

&lt;p&gt;Yelenevych agrees, citing JavaScript’s frameworks as a key component to its success. “JavaScript—you can find this language in use on almost every website. I think React, already the most popular JS frontend library, will continue to gain popularity. In general, developers love to create applications in React.”&lt;/p&gt;

&lt;p&gt;Indeed, it seems virtually certain that JavaScript will continue to serve as the engine that powers the web well beyond 2021, especially as new generations of students utilize it for websites’ scripted behavior. Millions of websites will still rely on third-party JavaScript libraries and frameworks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Blazor
&lt;/h2&gt;

&lt;p&gt;With the popularity of C#, I believe deeply that Blazor will become extremely popular this year. Typically speaking, programmers love working in one language, especially if that particular language is used for web development. In previous years, for any form of web development, a developer needed at least 2 different languages, a backend API as well as JavaScript/TypeScript. With Blazor now, you can potentially dismantle all use of JS for the use of C# from the backend to the frontend. They utilized the Razor language and WebAssembly, as well as a server side rendering. To read more, see a few of my previous articles listed below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/blazor-dependency-injection" rel="noopener noreferrer"&gt;Data Injection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/blazor-data-binding" rel="noopener noreferrer"&gt;Data Binding&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/deep-dive-blazor-routing" rel="noopener noreferrer"&gt;Routing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/deep-dive-blazor-components" rel="noopener noreferrer"&gt;Blazor Components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/deep-dive-blazor-server" rel="noopener noreferrer"&gt;Blazor Server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/deep-dive-blazor-wasm" rel="noopener noreferrer"&gt;Blazor Wasm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grantwatson.app/blog/blazing-good-time-with-blazor" rel="noopener noreferrer"&gt;What is Blazor&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why are code reviews important?</title>
      <dc:creator>Grant Watson</dc:creator>
      <pubDate>Mon, 15 Feb 2021 19:39:11 +0000</pubDate>
      <link>https://dev.to/grantwatsondev/why-are-code-reviews-important-995</link>
      <guid>https://dev.to/grantwatsondev/why-are-code-reviews-important-995</guid>
      <description>&lt;p&gt;Original post &lt;a href="https://www.grantwatson.app/blog/code-reviews-are-important" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define what a code review is:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code review is a software quality assurance activity in which one or several people check a program mainly by viewing and reading parts of its source code, and they do so after implementation or as an interruption of implementation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Push &amp;amp; Merge Conflicts Galore
&lt;/h2&gt;

&lt;p&gt;Ideas of why it is a good idea to perform code reviews:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sharing of knowledge and new techniques&lt;/li&gt;
&lt;li&gt;Maintainability&lt;/li&gt;
&lt;li&gt;Compliance in quality and requirements&lt;/li&gt;
&lt;li&gt;Committers are motivated to write clean code, minimizing mistakes&lt;/li&gt;
&lt;li&gt;Sharing of knowledge and new techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every project has a host of unwritten rules and tacit understandings. This "institutional knowledge" must be transmitted to all new arrivals on a project. By definition it is impossible (and perhaps not even cost effective) to write down this information or to convey it all in one sitting. The inductee must acquire this information in the first months on the project, usually elicited from experienced developers when he does something wrong.&lt;/p&gt;

&lt;p&gt;Code review can facilitate the communication of institutional knowledge as it relates to code written by the newbie. Experienced team members have the opportunity to impart their wisdom and advice.&lt;/p&gt;

&lt;p&gt;At the heart of all agile teams is unbeatable flexibility: an ability to take work off the backlog and begin execution by all team members. As a result, teams are better able to swarm around new work because no one is the "critical path." Full stack engineers can tackle front-end work as well as server-side work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensuring maintainability
&lt;/h2&gt;

&lt;p&gt;The expense of developing software is not just in its initial creation but in the ability of developers to use and modify existing code in the future. Software is notoriously difficult and expensive to maintain. This is especially true when a developer leaves a project and a new developer arrives, but it is even true with a single developer looking back on code he wrote six months ago.&lt;/p&gt;

&lt;p&gt;Maintainability is generally achieved by code organization and adequate comments. A person uninvolved in the project should be able to read a portion of code and understand what it does, see the constraints and preconditions of its use and contextual information (e.g. the author used a peculiar technique because of a bug in the OS). In addition, software organizations often have coding guidelines ranging from whitespace conventions to the maximum size of a function. A reviewer can provide the ignorance and objectivity necessary to ensure these goals.&lt;/p&gt;

&lt;p&gt;Shell Research saved an average of 30 hours of maintenance work for every hour invested in inspections.&lt;/p&gt;

&lt;p&gt;— Software Practice and Experience, 22(2):173-182, Feb. 1992.&lt;/p&gt;

&lt;h2&gt;
  
  
  It dramatically improves code quality
&lt;/h2&gt;

&lt;p&gt;Let’s make something clear: this is not about standards and code linting (at least not exclusively). It’s about making code more efficient. In a team where everybody has their own background and strong suits, asking for improvements (because that’s what it’s about) is always a good idea. Someone could suggest a smarter solution, a more appropriate design pattern, a way to reduce complexity or to improve performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimizing your mistakes and their impact
&lt;/h2&gt;

&lt;p&gt;This might seem like the most obvious advantage to the code peer review process, but it’s also one of the most important. When you’re working with the real pressures of time and budget, it’s easy to skip this step. Sure, you’re confident in your work, but even the best coders can go crossed-eyed from looking at their own work too long. Code review helps give a fresh set of eyes to identify bugs and simple coding errors before your product gets to the next step, making the process for getting the software to the customer more efficient.&lt;/p&gt;

&lt;p&gt;Simply reviewing someone’s code and identifying errors is great. However, when it comes to the code peer review process there also needs to be a level of follow-up and accountability. Make sure there is process in place for checking back in to confirm code discrepancies have been addressed before moving into production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensuring project quality and meeting requirements
&lt;/h2&gt;

&lt;p&gt;The scope of any given software project and its requirements might run through the hands of several developers. The code review process can serve as a check and balance against different interpretations of that scope and requirements compared to the code that ends up being delivered. The second set of eyes can ensure you don’t fall into the “pit” you created based on your own understanding of what is being asked and that something important hasn’t been overlooked. Having code scrutinized by your peers can save a lot of time “confronting” QA later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving code performance
&lt;/h2&gt;

&lt;p&gt;Due to the lack of experience, some younger developers might be unaware of optimization techniques that could be applied on their code. The code review process provides an opportunity for these developers to acquire skills and boost the performance of their code. Additionally, it gives these younger developers a chance to hone their skills and become experts in their craft.&lt;/p&gt;

&lt;p&gt;While realizing the required functionalities, many developers also try to pursue optimized code for conciseness and performance efficiency. However, this will result in more code complexity and less readability. (Note: Code conciseness doesn’t mean its logic is simple to understand.) Moreover, the data model that the code is built on might change in later development phases. Thus, such premature optimization will eventually increase the cost of maintenance.&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>testing</category>
      <category>reviews</category>
    </item>
  </channel>
</rss>
