<?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: Nishanthan K</title>
    <description>The latest articles on DEV Community by Nishanthan K (@nishanthan-k).</description>
    <link>https://dev.to/nishanthan-k</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2117032%2F840671b3-0012-4e95-8c3a-fce7ced0a21c.png</url>
      <title>DEV Community: Nishanthan K</title>
      <link>https://dev.to/nishanthan-k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nishanthan-k"/>
    <language>en</language>
    <item>
      <title>Backpropagation in Deep Learning: A Complete, Intuitive, and Practical Guide</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Wed, 17 Dec 2025 03:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/backpropagation-in-deep-learning-a-complete-intuitive-and-practical-guide-3dm4</link>
      <guid>https://dev.to/nishanthan-k/backpropagation-in-deep-learning-a-complete-intuitive-and-practical-guide-3dm4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: Why Backpropagation Matters
&lt;/h2&gt;

&lt;p&gt;Backpropagation is the &lt;strong&gt;learning engine&lt;/strong&gt; behind modern deep learning.&lt;br&gt;
Every time a neural network improves its predictions — from recognizing faces to generating text — the improvement comes from one mechanism: &lt;strong&gt;adjusting weights using gradients&lt;/strong&gt;, and those gradients are computed through backpropagation.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this matters:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A neural network is essentially a giant parametric function with millions or billions of weights.&lt;/li&gt;
&lt;li&gt;Backpropagation provides an efficient way to compute how much each weight contributed to the final error.&lt;/li&gt;
&lt;li&gt;Without backpropagation, training a deep model would be computationally impossible — you’d need to recompute partial derivatives for every weight independently, which would scale exponentially.&lt;/li&gt;
&lt;li&gt;Backprop makes learning &lt;strong&gt;practical&lt;/strong&gt; and &lt;strong&gt;efficient&lt;/strong&gt;, even for very large models.&lt;/li&gt;
&lt;li&gt;It also forms the foundation for:

&lt;ul&gt;
&lt;li&gt;Convolutional networks&lt;/li&gt;
&lt;li&gt;Transformers
-Diffusion models&lt;/li&gt;
&lt;li&gt;Reinforcement learning&lt;/li&gt;
&lt;li&gt;Large language models&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In short, backpropagation is the backbone of modern AI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What a Neural Network Really Computes (Forward Pass Overview)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before understanding backpropagation, we need a clear picture of what the network does in the &lt;em&gt;&lt;code&gt;forward pass&lt;/code&gt;&lt;/em&gt; because backprop is simply the &lt;strong&gt;reverse of this computation&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;At its core, a neural network performs three steps repeatedly across layers:

&lt;ol&gt;
&lt;li&gt;Take inputs from the previous layer&lt;/li&gt;
&lt;li&gt;Apply a linear transformation using weights and biases&lt;/li&gt;
&lt;li&gt;Pass the result through a non-linear activation function
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mathematically, for a single layer:

z = Wx + b
a = f(z)

Where:
- x = input vector
- W = weight matrix
- b = bias vector
- z = linear combination (pre-activation)
- f(⋅) = activation function (ReLU, Sigmoid, etc.)
- a = output (activation)

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

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;A deep network simply &lt;strong&gt;repeats this process&lt;/strong&gt; layer after layer.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each layer transforms the input into a representation that makes the final task easier — whether that’s classification, detection, language modeling, or something else.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why this matters for backprop:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The forward pass creates a computational graph — &lt;strong&gt;a chain of operations where each output depends on previous ones&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Backprop will move in the opposite direction through this graph, calculating &lt;strong&gt;how changes in each weight affect the final loss&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Knowing the exact operations in the forward pass helps us understand how the gradients flow backward.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Core Idea Behind Backpropagation
&lt;/h2&gt;
&lt;h3&gt;
  
  
  How should each weight in the network change to reduce the final error?”
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A neural network may have millions of parameters, and each parameter influences the output in a slightly different way. Backpropagation provides a systematic method to compute these influences efficiently&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Here’s the core idea in simple terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Calculate the loss&lt;/strong&gt;:  After the forward pass, we compare the model’s prediction with the true label and compute how “wrong” the prediction was.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Determine how the loss changes with respect to the output of the last layer&lt;/strong&gt;. This tells us the immediate direction in which the model should adjust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move backward layer by layer&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Using the chain rule, we figure out how the loss depends on:

&lt;ol&gt;
&lt;li&gt; each layer’s activations&lt;/li&gt;
&lt;li&gt;each layer’s weights&lt;/li&gt;
&lt;li&gt;each layer’s inputs&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accumulate gradients&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Every weight gets a gradient value that tells us:

&lt;ul&gt;
&lt;li&gt;direction (positive or negative)&lt;/li&gt;
&lt;li&gt;magnitude (how strong the update should be)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update the weights&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Optimizers like &lt;strong&gt;SGD&lt;/strong&gt; or &lt;strong&gt;Adam&lt;/strong&gt; use these gradients to move the weights to slightly better values.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Backprop does not compute gradients from scratch for each weight.&lt;br&gt;
It reuses intermediate results from the forward pass, which makes the entire process efficient.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Understanding the Computational Graph
&lt;/h2&gt;

&lt;p&gt;A neural network can be viewed as a computational graph — a sequence of operations where each node represents a mathematical function, and each edge represents the flow of data.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why this graph matters:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every value produced during the forward pass (like z, a, activations, etc.) becomes part of the graph.&lt;/li&gt;
&lt;li&gt;Backpropagation relies on this graph to know how outputs depend on earlier computations.&lt;/li&gt;
&lt;li&gt;Deep learning frameworks like PyTorch and TensorFlow automatically build this graph behind the scenes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Chain Rule: The Mathematical Engine of Backpropagation
&lt;/h2&gt;

&lt;p&gt;Backpropagation is built entirely on one mathematical principle: the chain rule of calculus.&lt;br&gt;
If you understand the chain rule, you understand the heart of backprop.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why the chain rule is needed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In a neural network, the loss doesn’t depend on any weight directly.&lt;/li&gt;
&lt;li&gt;Instead, it depends on:

&lt;ul&gt;
&lt;li&gt;the activations of the last layer&lt;/li&gt;
&lt;li&gt;which depend on the previous layer&lt;/li&gt;
&lt;li&gt;which depend on the one before it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This creates a long chain of dependencies.&lt;/li&gt;
&lt;li&gt;The chain rule tells us how a change in any early variable (like a weight) affects the final loss.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Applying the chain rule to layers
&lt;/h3&gt;

&lt;p&gt;Consider one layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    z = Wx + b
    a = f(z)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    L = Loss(a)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the chain rule, the gradient of the loss with respect to the weights is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ∂L/∂W = (∂L/∂a) · (∂a/∂z) · (∂z/∂W)

    where
        ∂L/∂a: how the loss changes with the layer’s output
        ∂a/∂z: how the activation reacts to its input
        ∂z/∂W: how the output of this layer depends on its weights
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step-by-Step Backpropagation Through a Single Neuron
&lt;/h2&gt;

&lt;p&gt;Now that the chain rule and computational graph ideas are clear, let’s walk through backpropagaion &lt;strong&gt;inside one neuron&lt;/strong&gt;.&lt;br&gt;
This is the smallest unit of a neural network, and understanding it removes most of the confusion around deeper models.&lt;/p&gt;
&lt;h3&gt;
  
  
  Forward Pass (Single Neuron)
&lt;/h3&gt;

&lt;p&gt;A neuron computes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    z = Wx + b
    a = f(z)

    where
        x -&amp;gt; input
        W -&amp;gt; weight
        b -&amp;gt; bias
        f -&amp;gt; activation function
        a -&amp;gt; output of the neuron

    L(a): Loss function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backward Pass (Goal: compute gradients)
&lt;/h3&gt;

&lt;p&gt;We want&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gradient with respect to the activation output
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ∂L/∂a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Gradient through the activation function
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ∂L/∂z = (∂L/∂a) · f′(z)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Gradient with respect to the weights
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ∂L/∂W = (∂L/∂z) · x

Since   z = Wx + b

        ∂z/∂W = x

So,
        ∂L/∂W = ∂L/∂z * x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Gradient with respect to the bias
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        ∂z/∂b = 1
So,
        ∂L/∂b = ∂L/∂z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Gradient with respect to the input
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        ∂L/∂x = (∂L/∂z) · W
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Backpropagation is more than a mathematical procedure — it’s the core mechanism that allows neural networks to learn.&lt;br&gt;
Once you understand how gradients flow through a network, you gain the ability to reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why certain architectures train well?&lt;/li&gt;
&lt;li&gt;Why others fail?&lt;/li&gt;
&lt;li&gt;How initialization, activations, normalization, and residual connections shape gradient behavior?&lt;/li&gt;
&lt;li&gt;What makes transformers, CNNs, and deep RNNs stable?&lt;/li&gt;
&lt;li&gt;How to debug training issues with confidence?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deeper your intuition for backpropagation, the more effective you become at designing and improving models.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Neural Network — A Simple, Beginner-Friendly Overview</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Mon, 01 Dec 2025 03:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/neural-network-a-simple-beginner-friendly-overview-16p8</link>
      <guid>https://dev.to/nishanthan-k/neural-network-a-simple-beginner-friendly-overview-16p8</guid>
      <description>&lt;p&gt;Neural networks are at the heart of modern AI. Whether it’s image recognition, chatbots, or recommendation systems, they all rely on these interconnected structures to learn patterns from data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Neural Network?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A neural network is made up of many &lt;strong&gt;interconnected nodes (neurons)&lt;/strong&gt;, each acting like a tiny decision-making unit.
&lt;/li&gt;
&lt;li&gt;Every connection between neurons carries a &lt;strong&gt;weight&lt;/strong&gt;, which is a parameter the model learns during training.
&lt;/li&gt;
&lt;li&gt;These weights determine how strongly one neuron influences another, and they are gradually adjusted so the network can make better predictions over time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How Are the Values Estimated?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When training begins, each neuron starts with &lt;strong&gt;random weights&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;These weights are updated through &lt;strong&gt;backpropagation&lt;/strong&gt;, a feedback process that adjusts them based on how wrong the model’s prediction was.
&lt;/li&gt;
&lt;li&gt;The update depends on:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loss value:&lt;/strong&gt; how far the prediction was from correct
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradient:&lt;/strong&gt; the direction the weight should move
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate:&lt;/strong&gt; how big each step of adjustment should be
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The goal is to &lt;strong&gt;reduce the loss&lt;/strong&gt; and push the &lt;strong&gt;gradient closer to zero&lt;/strong&gt; over time.
&lt;/li&gt;

&lt;li&gt;Interpreting the gradient:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Positive gradient → decrease the weight&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Negative gradient → increase the weight&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Neural Networks?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Traditional machine learning works well when data patterns are &lt;strong&gt;linear&lt;/strong&gt;, meaning they follow straight-line relationships.
&lt;/li&gt;
&lt;li&gt;Neural networks shine because they use &lt;strong&gt;activation functions&lt;/strong&gt; to introduce &lt;strong&gt;non-linearity&lt;/strong&gt;, enabling them to learn complex patterns — shapes, edges, behaviors, and any relationship that isn’t simple or straight.
&lt;/li&gt;
&lt;li&gt;Popular activation functions include &lt;strong&gt;ReLU&lt;/strong&gt;, &lt;strong&gt;Sigmoid&lt;/strong&gt;, and &lt;strong&gt;Softplus&lt;/strong&gt;, each influencing how a neuron activates.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Layers in a Neural Network
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Input Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The network begins with an input layer containing multiple nodes.
&lt;/li&gt;
&lt;li&gt;These nodes don’t learn anything — they simply &lt;strong&gt;pass the raw input into the network&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;They are often mistaken for neurons, but their job is mainly to feed data forward.

&lt;ul&gt;
&lt;li&gt;They take the raw data.&lt;/li&gt;
&lt;li&gt;They pass those numbers into the network.&lt;/li&gt;
&lt;li&gt;They do not apply weights, biases, or activations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Because of this, these nodes are often mistaken for “neurons” but they’re better understood as data carriers — a doorway into the network rather than processors.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hidden Layers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A network may have one or several hidden layers, each filled with neurons.
&lt;/li&gt;
&lt;li&gt;These are the &lt;strong&gt;actual learning units&lt;/strong&gt;, transforming the input step by step to capture patterns in the data.

&lt;ul&gt;
&lt;li&gt;It receives input from the previous layer&lt;/li&gt;
&lt;li&gt;Applies &lt;strong&gt;weights&lt;/strong&gt; and &lt;strong&gt;biases&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Passes the result through an &lt;strong&gt;activation function&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And sends the output deeper into the network&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;This repeated transformation allows the model to gradually extract patterns — edges in images, sentiment in text, or trends in numerical data.&lt;/li&gt;

&lt;li&gt;Layer by layer, the network builds up a more meaningful internal representation of the input.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Output Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The final layer, responsible for producing the network’s output — a prediction, probability, class label, etc.&lt;/li&gt;
&lt;li&gt;Depending on the problem, this layer may output:

&lt;ul&gt;
&lt;li&gt; A single number&lt;/li&gt;
&lt;li&gt; A vector of probabilities&lt;/li&gt;
&lt;li&gt; A class label&lt;/li&gt;
&lt;li&gt; A multi-dimensional prediction&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Like hidden neurons, output neurons also use weights, biases, and sometimes an activation function (e.g., sigmoid or softmax).&lt;/li&gt;

&lt;li&gt;The only difference is that this layer’s output is directly interpreted as the model’s answer.&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  The 5-Step Life Cycle of a Neuron (Applies to Every Layer Except Input)
&lt;/h2&gt;

&lt;p&gt;Every neuron inside a neural network — whether in a hidden layer or the output layer — follows the exact same processing routine. Understanding this cycle is key to building intuition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. It receives inputs (activations).&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;These activations come from either the input layer or the previous hidden layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. It multiplies each input by its corresponding weight.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Weights determine how strongly the neuron should pay attention to each incoming value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. It adds a bias.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bias shifts the weighted sum, giving the neuron flexibility to activate even when inputs are small or zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. It applies an activation function.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The weighted sum plus bias (called the pre-activation, or z) goes through a function like ReLU, sigmoid, or tanh.&lt;/li&gt;
&lt;li&gt;This step introduces non-linearity — essential for learning complex patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. It outputs a new activation.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This final value (a) becomes the input to the next layer, allowing the network to stack transformations and build rich representations.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A neural network is essentially a repeated cycle of: &lt;strong&gt;input → weighted sum → bias → activation → output&lt;/strong&gt; layer after layer, until the final prediction is produced.&lt;/p&gt;

&lt;p&gt;This is a gentle introduction to neural networks — enough to understand what they are made of and how they learn. From here, you can explore topics like &lt;strong&gt;activation functions, optimizers, loss functions, and different neural architectures&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>ai</category>
      <category>python</category>
    </item>
    <item>
      <title>How Neural Networks Learn – A Simple Guide to Machine Learning &amp; Deep Learning</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Fri, 28 Nov 2025 04:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/how-a-model-really-learns-from-loss-to-learning-in-machine-learning-deep-learning-26b0</link>
      <guid>https://dev.to/nishanthan-k/how-a-model-really-learns-from-loss-to-learning-in-machine-learning-deep-learning-26b0</guid>
      <description>&lt;p&gt;Machine Learning and Deep Learning are often treated as black boxes filled with complex math and jargon. But at their core, they are built on a few simple ideas: measuring error, understanding direction, and making small improvements over time.&lt;/p&gt;

&lt;p&gt;In this article, I break down how a model &lt;em&gt;actually learns&lt;/em&gt; — from the moment it makes a mistake, to how that mistake travels backward through the network to update weights and improve future predictions. Starting from a simple equation, we’ll build up to neural networks and the complete training loop, step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Intelligence, Patterns, and Models
&lt;/h2&gt;

&lt;p&gt;Human intelligence works by building &lt;strong&gt;mental models&lt;/strong&gt; of the world.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Black clouds + strong wind → We expect rain
&lt;/li&gt;
&lt;li&gt;Sometimes this is wrong (it could be a cloud shadow)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, the brain refines these models.&lt;/p&gt;

&lt;p&gt;Machine Learning works the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input → Pattern → Output&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The system learns relationships from data, not rules written manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;em&gt;model&lt;/em&gt; is simply a mathematical way of representing this pattern.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Core Idea: Model as an Equation
&lt;/h2&gt;

&lt;p&gt;The simplest model looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = mX + b

Where:
X = input
y = output
m and b = parameters (values to be learned)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Machine Learning, this is often written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = wX + b

Here:
w = weight (importance of input)
b = bias (base value added to the output)

The entire goal of training is to find the best values of w and b so the prediction matches reality.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Loss Function — Measuring Mistakes
&lt;/h2&gt;

&lt;p&gt;Once the model makes a prediction, it needs to know: “How wrong am I?” That’s the job of the loss function.&lt;/p&gt;

&lt;h3&gt;
  
  
  A loss function:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Compares actual output and predicted output&lt;/li&gt;
&lt;li&gt;Returns a number that shows how bad the prediction was&lt;/li&gt;
&lt;li&gt;High loss → very wrong&lt;/li&gt;
&lt;li&gt;Low loss → close to correct&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This number becomes the main guiding signal for learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Gradient — Finding the Direction of Improvement
&lt;/h2&gt;

&lt;p&gt;After loss is calculated, the model asks: “In which direction should I change my parameters to reduce this error?” The gradient is that direction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intuitively:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A positive gradient means: if we increase this parameter, loss will go up&lt;/li&gt;
&lt;li&gt;A negative gradient means: if we increase this parameter, loss will go down&lt;/li&gt;
&lt;li&gt;A zero gradient means: we are at a flat point (often a minimum)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Learning Rate — Controlling the Speed of Learning
&lt;/h2&gt;

&lt;p&gt;The learning rate controls how much the parameter is allowed to change in each step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Conceptually, the update rule is:

new_weight = old_weight - (learning_rate × gradient)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If the learning rate is too large → the model jumps wildly, overshoots, and becomes unstable&lt;/li&gt;
&lt;li&gt;If the learning rate is too small → the model moves very slowly and takes forever to learn&lt;/li&gt;
&lt;li&gt;If the learning rate is reasonable → learning is smooth and stable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the learning rate is simply the step size of learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Epoch — Repeating the Learning Process
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One epoch means the model has seen the entire training dataset once.&lt;/li&gt;
&lt;li&gt;During an epoch, the model would makes predictions on all training data

&lt;ul&gt;
&lt;li&gt;Calculates the loss&lt;/li&gt;
&lt;li&gt;Updates the parameters&lt;/li&gt;
&lt;li&gt;Repeats this process for the next epoch&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;More epochs → more opportunities to learn&lt;/li&gt;

&lt;li&gt;Too many epochs → the model may start memorizing instead of generalizing (this is called overfitting)&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Batch — Dividing the Dataset
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Instead of feeding the entire dataset to the model at once, we split it into batches.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example:

Dataset size: 1000 samples
Batch size: 100
Then per epoch, we have: 1000 / 100 = 10 batches

So the model updates its parameters 10 times in one epoch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits of batching:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reduces memory usage&lt;/li&gt;
&lt;li&gt;Gives more frequent parameter updates&lt;/li&gt;
&lt;li&gt;Often leads to better and more stable learning&lt;/li&gt;
&lt;li&gt;There is no single “perfect” batch size. It depends on:

&lt;ul&gt;
&lt;li&gt;Dataset size&lt;/li&gt;
&lt;li&gt;Available hardware (CPU/GPU, RAM/VRAM)&lt;/li&gt;
&lt;li&gt;Model size and complexity&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Weights and Bias — Making Real-World Sense
&lt;/h2&gt;

&lt;p&gt;Earlier, we saw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = mX + b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In ML terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = wX + b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;w (weight) represents how important an input is&lt;/li&gt;
&lt;li&gt;b (bias) is a base value added regardless of the input&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Courier Charges
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;₹100 per kg → weight&lt;/li&gt;
&lt;li&gt;₹50 base charge → bias&lt;/li&gt;
&lt;li&gt;Even if the parcel weighs 0 kg, you still pay ₹50.&lt;/li&gt;
&lt;li&gt;Without the bias term, the model would be forced to predict ₹0 when the input is 0. Bias lets us shift the line up or down and represent real “base” behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;So bias is needed so that:&lt;/p&gt;

&lt;p&gt;The model is not forced to pass through (0, 0), and can better fit real-world data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. Neural Network — From One Equation to Many
&lt;/h2&gt;

&lt;p&gt;A single neuron performs a calculation like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = w1·x1 + w2·x2 + ... + wn·xn + b

- It takes many inputs
- Multiplies each by its own weight
- Adds them up and adds a bias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A layer is a group of neurons working in parallel on the same input.&lt;/li&gt;
&lt;li&gt;A neural network is a stack of such layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why use neural networks?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A single linear equation is limited to straight-line relationships&lt;/li&gt;
&lt;li&gt;Neural networks, combined with activation functions, can model complex, non-linear patterns&lt;/li&gt;
&lt;li&gt;This is what enables them to handle images, text, audio, and other complex data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Activation Function — The Source of Non-Linearity
&lt;/h2&gt;

&lt;p&gt;After a neuron computes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;z = w·x + b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We apply an activation function to get the final output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = activation(z)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Activation functions:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introduce non-linearity&lt;/li&gt;
&lt;li&gt;Allow the network to learn complex patterns and decision boundaries&lt;/li&gt;
&lt;li&gt;Enable tasks such as:

&lt;ul&gt;
&lt;li&gt;Image classification&lt;/li&gt;
&lt;li&gt;Object detection&lt;/li&gt;
&lt;li&gt;Natural language processing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Without activation functions:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every neuron is just a linear transformation&lt;/li&gt;
&lt;li&gt;Stacking multiple linear layers still gives a linear function&lt;/li&gt;
&lt;li&gt;The network would be no more powerful than a single linear model&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In short:&lt;/p&gt;

&lt;p&gt;Activation functions are what make neural networks more powerful than simple linear models.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  11. Forward Propagation — Data Moving Through the Network
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Forward propagation is the process of passing data through the network to produce an output.&lt;/li&gt;
&lt;li&gt;Steps:

&lt;ul&gt;
&lt;li&gt;Input data is fed into the input layer&lt;/li&gt;
&lt;li&gt;Each neuron in the next layer:&lt;/li&gt;
&lt;li&gt;Multiplies inputs by weights&lt;/li&gt;
&lt;li&gt;Adds bias&lt;/li&gt;
&lt;li&gt;Applies activation function&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The output of one layer becomes the input to the next layer&lt;/li&gt;

&lt;li&gt;This continues until the final output layer produces the prediction&lt;/li&gt;

&lt;li&gt;Flow: &lt;code&gt;Input → Hidden layer 1 → Hidden layer 2 → ... → Output layer&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Important:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Forward propagation only computes the outputs.&lt;/li&gt;
&lt;li&gt;No learning or weight updates happen in this step.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Backward Propagation — Learning From Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;After forward propagation, we:

&lt;ul&gt;
&lt;li&gt;Compare the prediction with the actual target&lt;/li&gt;
&lt;li&gt;Compute the loss (error)&lt;/li&gt;
&lt;li&gt;Now the model needs to adjust its weights to reduce this loss.&lt;/li&gt;
&lt;li&gt;This is where backward propagation (backprop) comes in.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Backpropagation:

&lt;ul&gt;
&lt;li&gt;Sends the error signal backward from the output layer toward the input layer&lt;/li&gt;
&lt;li&gt;Computes, for each weight and bias, how much it contributed to the error (its gradient)&lt;/li&gt;
&lt;li&gt;Once gradients are known, we update parameters using gradient descent:

&lt;ul&gt;
&lt;li&gt;new_weight = old_weight - (learning_rate × gradient)&lt;/li&gt;
&lt;li&gt;new_bias   = old_bias   - (learning_rate × gradient)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;So:

&lt;ul&gt;
&lt;li&gt;Backpropagation calculates gradients;&lt;/li&gt;
&lt;li&gt;Gradient descent + learning rate perform the actual update.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Backpropagation is the core of how the network learns.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  13. The Complete Training Cycle
&lt;/h2&gt;

&lt;p&gt;Putting everything together, a full training loop for a neural network looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Input data is passed into the network&lt;/li&gt;
&lt;li&gt;Forward propagation computes the prediction&lt;/li&gt;
&lt;li&gt;Loss function measures how wrong the prediction&lt;/li&gt;
&lt;li&gt;Backward propagation computes gradients for all weights and biases&lt;/li&gt;
&lt;li&gt;Gradient descent updates the parameters using the learning rate&lt;/li&gt;
&lt;li&gt;This is repeated for:

&lt;ul&gt;
&lt;li&gt;Every batch&lt;/li&gt;
&lt;li&gt;Across multiple epochs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;In one line:&lt;/p&gt;

&lt;p&gt;Input → Forward Propagation → Loss → Backpropagation → Update Weights → Repeat&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;With each cycle:

&lt;ul&gt;
&lt;li&gt;The model becomes a bit less wrong&lt;/li&gt;
&lt;li&gt;The loss usually goes down&lt;/li&gt;
&lt;li&gt;The predictions improve&lt;/li&gt;
&lt;li&gt;This is the entire training process in a nutshell.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  14. Inference — Using the Trained Model
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Once the model is trained:

&lt;ul&gt;
&lt;li&gt;We freeze the learned weights and biases&lt;/li&gt;
&lt;li&gt;We give it new input data it has never seen&lt;/li&gt;
&lt;li&gt;It runs only forward propagation to produce predictions&lt;/li&gt;
&lt;li&gt;No backpropagation or weight updates happen during inference.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;This is the phase where the model is actually used in production:

&lt;ul&gt;
&lt;li&gt;Recommending products&lt;/li&gt;
&lt;li&gt;Classifying images&lt;/li&gt;
&lt;li&gt;Translating text&lt;/li&gt;
&lt;li&gt;Detecting fraud, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;From a simple line like y = wX + b to deep neural networks, everything in Machine Learning and Deep Learning is built on a few core ideas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Representing patterns with models
- Measuring error with a loss function
- Using gradients to find a better direction
- Controlling change with learning rate
- Repeating the process over batches and epochs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The concepts are simple.&lt;br&gt;
The power comes from scale, data, and iteration.&lt;/p&gt;

</description>
      <category>deeplearning</category>
      <category>machinelearning</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Understanding Java Constructors: Types, Execution, and Differences from Methods</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Sun, 05 Oct 2025 18:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/understanding-java-constructors-types-execution-and-differences-from-methods-35cm</link>
      <guid>https://dev.to/nishanthan-k/understanding-java-constructors-types-execution-and-differences-from-methods-35cm</guid>
      <description>&lt;h2&gt;
  
  
  Understanding Constructors in Java
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;constructor&lt;/strong&gt; in Java is similar to a method but serves a specific purpose: initializing objects. This article provides a deep dive into constructors, their execution, types, and how they differ from regular methods.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Constructor?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same name as the class&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No return type&lt;/strong&gt; (not even &lt;code&gt;void&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary role&lt;/strong&gt;: Assign or initialize values to class variables
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic invocation&lt;/strong&gt;: Called automatically when an object is created; cannot be called like a regular method
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Execution of Constructors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Compile Time
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Java compiler converts a constructor into a special method called &lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt; in the &lt;code&gt;.class&lt;/code&gt; file.
&lt;/li&gt;
&lt;li&gt;JVM maintains two special methods for initialization:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt;&lt;/strong&gt; → Contains instance constructors; not callable directly by user code
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;clinit&amp;gt;&lt;/code&gt;&lt;/strong&gt; → Contains static field initializations and static blocks; executed once when the class is loaded
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;If no constructor is defined by the developer, Java automatically creates a &lt;strong&gt;default constructor&lt;/strong&gt; and stores it in &lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Runtime
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In the JVM, a constructor is represented as a special method (&lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt;) and stored &lt;strong&gt;once&lt;/strong&gt; in the &lt;strong&gt;Method Area&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Every time an object is created, the JVM executes this stored constructor; no new constructor code is created per object.
&lt;/li&gt;
&lt;li&gt;Constructors are primarily for initializing object state; heavy business logic should generally be avoided.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Types of Constructors
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Default Constructor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added automatically by Java when no constructor is defined.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No-Argument Constructor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly written by the developer without parameters.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Parameterized Constructor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Written with parameters to initialize object fields flexibly.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Copy Constructor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not built into Java by default, but can be created by the developer to copy values from another object.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Default constructor (auto-generated by Java)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// No-arg constructor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B created"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Parameterized constructor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Copy constructor&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;D&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="no"&gt;D&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;D&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Constructor vs Method in Java
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Constructor&lt;/th&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Must be same as the class&lt;/td&gt;
&lt;td&gt;Can have any legal identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Return Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (not even &lt;code&gt;void&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Must declare a return type (or &lt;code&gt;void&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Invocation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Called automatically with &lt;code&gt;new&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Must be explicitly invoked (&lt;code&gt;obj.method()&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Initialize object state (fresh object setup)&lt;/td&gt;
&lt;td&gt;Define behavior of an already created object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bytecode Representation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stored as &lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt; in &lt;code&gt;.class&lt;/code&gt; file&lt;/td&gt;
&lt;td&gt;Stored with its given name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inheritance Behavior&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not inherited, but calls parent constructor (&lt;code&gt;super()&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Inherited and can be overridden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overloading&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can be overloaded&lt;/td&gt;
&lt;td&gt;Can be overloaded and overridden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Special Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can call another constructor (&lt;code&gt;this(...)&lt;/code&gt; or &lt;code&gt;super(...)&lt;/code&gt;) as first statement&lt;/td&gt;
&lt;td&gt;No such restriction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constructor&lt;/strong&gt; → Object birth + initialization, JVM-reserved mechanism (&lt;code&gt;&amp;lt;init&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method&lt;/strong&gt; → Object behavior, regular callable unit of code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Constructors are foundational to object-oriented programming in Java, ensuring objects are properly initialized while maintaining a clean separation of initialization logic from business logic.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>java</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Brushing Up on React Hooks</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Mon, 28 Jul 2025 03:33:01 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/brushing-up-on-react-hooks-30la</link>
      <guid>https://dev.to/nishanthan-k/brushing-up-on-react-hooks-30la</guid>
      <description>&lt;h2&gt;
  
  
  React Hooks Summary
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;useState&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;memoizedState&lt;/code&gt; holds the current state value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;baseState&lt;/code&gt; is the initial state value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dispatch&lt;/code&gt; is the setter function to update state.&lt;/li&gt;
&lt;li&gt;Triggers re-render &lt;strong&gt;after&lt;/strong&gt; the current call stack is empty.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. &lt;code&gt;useEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Allows you to perform side effects (API calls, subscriptions).&lt;/li&gt;
&lt;li&gt;Cleanup is handled by returning a function inside the effect.&lt;/li&gt;
&lt;li&gt;Cleanup runs:

&lt;ul&gt;
&lt;li&gt;Before the component unmounts.&lt;/li&gt;
&lt;li&gt;Before the effect runs again (if dependencies change).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. &lt;code&gt;useMemo&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Caches the &lt;strong&gt;result&lt;/strong&gt; of a computation.&lt;/li&gt;
&lt;li&gt;Prevents recalculating expensive operations unless dependencies change.&lt;/li&gt;
&lt;li&gt;Useful for:

&lt;ul&gt;
&lt;li&gt;Filtering, sorting, parsing large data.&lt;/li&gt;
&lt;li&gt;Memoizing derived data for performance.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Can also be used to wrap child components to prevent unnecessary re-renders (in conjunction with &lt;code&gt;React.memo&lt;/code&gt;).&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. &lt;code&gt;React.memo&lt;/code&gt; vs &lt;code&gt;useMemo&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;React.memo&lt;/code&gt;: Prevents re-rendering a &lt;strong&gt;component&lt;/strong&gt; unless props change.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useMemo&lt;/code&gt;: Prevents re-running a &lt;strong&gt;function&lt;/strong&gt; unless dependencies change.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. &lt;code&gt;useCallback&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Memoizes the &lt;strong&gt;function definition&lt;/strong&gt; itself.&lt;/li&gt;
&lt;li&gt;Useful when passing callbacks to memoized child components.&lt;/li&gt;
&lt;li&gt;Prevents unnecessary re-renders due to new function references on each render.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. &lt;code&gt;useRef&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Mutable ref object that persists for the full lifetime of the component.&lt;/li&gt;
&lt;li&gt;Doesn't trigger re-renders.&lt;/li&gt;
&lt;li&gt;Can be used to access DOM nodes or hold mutable variables.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. &lt;code&gt;useReducer&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Alternative to &lt;code&gt;useState&lt;/code&gt; for complex state logic.&lt;/li&gt;
&lt;li&gt;Accepts a reducer function and an initial state.&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;[state, dispatch]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Best for managing state transitions or multiple sub-values.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. &lt;code&gt;useLayoutEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Like &lt;code&gt;useEffect&lt;/code&gt;, but runs &lt;strong&gt;after DOM mutation&lt;/strong&gt;, &lt;strong&gt;before paint&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use for DOM measurements, layout adjustments.&lt;/li&gt;
&lt;li&gt;Main use case: e.g., sidebar collapse before layout shift.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. &lt;code&gt;useImperativeHandle&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Customizes the instance value exposed by &lt;code&gt;ref&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Used with &lt;code&gt;forwardRef&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Allows parent to trigger child functions imperatively.&lt;/li&gt;
&lt;li&gt;Use case: trigger child API call on parent submit button click.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  10. &lt;code&gt;useDebugValue&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Used for debugging custom hooks in React DevTools.&lt;/li&gt;
&lt;li&gt;Display custom hook values to help debugging.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How Java Stores Data in Memory: Writing Efficient Code with Primitives and Non-Primitives</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Fri, 16 May 2025 03:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/how-java-stores-data-in-memory-writing-efficient-code-with-primitives-and-non-primitives-42kg</link>
      <guid>https://dev.to/nishanthan-k/how-java-stores-data-in-memory-writing-efficient-code-with-primitives-and-non-primitives-42kg</guid>
      <description>&lt;h2&gt;
  
  
  How Java Stores Data in Memory — Primitives vs Non-Primitives
&lt;/h2&gt;

&lt;p&gt;Java is a &lt;strong&gt;statically typed language&lt;/strong&gt;, which means every variable’s type must be known at compile time. This allows the JVM (Java Virtual Machine) to allocate memory efficiently and enforce type safety during execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primitive Types in Java
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Primitive types&lt;/strong&gt; are the building blocks of data in Java. They have &lt;strong&gt;fixed memory sizes&lt;/strong&gt; and are stored in the &lt;strong&gt;stack&lt;/strong&gt;. The value of a primitive can change, but its size does not.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;Smallest integer (–128 to 127)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;Short integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;Default integer type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;Large-range integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;Single-precision float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;double&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;Double-precision float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;Unicode character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 bit*&lt;/td&gt;
&lt;td&gt;True or False (handled as 1 byte internally)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: Although &lt;code&gt;boolean&lt;/code&gt; is conceptually 1 bit, it is usually stored as **1 byte&lt;/em&gt;* in memory due to alignment and practical implementation constraints.*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Non-Primitive (Reference) Types
&lt;/h3&gt;

&lt;p&gt;Non-primitives, also called &lt;strong&gt;reference types&lt;/strong&gt;, are more complex and stored in the &lt;strong&gt;heap&lt;/strong&gt;, while their references (pointers) are kept in the &lt;strong&gt;stack&lt;/strong&gt;. These types include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sequence of characters (immutable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Arrays&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ordered collection of elements (of any type, including primitives)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Custom-defined objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Interface&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Abstract types that other classes implement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Enum&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A fixed set of constants (internally class-like)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Wrapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object representations of primitive types (e.g., &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Double&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Collections&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data structures like &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, etc. (part of Java Collections Framework)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How Java Stores Data in Memory
&lt;/h3&gt;

&lt;p&gt;Java abstracts memory management with &lt;strong&gt;automatic garbage collection&lt;/strong&gt;, but here’s how it works under the hood:&lt;/p&gt;

&lt;h4&gt;
  
  
  Stack Memory
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Stores &lt;strong&gt;method calls&lt;/strong&gt;, &lt;strong&gt;local variables&lt;/strong&gt;, and &lt;strong&gt;primitive types&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast access&lt;/strong&gt; due to LIFO structure.&lt;/li&gt;
&lt;li&gt;Memory is freed automatically once a method exits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Heap Memory
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Stores &lt;strong&gt;objects&lt;/strong&gt; and &lt;strong&gt;non-primitive values&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Accessed via references stored in the stack.&lt;/li&gt;
&lt;li&gt;Managed by &lt;strong&gt;Garbage Collector&lt;/strong&gt; (GC).&lt;/li&gt;
&lt;li&gt;Larger and &lt;strong&gt;slower&lt;/strong&gt; than stack but can store dynamic and complex structures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Primitive Types Are Accessed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Stored &lt;strong&gt;directly&lt;/strong&gt; in the stack.&lt;/li&gt;
&lt;li&gt;Access and modification are &lt;strong&gt;fast and straightforward&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Since they are fixed-size, the JVM knows exactly how much memory to allocate and retrieve.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Non-Primitives Are Accessed
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;When a non-primitive is created, the &lt;strong&gt;reference (memory address)&lt;/strong&gt; is stored in the stack.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;actual object&lt;/strong&gt; is stored in the heap.&lt;/li&gt;
&lt;li&gt;Accessing the object involves &lt;strong&gt;following the reference&lt;/strong&gt; from stack to heap.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; (stack) → points to → &lt;code&gt;"John"&lt;/code&gt; (heap)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we change &lt;code&gt;name = "Jack";&lt;/code&gt;, now &lt;code&gt;name&lt;/code&gt; points to a new &lt;code&gt;"Jack"&lt;/code&gt; in heap (because &lt;code&gt;String&lt;/code&gt; is immutable).&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Alignment and JVM Optimization
&lt;/h3&gt;

&lt;p&gt;Java is designed with the principle: &lt;strong&gt;“Write once, run anywhere”&lt;/strong&gt;, which means JVM must work on both &lt;strong&gt;32-bit and 64-bit CPUs&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  JVM Alignment Strategy:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Regardless of declared type, JVM aligns memory into &lt;strong&gt;4-byte or 8-byte chunks&lt;/strong&gt; depending on CPU.&lt;/li&gt;
&lt;li&gt;Operations on smaller types (&lt;code&gt;byte&lt;/code&gt;, &lt;code&gt;short&lt;/code&gt;) are &lt;strong&gt;converted to &lt;code&gt;int&lt;/code&gt;&lt;/strong&gt; internally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Why is that?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;byte&lt;/code&gt; takes 25% of a 4-byte block; &lt;code&gt;short&lt;/code&gt; takes 50%.&lt;/li&gt;
&lt;li&gt;CPU needs &lt;strong&gt;extra steps&lt;/strong&gt; to calculate offsets and align the memory block.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;int&lt;/code&gt; consumes the entire 4-byte block, making &lt;strong&gt;storage and retrieval faster&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JVM promotes &lt;code&gt;byte&lt;/code&gt; and &lt;code&gt;short&lt;/code&gt; to &lt;code&gt;int&lt;/code&gt; during calculations and requires &lt;strong&gt;explicit casting&lt;/strong&gt; to store results back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Misconception: Using &lt;code&gt;byte&lt;/code&gt;/&lt;code&gt;short&lt;/code&gt; Saves Memory?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Why &lt;code&gt;byte&lt;/code&gt; and &lt;code&gt;short&lt;/code&gt; are &lt;em&gt;less efficient&lt;/em&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JVM treats them as &lt;code&gt;int&lt;/code&gt; internally.&lt;/li&gt;
&lt;li&gt;Adds &lt;strong&gt;extra overhead&lt;/strong&gt; during arithmetic and access.&lt;/li&gt;
&lt;li&gt;Introduces &lt;strong&gt;hidden conversions&lt;/strong&gt; (widening and narrowing).&lt;/li&gt;
&lt;li&gt;Slower due to memory misalignment and CPU inefficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For performance and alignment, &lt;strong&gt;use &lt;code&gt;int&lt;/code&gt; as default&lt;/strong&gt; for integers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What About Wrapper Classes?
&lt;/h3&gt;

&lt;p&gt;Wrapper classes (&lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Double&lt;/code&gt;, etc.) are &lt;strong&gt;object versions&lt;/strong&gt; of primitive types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stored in heap like any object.&lt;/li&gt;
&lt;li&gt;Used in Collections (e.g., &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt;, not &lt;code&gt;List&amp;lt;int&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Include utility methods like &lt;code&gt;parseInt&lt;/code&gt;, &lt;code&gt;compareTo&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Auto-boxing and unboxing happen automatically:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// auto-boxing&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// unboxing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boxing adds &lt;strong&gt;memory and performance overhead&lt;/strong&gt;, so avoid unnecessary boxing in critical code paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primitive types&lt;/strong&gt; are fixed-size and fast, stored in stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-primitives&lt;/strong&gt; are stored in heap with reference in stack.&lt;/li&gt;
&lt;li&gt;JVM uses &lt;strong&gt;int as the baseline&lt;/strong&gt; for all smaller integral operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid using &lt;code&gt;byte&lt;/code&gt; and &lt;code&gt;short&lt;/code&gt; for optimization&lt;/strong&gt;, it backfires due to hidden processing.&lt;/li&gt;
&lt;li&gt;Wrapper classes add object overhead; &lt;strong&gt;prefer primitives&lt;/strong&gt; for performance-critical paths.&lt;/li&gt;
&lt;li&gt;Java abstracts memory handling, but &lt;strong&gt;understanding this helps you write more efficient code&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>data</category>
      <category>programming</category>
    </item>
    <item>
      <title>Understanding Angular Rendering, Re-rendering, and Change Detection for Optimal Performance</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Mon, 07 Apr 2025 04:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/understanding-angular-rendering-re-rendering-and-change-detection-for-optimal-performance-2dle</link>
      <guid>https://dev.to/nishanthan-k/understanding-angular-rendering-re-rendering-and-change-detection-for-optimal-performance-2dle</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you’re transitioning from React to Angular or starting with Angular as first step, understanding Angular’s rendering process, change detection mechanism, and re-rendering strategy is crucial for writing efficient and high-performance applications. Unlike React, where the virtual DOM helps optimize the re-render process, Angular’s change detection mechanism checks every component to ensure the UI reflects the latest data. This article will break down the concepts of rendering, change detection, and performance optimization in Angular, answering the questions you might have along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Angular Rendering and Re-rendering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How Does Angular Render and Re-render Components?
&lt;/h3&gt;

&lt;p&gt;Angular, unlike React, uses a real DOM and checks for changes during change detection. Let's break down the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initial Rendering:&lt;/strong&gt; When a component is created for the first time, Angular processes the component’s template and binds the data from the component to the template.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Change Detection:&lt;/strong&gt; Once the component is initialized, Angular listens for changes in the data. When any data-bound property changes, Angular triggers the change detection process, checking the whole component tree from the root.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Re-rendering:&lt;/strong&gt; When data in a component changes, Angular goes through the change detection cycle again. Unlike React, which uses a virtual DOM, Angular re-renders the DOM directly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This brings up an interesting question: &lt;strong&gt;If change detection checks the whole component tree, does Angular re-render everything even if only a small part of the data changes?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Do Angular Re-renders Everything or Just the Changed Part?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Angular does indeed go through all bindings in the component, even if only a single property changes. This is less efficient compared to React’s virtual DOM diffing mechanism, where only the changed elements are re-rendered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;However, Angular uses optimizations such as OnPush change detection strategy and TrackBy in *ngFor to reduce unnecessary checks. Let's dive deeper into these strategies.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exploring Angular's Change Detection Mechanism
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How Does Change Detection Work in Angular?
&lt;/h3&gt;

&lt;p&gt;Change detection in Angular follows a process where Angular traverses the component tree and checks each binding to see if it has changed. If any change is detected, Angular updates the DOM.&lt;/p&gt;

&lt;p&gt;The default strategy is CheckAlways, which checks all components in the component tree. But Angular allows you to optimize this using OnPush.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is OnPush?
&lt;/h3&gt;

&lt;p&gt;When using OnPush change detection, Angular only checks a component for changes when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One of its Input properties changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An event is triggered (e.g., button click).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An observable emits a new value.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can significantly improve performance in large applications by avoiding unnecessary checks on components that haven’t changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-my-component',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: './my-component.component.html',
})
export class MyComponent {
  @Input() data: any;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using OnPush, you restrict the component to be checked only when a relevant change occurs, rather than checking it on every cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Does Angular Check All Components for Changes?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You might wonder, &lt;strong&gt;Why does Angular check the entire component tree? Can it just check the component where the change happened?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Angular’s default change detection works by traversing the whole component tree to check for any data changes. This design ensures that all bindings are up to date, but can become inefficient, especially in large applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unlike React’s virtual DOM, Angular doesn’t maintain a previous DOM snapshot, and so it doesn't have an efficient diffing mechanism that would allow it to detect changes at a granular level.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Challenge with Functions in Templates
&lt;/h3&gt;

&lt;p&gt;Angular has a two-way binding mechanism, which helps with reactivity. But one performance pitfall is calling functions directly in templates. Functions in templates are re-evaluated on every change detection cycle, which can hurt performance if not used properly.&lt;/p&gt;

&lt;p&gt;For example, calling a function in a template like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ computeValue() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Could cause the function to run repeatedly, making it inefficient. To avoid this, use getters or Signals (in Angular 16.2+) to track state more efficiently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get computedValue(): number {
  return this.data * 10;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, the value is calculated once, and Angular can optimize re-renders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing Angular for Better Performance
&lt;/h2&gt;

&lt;p&gt;To address performance concerns, let’s talk about strategies to optimize rendering and change detection in Angular.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;strong&gt;OnPush&lt;/strong&gt; Change Detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As mentioned earlier, the OnPush strategy significantly reduces unnecessary re-renders. It tells Angular to check the component only when its inputs or observables change, or when an event is triggered.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;strong&gt;trackBy&lt;/strong&gt; with *ngFor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When using *ngFor, Angular creates new DOM elements for every item in the list. If the list is large, this can become inefficient. You can optimize the rendering of lists by using trackBy to track which items have changed, rather than recreating the entire DOM for the list every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div *ngFor="let item of items; trackBy: trackById"&amp;gt;
  {{ item.name }}
&amp;lt;/div&amp;gt;

trackById(index: number, item: any): number {
  return item.id;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Avoid Functions in Templates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of calling functions directly in the template, use getters or Signals (in Angular 16.2+) to keep state changes efficient and avoid recomputing values on every change detection cycle.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Signals (Angular 16.2+):&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Signals in Angular provide a more efficient way to manage state and trigger updates. With signals, Angular tracks the state and updates the DOM only when the value of the signal changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;isA = signal(true);
isB = signal(false);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use &lt;strong&gt;ngOnChanges and Input Setters&lt;/strong&gt;
For efficient handling of input changes, Angular provides Input Setters and ngOnChanges. Instead of checking changes manually, use these lifecycle hooks to optimize reactivity.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Input() set data(value: any) {
  this._data = value;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use this instead of ngOnChanges to efficiently handle changes in input properties.&lt;/p&gt;

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

&lt;p&gt;Understanding Angular’s rendering, re-rendering, and change detection mechanisms is key to building efficient applications. By using techniques like OnPush change detection, trackBy in *ngFor, avoiding functions in templates, and leveraging Signals (in Angular 16.2+), you can optimize your Angular applications for better performance.&lt;/p&gt;

&lt;p&gt;Remember, while Angular doesn’t use a virtual DOM like React, it offers a powerful change detection system that you can fine-tune for optimal performance. Implement these strategies and take control of your app’s reactivity—leading to faster, smoother, and more efficient user experiences.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How MongoDB’s ObjectID and B-Tree Search Make Your Queries Super Fast</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Wed, 19 Feb 2025 03:30:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/how-mongodbs-objectid-and-b-tree-search-make-your-queries-super-fast-3hhn</link>
      <guid>https://dev.to/nishanthan-k/how-mongodbs-objectid-and-b-tree-search-make-your-queries-super-fast-3hhn</guid>
      <description>&lt;p&gt;MongoDB uses a unique identifier, called &lt;strong&gt;ObjectId&lt;/strong&gt;, for each document stored in its database. An ObjectId is a 12-byte identifier that is generated in a specific format to ensure it’s unique across distributed systems. &lt;/p&gt;

&lt;p&gt;In this article, we will break down the structure of MongoDB's ObjectId, how it is generated, and how MongoDB uses a binary tree-like structure for indexing and searching. We will also discuss how this structure helps MongoDB perform searches efficiently, even with millions of entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of MongoDB's ObjectId
&lt;/h2&gt;

&lt;p&gt;MongoDB’s &lt;strong&gt;ObjectId&lt;/strong&gt; is a &lt;strong&gt;12-byte&lt;/strong&gt; identifier, and its structure is designed to ensure uniqueness while keeping it compact. The 12 bytes are divided into four main parts:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Timestamp (4 bytes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The first 4 bytes represent the timestamp when the ObjectId was generated. &lt;/li&gt;
&lt;li&gt;This timestamp is recorded in &lt;strong&gt;seconds&lt;/strong&gt; since the Unix epoch (January 1, 1970).&lt;/li&gt;
&lt;li&gt;This ensures that ObjectIds are roughly ordered by creation time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Machine Id (3 bytes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The next 3 bytes represent a unique identifier for the machine where the ObjectId was generated.&lt;/li&gt;
&lt;li&gt;Typically, it’s derived from the machine's IP address or a hash of the machine's network interfaces.&lt;/li&gt;
&lt;li&gt;This will be &lt;strong&gt;constant for its lifetime&lt;/strong&gt; untill the &lt;strong&gt;hostname and other system details&lt;/strong&gt; got changed&lt;/li&gt;
&lt;li&gt;This ensures that even if two MongoDB instances are running on different machines, they can generate unique ObjectIds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Process Id (2 bytes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The following 2 bytes represent the process ID of the MongoDB server process. &lt;/li&gt;
&lt;li&gt;This helps to distinguish ObjectIds generated by different processes running on the same machine.&lt;/li&gt;
&lt;li&gt;This is only constant for that run and it will change when the server was restarted / on re-run.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Counter (3 bytes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The last 3 bytes represent an &lt;strong&gt;incrementing counter&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;The counter starts at a random value. If &lt;strong&gt;multiple documents / objectIds&lt;/strong&gt; are generated at the same timestamp (same second), the counter ensures each generated &lt;strong&gt;ObjectId is unique by incrementing&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If only one &lt;strong&gt;Document / ObjectId&lt;/strong&gt; is generated per second, the counter will reset to another random value for the next second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key point:&lt;/strong&gt; This counter ensures uniqueness when multiple ObjectId values are generated in the same second by the same machine and process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example of an ObjectId:
&lt;/h3&gt;

&lt;p&gt;507f191e810c19729de860ea&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first 4 bytes: &lt;code&gt;507f191e&lt;/code&gt; represent the timestamp.&lt;/li&gt;
&lt;li&gt;The next 3 bytes: &lt;code&gt;81&lt;/code&gt; represent the machine ID.&lt;/li&gt;
&lt;li&gt;The next 2 bytes: &lt;code&gt;0c&lt;/code&gt; represent the process ID.&lt;/li&gt;
&lt;li&gt;The last 3 bytes: &lt;code&gt;19729de&lt;/code&gt; represent the incrementing counter.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  MongoDB Index Structure and Page Layout:
&lt;/h3&gt;

&lt;p&gt;MongoDB uses a &lt;strong&gt;B-tree-like&lt;/strong&gt; index structure, not an real tree we are using in data structures but with certain modifications for optimization. Here's a breakdown:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Root Node:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;root node&lt;/strong&gt; of the index tree stores &lt;strong&gt;keys&lt;/strong&gt; (usually indexed fields like &lt;code&gt;ObjectId&lt;/code&gt;, or other indexed fields).&lt;/li&gt;
&lt;li&gt;This root node acts as the starting point for the search process, &lt;strong&gt;guiding MongoDB towards the right child node.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Contains &lt;strong&gt;sorted keys&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Points to &lt;strong&gt;child nodes&lt;/strong&gt; which continue the search deeper into the tree.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. &lt;strong&gt;Child Pages:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Child nodes (or child pages) store &lt;strong&gt;sorted keys&lt;/strong&gt; and pointers to their &lt;strong&gt;leaf nodes&lt;/strong&gt; or further child nodes.&lt;/li&gt;
&lt;li&gt;These nodes are like intermediates, helping narrow down the range of values that need to be searched.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Contains &lt;strong&gt;sorted key-value pairs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Contains pointers to the next level (further child pages or leaf pages).&lt;/li&gt;
&lt;li&gt;May be created or split as the index grows.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Leaf Pages:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;leaf pages&lt;/strong&gt; are the actual locations where &lt;strong&gt;document references&lt;/strong&gt; (pointers to documents) are stored.&lt;/li&gt;
&lt;li&gt;Each entry in the leaf page contains a &lt;strong&gt;key&lt;/strong&gt; (indexed field value) and a &lt;strong&gt;pointer&lt;/strong&gt; to the actual document (i.e., location in the data store).&lt;/li&gt;
&lt;li&gt;These pages are where the final results are stored, which MongoDB returns in a query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Contains the &lt;strong&gt;actual document references&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Sorted by the indexed field for fast lookups.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Page Structure:
&lt;/h3&gt;

&lt;p&gt;In MongoDB, &lt;strong&gt;index pages&lt;/strong&gt; are typically designed to be &lt;strong&gt;4 KB&lt;/strong&gt; in size. If the page contains entries like &lt;code&gt;ObjectId&lt;/code&gt; (a 12-byte identifier), each page can store around &lt;strong&gt;317 entries&lt;/strong&gt;. This size may vary slightly based on the size of indexed fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt; are fetched from the disk into memory during searches, ensuring that queries are handled efficiently.&lt;/li&gt;
&lt;li&gt;MongoDB uses a &lt;strong&gt;binary search&lt;/strong&gt; within a page to locate the exact entry, which ensures faster retrieval of documents.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  How MongoDB Manages Page Growth:
&lt;/h3&gt;

&lt;p&gt;As MongoDB adds more entries to an index, it needs to &lt;strong&gt;split nodes&lt;/strong&gt; to ensure that the index remains balanced.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a &lt;strong&gt;page&lt;/strong&gt; reaches its capacity, MongoDB &lt;strong&gt;splits&lt;/strong&gt; the page into two and &lt;strong&gt;promotes the middle key&lt;/strong&gt; to the parent node.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;middle key&lt;/strong&gt; is the key that divides the entries in half and is used to maintain a balanced index.&lt;/li&gt;
&lt;li&gt;As the index continues to grow, this process of splitting and promoting ensures the &lt;strong&gt;B-tree remains balanced&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balancing the tree&lt;/strong&gt; through splits and promotions ensures that &lt;strong&gt;search operations remain efficient&lt;/strong&gt; and that the index is optimal for query performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example of How the Index Tree Works:
&lt;/h3&gt;

&lt;p&gt;Consider an index on the &lt;code&gt;ObjectId&lt;/code&gt; field in MongoDB:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Root Node&lt;/strong&gt;: Contains keys pointing to child nodes. For example, if you have a collection of documents with &lt;code&gt;ObjectId&lt;/code&gt;, the root node will store keys like &lt;code&gt;ObjectId:123&lt;/code&gt;, &lt;code&gt;ObjectId:124&lt;/code&gt;, etc., with pointers to child nodes that contain more detailed keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Child Pages&lt;/strong&gt;: These child nodes will store ranges of &lt;code&gt;ObjectId&lt;/code&gt;s and pointers to further nodes or leaf nodes, helping narrow down the search.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leaf Pages&lt;/strong&gt;: Finally, the leaf pages contain the &lt;strong&gt;actual document pointers&lt;/strong&gt; for specific &lt;code&gt;ObjectId&lt;/code&gt;s. For example, a leaf page might contain a key like &lt;code&gt;ObjectId:123&lt;/code&gt; and a pointer to the exact location of the document in the storage.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a query is executed, MongoDB will traverse this tree structure by following the &lt;strong&gt;key pointers&lt;/strong&gt; from the root node, through child nodes, and ultimately to the leaf nodes where it finds the &lt;strong&gt;document references&lt;/strong&gt;. This ensures efficient searching, even with large datasets.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Takeaways:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB uses a &lt;strong&gt;modified B-tree&lt;/strong&gt; index structure for fast lookups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt; are crucial for holding index entries and documents. Pages are typically 4 KB in size and contain &lt;strong&gt;sorted entries&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaf pages&lt;/strong&gt; contain the actual document references and are where the search ultimately lands.&lt;/li&gt;
&lt;li&gt;As the tree grows, &lt;strong&gt;node splits&lt;/strong&gt; and &lt;strong&gt;middle key promotions&lt;/strong&gt; ensure that the index remains balanced and efficient for query processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: From Scratch to 17 Entries
&lt;/h2&gt;

&lt;p&gt;Let’s consider the process of adding entries to a MongoDB index and how the keys move up in the tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Tree Construction:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insert 1, 2, 3&lt;/strong&gt;:
Initially, we add three entries, and they all fit in the root node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[1, 2, 3]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insert 4&lt;/strong&gt;:
Adding the fourth entry causes the root to split. The middle key (&lt;code&gt;2&lt;/code&gt;) gets promoted to a new root.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Root: [2]&lt;br&gt;
Left Child: [1]&lt;br&gt;
Right Child: [3, 4]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insert 5, 6, 7&lt;/strong&gt;:
The right child now overflows, so the middle key (&lt;code&gt;6&lt;/code&gt;) moves up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Root: [2, 6]&lt;br&gt;
Left Child: [1]&lt;br&gt;
Middle Child: [3, 4, 5]&lt;br&gt;
Right Child: [7]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insert 8, 9, 10&lt;/strong&gt;:
The right child overflows again, so the middle key (&lt;code&gt;9&lt;/code&gt;) moves up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Root: [2, 6, 9]&lt;br&gt;
Left Child: [1]&lt;br&gt;
Middle Left Child: [3, 4, 5]&lt;br&gt;
Middle Right Child: [7, 8]&lt;br&gt;
Right Child: [10]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insert 11, 12, 13, 14, 15, 16, 17&lt;/strong&gt;:
We continue inserting entries, and they cause further splits, with the middle keys getting promoted up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Root: [2, 6, 9, 13]&lt;br&gt;&lt;br&gt;
Left Child: [1]&lt;br&gt;&lt;br&gt;
Middle Left Child: [3, 4, 5]&lt;br&gt;&lt;br&gt;
Middle Child: [7, 8]&lt;br&gt;&lt;br&gt;
Right Child: [10, 11]&lt;br&gt;&lt;br&gt;
Final Child: [12, 14, 15, 16, 17]  &lt;/p&gt;

&lt;h3&gt;
  
  
  Final tree strucutre
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         [6, 9, 13]
                      /    |    |    \
         [1, 2, 3, 4, 5]   [7, 8]  [10, 11]  [12, 14, 15, 16, 17]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Simplified MongoDB Search Process
&lt;/h2&gt;

&lt;p&gt;Here’s a simplified summary of how MongoDB searches for documents using the index:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start with the Index&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB first looks at the &lt;strong&gt;index&lt;/strong&gt; (similar to a table of contents in a book) to figure out where to find documents.&lt;/li&gt;
&lt;li&gt;The index is stored in a &lt;strong&gt;B-tree&lt;/strong&gt; structure, which helps MongoDB quickly find the right spot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Navigate the Tree&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;root node&lt;/strong&gt; of the tree holds pointers to the next pages (child nodes).&lt;/li&gt;
&lt;li&gt;The tree is &lt;strong&gt;split into pages&lt;/strong&gt;, each containing &lt;strong&gt;key-value pairs&lt;/strong&gt;. These keys are the indexed fields (like ObjectId, or any other field you're indexing).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Find the Relevant Range&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a query is made, MongoDB starts at the &lt;strong&gt;root node&lt;/strong&gt; and uses &lt;strong&gt;binary search&lt;/strong&gt; to find the right range of keys.&lt;/li&gt;
&lt;li&gt;It keeps following the pointers to the next pages until it narrows down to the correct range of keys for the search.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Determine the Page to Search&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As MongoDB navigates the tree, it looks for the &lt;strong&gt;page number&lt;/strong&gt; (stored in the index) that contains the matching &lt;strong&gt;_id&lt;/strong&gt; or document key range.&lt;/li&gt;
&lt;li&gt;Once it finds the correct page, it jumps to that page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Search on the Page&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;page&lt;/strong&gt; contains a &lt;strong&gt;binary search&lt;/strong&gt; of documents stored in it. MongoDB uses the pointers in the page to go straight to the document's &lt;strong&gt;storage location&lt;/strong&gt; (like the exact spot where the document is stored on disk).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fetch the Document&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, MongoDB uses the &lt;strong&gt;storage location&lt;/strong&gt; found in the index (the &lt;strong&gt;position pointer&lt;/strong&gt;) to go directly to the document on the disk and fetch it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  In short:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB first uses the &lt;strong&gt;index&lt;/strong&gt; (a tree structure) to find the right range of documents.&lt;/li&gt;
&lt;li&gt;It uses &lt;strong&gt;binary search&lt;/strong&gt; to find the correct page.&lt;/li&gt;
&lt;li&gt;Then, it jumps to that page and finds the document by looking up the position pointer, directly fetching it from the disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process ensures that MongoDB can &lt;strong&gt;quickly&lt;/strong&gt; locate and fetch documents even if the database grows large.&lt;/p&gt;


&lt;h2&gt;
  
  
  Real strucuture with 64 level split
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                           ┌────────────────── Root Node ───────────────────┐
                           │ Keys: [512, 1024, 1536]                         │
                           │ Child Pointers: [P1, P2, P3, P4]                │
                           └────────────────────────────────────────────────┘
                                         ↓ Choose correct child based on _id

 ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │                         Internal Nodes (Level 2)                                                              │
 └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
 │ P1 → Keys: [128, 256, 384]  │ P2 → Keys: [640, 768, 896]  │ P3 → Keys: [1152, 1280, 1408]  │ P4 → Keys: [1664, 1792, 1920] │
 │ Child Pointers: [P5-P8]     │ Child Pointers: [P9-P12]    │ Child Pointers: [P13-P16]     │ Child Pointers: [P17-P20]    │

                                         ↓ Choose correct child based on _id

 ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │                         Internal Nodes (Level 3)                                                              │
 └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
 │ P5 → Keys: [32, 64, 96]  │ P6 → Keys: [160, 192, 224]  │ P7 → Keys: [288, 320, 352]  │ P8 → Keys: [416, 448, 480]  │
 │ P9 → Keys: [544, 576, 608]  │ P10 → Keys: [672, 704, 736]  │ P11 → Keys: [800, 832, 864]  │ P12 → Keys: [928, 960, 992]  │
 │ P13 → Keys: [1056, 1088, 1120]  │ P14 → Keys: [1184, 1216, 1248]  │ P15 → Keys: [1312, 1344, 1376]  │ P16 → Keys: [1440, 1472, 1504]  │
 │ P17 → Keys: [1568, 1600, 1632]  │ P18 → Keys: [1728, 1760, 1792]  │ P19 → Keys: [1856, 1888, 1920]  │ P20 → Keys: [1984, 2000]  │

                                         ↓ Choose correct child based on _id

 ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │                         Leaf Nodes (Level 4) - Actual Document Pointers                                       │
 └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
 │ P21 → Keys: [1-64] (D1-D64)  │ P22 → Keys: [65-128] (D65-D128)  │ P23 → Keys: [129-192] (D129-D192)  │ P24 → Keys: [193-256] (D193-D256)  │
 │ P25 → Keys: [257-320] (D257-D320)  │ P26 → Keys: [321-384] (D321-D384)  │ P27 → Keys: [385-448] (D385-D448)  │ P28 → Keys: [449-512] (D449-D512)  │
 │ P29 → Keys: [513-576] (D513-D576)  │ P30 → Keys: [577-640] (D577-D640)  │ P31 → Keys: [641-704] (D641-D704)  │ P32 → Keys: [705-768] (D705-D768)  │
 │ P33 → Keys: [769-832] (D769-D832)  │ P34 → Keys: [833-896] (D833-D896)  │ P35 → Keys: [897-960] (D897-D960)  │ P36 → Keys: [961-1024] (D961-D1024)  │
 │ P37 → Keys: [1025-1088] (D1025-D1088)  │ P38 → Keys: [1089-1152] (D1089-D1152)  │ P39 → Keys: [1153-1216] (D1153-D1216)  │ P40 → Keys: [1217-1280] (D1217-D1280)  │
 │ P41 → Keys: [1281-1344] (D1281-D1344)  │ P42 → Keys: [1345-1408] (D1345-D1408)  │ P43 → Keys: [1409-1472] (D1409-D1472)  │ P44 → Keys: [1473-1536] (D1473-D1536)  │
 │ P45 → Keys: [1537-1600] (D1537-D1600)  │ P46 → Keys: [1601-1664] (D1601-D1664)  │ P47 → Keys: [1665-1728] (D1665-D1728)  │ P48 → Keys: [1729-1792] (D1729-D1792)  │
 │ P49 → Keys: [1793-1856] (D1793-D1856)  │ P50 → Keys: [1857-1920] (D1857-D1920)  │ P51 → Keys: [1921-1984] (D1921-D1984)  │ P52 → Keys: [1985-2000] (D1985-D2000)  │


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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Search flow for _id 1754
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Root Node: &lt;code&gt;_id = 1754&lt;/code&gt; falls in range [1536, 2000], follow &lt;code&gt;P4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internal Node (L2): &lt;code&gt;_id = 1754&lt;/code&gt; falls in range [1664, 1920], follow &lt;code&gt;P18&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internal Node (L3): &lt;code&gt;_id = 1754&lt;/code&gt; falls in range [1728, 1792], follow &lt;code&gt;P48&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Leaf Node (L4): &lt;code&gt;_id = 1754&lt;/code&gt; is found, get &lt;code&gt;Document Pointer D1754&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieve document from storage&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Searching for an ID in MongoDB (Example with 3.6 Million Entries)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Let’s say we have a collection of &lt;strong&gt;3.6 million entries&lt;/strong&gt; and you need to find an entry with a specific &lt;strong&gt;ObjectId&lt;/strong&gt;. Here’s how MongoDB would perform the search.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At each level, you have 64 choices (64 child pointers).&lt;br&gt;
So for large values (like the 3.7 millionth record), this structure is efficient.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import math

total_entries = 3600000

branching_factor = 64

num_searches = math.ceil(math.log(total_entries, branching_factor))
print(num_searches)

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For searching the 3.6 millionth entry, it would take approximately &lt;strong&gt;4 searches (or 4 levels of traversal in the tree)&lt;/strong&gt;. This is because the B-tree structure narrows down the search space significantly at each level. &lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;MongoDB’s &lt;strong&gt;ObjectId&lt;/strong&gt; provides a compact, efficient way to uniquely identify documents, and its indexing system uses a &lt;strong&gt;B-tree-like structure&lt;/strong&gt; to allow for fast searches. As documents are inserted, keys are promoted to parent nodes, ensuring that MongoDB maintains a balanced and efficient index structure. When searching for a specific &lt;strong&gt;ObjectId&lt;/strong&gt;, MongoDB can quickly narrow down the search space using &lt;strong&gt;binary search&lt;/strong&gt; on the root and child pages, resulting in fast lookups even for large collections.&lt;/p&gt;

&lt;p&gt;By combining &lt;strong&gt;timestamp-based generation&lt;/strong&gt; for ObjectIds and a &lt;strong&gt;binary search-based indexing&lt;/strong&gt; structure, MongoDB is able to offer high performance for both data storage and retrieval.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>optimization</category>
      <category>performance</category>
    </item>
    <item>
      <title>Understanding the Java Execution Process: From Code to Execution</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Thu, 30 Jan 2025 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/understanding-the-java-execution-process-from-code-to-execution-1n89</link>
      <guid>https://dev.to/nishanthan-k/understanding-the-java-execution-process-from-code-to-execution-1n89</guid>
      <description>&lt;p&gt;Java is widely known for its platform independence and efficient execution. This article will walk you through the entire Java execution process, from writing human-readable code to running it across different platforms. We’ll cover the roles of JDK, JVM, and JRE, as well as the steps involved in compiling and executing Java programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Key Java Components
&lt;/h2&gt;

&lt;p&gt;Before diving into the execution process, it’s essential to understand the three core components in Java:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JDK (Java Development Kit)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The JDK is a full-fledged software development kit that allows you to write, compile, and execute Java programs.&lt;/li&gt;
&lt;li&gt;It includes the JVM (Java Virtual Machine) and JRE (Java Runtime Environment), as well as essential tools for development, such as the compiler (&lt;code&gt;javac&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;JDK is used by developers to write and compile code, which is later executed by the JVM.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;JVM (Java Virtual Machine)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The JVM is the engine that runs Java bytecode. It makes Java platform-independent by abstracting the underlying hardware and operating system.&lt;/li&gt;
&lt;li&gt;Java programs are compiled into bytecode, which the JVM interprets and executes, allowing the same Java program to run on any machine with a JVM.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;JRE (Java Runtime Environment)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The JRE provides the necessary libraries and resources to run Java programs, including the JVM.&lt;/li&gt;
&lt;li&gt;It contains the core classes like String and Array, which your Java program may depend on.&lt;/li&gt;
&lt;li&gt;The JRE doesn’t include development tools like the compiler, making it suitable for running Java applications but not for development.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. The Java Execution Process
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Write the Code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You start by writing Java code, which is typically saved in &lt;code&gt;.java&lt;/code&gt; files. This code is human-readable and follows Java syntax.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Compile the Code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the code is ready, the &lt;code&gt;javac&lt;/code&gt; compiler is used to convert the human-readable &lt;code&gt;.java&lt;/code&gt; code into bytecode (stored in &lt;code&gt;.class&lt;/code&gt; files).&lt;/li&gt;
&lt;li&gt;Bytecode is a binary format, which is the same for all operating systems. This bytecode can then be executed on any platform that has a JVM, ensuring platform independence.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Execute the Bytecode with JVM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;3.1 Loading the Bytecode&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;When you attempt to execute the Java program, the JVM loads the bytecode (i.e., the &lt;code&gt;.class&lt;/code&gt; file) into memory.&lt;/li&gt;
&lt;li&gt;The ClassLoader is responsible for finding and loading the class based on the class name provided by the user.&lt;/li&gt;
&lt;li&gt;If the class cannot be found, a &lt;code&gt;ClassNotFoundException&lt;/code&gt; is thrown.&lt;/li&gt;
&lt;li&gt;If the class is found, the JVM loads it into memory. Static methods, variables, and data from the class are stored in the Method Area, a special part of the JVM memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3.2 Executing the Bytecode&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Once the class is loaded, the JVM looks for the &lt;code&gt;main()&lt;/code&gt; method (the entry point of the program) to begin execution.&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;main()&lt;/code&gt; method is found, the execution process starts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Execution Mechanism
&lt;/h2&gt;

&lt;p&gt;There are two main approaches the JVM uses to execute bytecode: Interpreter and Just-In-Time (JIT) Compiler.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interpreter (Slower)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the interpreter approach, the JVM reads and executes the bytecode line by line.&lt;/li&gt;
&lt;li&gt;Every time a method is invoked, the JVM re-interprets the bytecode, which can be slow since the same method may be re-executed multiple times.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;JIT (Just-In-Time) Compiler (Faster)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The JIT Compiler compiles bytecode into native machine code, which is specific to the platform and machine on which the program is running.&lt;/li&gt;
&lt;li&gt;It optimizes performance by using a technique called Hot Spots.&lt;/li&gt;
&lt;li&gt;Hot Spots are frequently used parts of the code (like methods). These are identified by the JIT compiler, and instead of interpreting them each time, the JIT compiles them into native machine code.&lt;/li&gt;
&lt;li&gt;The compiled machine code is cached, so when the same method is needed again, the JVM can use the cached machine code, resulting in faster execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hot Spots&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Hot Spot technique ensures that the JVM only compiles the frequently used methods, not the entire class. This results in significant performance improvements for long-running applications.&lt;/li&gt;
&lt;li&gt;The JVM uses machine code for execution of these hot spots instead of interpreting the bytecode every time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. JVM Memory Areas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The JVM allocates memory for different parts of the program during execution. Some key areas include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method Area:&lt;/strong&gt; Holds information about classes, methods, and static variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heap Area:&lt;/strong&gt; Stores objects created during runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack Area:&lt;/strong&gt; Stores local variables and method calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program Counter (PC):&lt;/strong&gt; A register that points to the current instruction being executed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Summary of the Execution Flow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write Code:&lt;/strong&gt; Java code is written in .java files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compile:&lt;/strong&gt; The code is compiled into bytecode (.class files) by the javac compiler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Bytecode:&lt;/strong&gt; The JVM, using the ClassLoader, loads the bytecode into memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find Entry Point:&lt;/strong&gt; The JVM looks for the main() method to start execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution via Interpreter or JIT:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interpreter:&lt;/strong&gt; Executes bytecode line by line (slower).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JIT Compiler:&lt;/strong&gt; Compiles hot spots into native machine code for faster execution (faster).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The combination of bytecode, JVM, and the JIT compiler ensures that Java is both platform-independent and efficient. The execution flow uses the Interpreter for simplicity and the JIT Compiler for performance optimization, allowing Java programs to run efficiently across various platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The JVM plays a key role in ensuring that Java code is portable and efficient. It first loads the bytecode, then executes it through either an interpreter (slower) or a JIT compiler (faster).&lt;/li&gt;
&lt;li&gt;By using JIT and hot spots, the JVM optimizes performance while maintaining the ability to run the same bytecode on different platforms.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>jvm</category>
      <category>jre</category>
      <category>jdk</category>
    </item>
    <item>
      <title>Mastering Node.js Routing: A Complete Guide with Internal Workings Explained</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Fri, 20 Dec 2024 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/mastering-nodejs-routing-a-complete-guide-with-internal-workings-explained-4gkg</link>
      <guid>https://dev.to/nishanthan-k/mastering-nodejs-routing-a-complete-guide-with-internal-workings-explained-4gkg</guid>
      <description>&lt;h2&gt;
  
  
  Understanding Routes in Node.js: A Beginner's Guide
&lt;/h2&gt;

&lt;p&gt;Routing is a fundamental concept in Node.js, especially when building web applications. It refers to defining endpoints in your application that respond to client requests. Each route is associated with a specific HTTP method (like &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt;) and a path. Let’s dive into how routing works in Node.js and explore its internal mechanics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Routes in Node.js
&lt;/h2&gt;

&lt;p&gt;To understand routing, let’s start with a simple example using the popular &lt;code&gt;Express.js&lt;/code&gt; framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const app = express();

// Define a GET route
app.get('/', (req, res) =&amp;gt; {
  res.send('Welcome to the Home Page!');
});

// Define a POST route
app.post('/submit', (req, res) =&amp;gt; {
  res.send('Form Submitted Successfully!');
});

// Start the server
app.listen(3000, () =&amp;gt; {
  console.log('Server is running on http://localhost:3000');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Here’s what happens:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Route Definition:&lt;/strong&gt; Each app.method(path, handler) defines a route where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method specifies the HTTP method (GET, POST, etc.).&lt;/li&gt;
&lt;li&gt;path is the URL endpoint (e.g., /submit).&lt;/li&gt;
&lt;li&gt;handler is the function executed when the route is accessed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Middleware Layer:&lt;/strong&gt; Express uses middleware to process incoming requests before reaching the route handler. Middleware can modify the request and response objects.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Internal Working of Routes in Node.js
&lt;/h2&gt;

&lt;p&gt;When a request hits the server, here’s what happens under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Matching:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Node.js, with Express, maintains a routing table—a collection of defined routes.&lt;/li&gt;
&lt;li&gt;When a request arrives, Express parses the request's HTTP method and URL.&lt;/li&gt;
&lt;li&gt;It compares these against the routing table to find a match.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Middleware Execution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before reaching the handler, middleware functions are executed in the order they are defined.&lt;/li&gt;
&lt;li&gt;Middleware can handle logging, authentication, or parsing JSON data from the request body.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Route Handler Execution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once a matching route is found, its handler function is executed.&lt;/li&gt;
&lt;li&gt;The handler has access to:

&lt;ul&gt;
&lt;li&gt;req (request object): Contains data like query parameters, headers, and body.&lt;/li&gt;
&lt;li&gt;res (response object): Used to send back a response to the client.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Response Dispatch:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The res object sends a response (like HTML, JSON, or plain text) back to the client.&lt;/li&gt;
&lt;li&gt;Once the response is sent, the connection is closed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Routing Techniques
&lt;/h2&gt;

&lt;p&gt;Express supports advanced routing capabilities, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Route Parameters:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/user/:id', (req, res) =&amp;gt; {
  res.send(`User ID: ${req.params.id}`);
});

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

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Query Parameters:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/search', (req, res) =&amp;gt; {
  res.send(`Search Query: ${req.query.q}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chained Routes:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.route('/product')
  .get((req, res) =&amp;gt; res.send('Get Product'))
  .post((req, res) =&amp;gt; res.send('Add Product'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Use tools like morgan for logging requests.&lt;/li&gt;
&lt;li&gt;Monitor performance with middleware like compression to optimize response sizes.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Routing in Node.js, especially with Express, provides a powerful way to define and manage application endpoints. Internally, it uses a systematic approach to match requests, execute middleware, and respond to clients. Understanding these mechanics can help you build more efficient and maintainable applications.&lt;/p&gt;

&lt;p&gt;Save this article for future reference and let us know your thoughts in the comments below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>mern</category>
    </item>
    <item>
      <title>Understanding Middlewares in Express.js and Their Internal Working</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Wed, 18 Dec 2024 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/understanding-middlewares-in-expressjs-and-their-internal-working-4ddc</link>
      <guid>https://dev.to/nishanthan-k/understanding-middlewares-in-expressjs-and-their-internal-working-4ddc</guid>
      <description>&lt;p&gt;In Express.js, middlewares are special functions that have access to the request (req), response (res), and a third parameter called next. Unlike regular route handlers, middlewares play a critical role in controlling the flow of the application by executing external logic before the main business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do Middlewares Work?
&lt;/h2&gt;

&lt;p&gt;When an HTTP request hits an Express.js server, it flows through a series of middleware functions. Each middleware can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modify the request object (e.g., attach data, validate tokens).&lt;/li&gt;
&lt;li&gt;Modify the response object (e.g., send a response early).&lt;/li&gt;
&lt;li&gt;Pass control to the next middleware in the stack using the next() function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a middleware doesn't call next(), the request-response cycle terminates there, and no further logic (including route handlers) will execute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do We Use Middlewares?
&lt;/h2&gt;

&lt;p&gt;Middlewares are perfect for scenarios where we need to add reusable logic before processing a request. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; Checking if the user is logged in (e.g., validating - JWT tokens).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization:&lt;/strong&gt; Ensuring users have the necessary permissions to perform certain actions (e.g., admins can delete content).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Validation:&lt;/strong&gt; Verifying if all required inputs are provided.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and Monitoring:&lt;/strong&gt; Recording details of incoming requests for analytics or debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling:&lt;/strong&gt; Catching errors globally to send meaningful responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Defining and Using Middlewares
&lt;/h2&gt;

&lt;p&gt;A middleware function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((req, res, next) =&amp;gt; {
    // Logic here
    next(); // Pass control to the next middleware or route handler
});

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;req (Request):&lt;/strong&gt; Contains information about the incoming HTTP request (e.g., headers, body, params).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;res (Response):&lt;/strong&gt; Used to send data back to the client.
next(): A function that passes control to the next middleware in line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Middleware Flow: Order of Execution
&lt;/h2&gt;

&lt;p&gt;Middleware order matters! Express executes middlewares sequentially in the order they are defined.&lt;/p&gt;

&lt;p&gt;If a middleware is defined after a route, it will not affect that route. This is why middlewares must be declared before routes in your app.js.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Middleware to check if the user has admin privileges
app.use((req, res, next) =&amp;gt; {
    console.log("Checking for admin role...");

    // Simulating a user object attached earlier in the pipeline
    if (req.user &amp;amp;&amp;amp; req.user.role === "admin") {
        console.log("Access granted");
        next(); // Move to the next middleware or route handler
    } else {
        console.log("Access denied");
        res.status(403).send("You do not have access to this resource.");
    }
});

// Routes
app.get("/admin/dashboard", (req, res) =&amp;gt; {
    res.send("Welcome to the admin dashboard!");
});

app.get("/public", (req, res) =&amp;gt; {
    res.send("This is a public page.");
});

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Internal Execution Flow
&lt;/h2&gt;

&lt;p&gt;Here’s what happens step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incoming Request:&lt;/strong&gt; A request hits the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middleware Execution:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The middleware checks the req.user.role.&lt;/li&gt;
&lt;li&gt;If role is "admin", it calls next() to pass control to the next middleware or route.&lt;/li&gt;
&lt;li&gt;If not, the middleware terminates the request by sending a 403 Forbidden response.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Route Handler:&lt;/strong&gt; If next() is called, the relevant route handler (e.g., /admin/dashboard) executes.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example Flow:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A user with role: "admin" requests /admin/dashboard.

&lt;ul&gt;
&lt;li&gt;Middleware logs "Access granted" and calls next().&lt;/li&gt;
&lt;li&gt;Route handler sends "Welcome to the admin dashboard!".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A user with role: "user" requests /admin/dashboard.

&lt;ul&gt;
&lt;li&gt;Middleware logs "Access denied" and sends "You do not have access to this resource".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Middlewares are like gatekeepers—they decide what happens before the main route logic runs.&lt;/li&gt;
&lt;li&gt;Use next() to ensure the flow continues to the next middleware or route.&lt;/li&gt;
&lt;li&gt;Always define critical middlewares before the routes to ensure they apply.&lt;/li&gt;
&lt;li&gt;If you don’t call next() or send a response, the request will hang (timed out).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>react</category>
    </item>
    <item>
      <title>Understanding .env Files and the dotenv Library in Node.js</title>
      <dc:creator>Nishanthan K</dc:creator>
      <pubDate>Mon, 16 Dec 2024 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishanthan-k/understanding-env-files-and-the-dotenv-library-in-nodejs-2opm</link>
      <guid>https://dev.to/nishanthan-k/understanding-env-files-and-the-dotenv-library-in-nodejs-2opm</guid>
      <description>&lt;p&gt;Environment configuration is a critical part of any application development process. This article explores the purpose of &lt;code&gt;.env&lt;/code&gt; files, how the &lt;code&gt;dotenv&lt;/code&gt; library works, and why Node.js cannot directly access &lt;code&gt;.env&lt;/code&gt; files. We'll also delve into the internal architecture of the &lt;code&gt;dotenv&lt;/code&gt; library to understand its functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a &lt;code&gt;.env&lt;/code&gt; File?
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;.env&lt;/code&gt; file is a simple &lt;strong&gt;text file&lt;/strong&gt; used to store environment-specific configurations, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;li&gt;Port numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file follows a &lt;strong&gt;key-value pair format&lt;/strong&gt;, making it easy to define and manage variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=3000
DB_USER=devuser
DB_PASS=devpassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Use Cases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Local Development:&lt;/strong&gt; Deby velopers use .env files to avoid hardcoding sensitive information in the codebase.&lt;br&gt;
&lt;strong&gt;Testing Environments:&lt;/strong&gt; Testing environments can have their own .env file with configurations that mimic production setups.&lt;/p&gt;
&lt;h2&gt;
  
  
  Note:
&lt;/h2&gt;

&lt;p&gt;.env files are typically excluded from production deployments due to security concerns. Sensitive data should be managed through environment variables provided by the hosting infrastructure or secret management tools.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Node.js Can't Access .env Directly
&lt;/h2&gt;

&lt;p&gt;Node.js assumes that environment variables are managed externally by the system or runtime tools. For instance, these variables can be set using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Operating system commands (export VAR_NAME=value on Unix/Linux)&lt;/li&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Cloud hosting platforms (e.g., AWS, Heroku, Vercel)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;.env files, on the other hand, are a developer convention designed for convenience during development. Node.js does not include native functionality to read .env files. This is where the dotenv library comes into play.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the dotenv Library?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;dotenv is a lightweight Node.js library that:&lt;/li&gt;
&lt;li&gt;Reads the .env file from the project root.&lt;/li&gt;
&lt;li&gt;Parses its content into key-value pairs.&lt;/li&gt;
&lt;li&gt;Injects these values into the global process.env object, making them accessible throughout your application.&lt;/li&gt;
&lt;li&gt;By doing so, dotenv acts as a bridge between .env files and Node.js applications, simplifying the management of environment-specific settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Internal Workflow of dotenv
&lt;/h2&gt;

&lt;p&gt;Here's how the dotenv library works under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File Reading:&lt;/strong&gt; The library uses Node.js's fs module to read the .env file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing:&lt;/strong&gt; The content of the file is parsed line by line. Key-value pairs are extracted using regular expressions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; The library skips blank lines and lines beginning with # (comments).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Injection:&lt;/strong&gt; The parsed key-value pairs are added to process.env. If a variable already exists in process.env, the library typically avoids overwriting it (configurable).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a simplified view of the dotenv workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fs = require('fs');
const path = require('path');

function parseEnvFile(filePath) {
    const content = fs.readFileSync(filePath, 'utf-8');
    const lines = content.split('\n');

    lines.forEach(line =&amp;gt; {
        if (line.trim() &amp;amp;&amp;amp; !line.startsWith('#')) {
            const [key, value] = line.split('=');
            process.env[key.trim()] = value.trim();
        }
    });
}

parseEnvFile(path.resolve(__dirname, '.env'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Development and Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a .env file in the root of your project:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=3000
DB_USER=devuser
DB_PASS=devpassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install dotenv:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Load the .env file in your application:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('dotenv').config();

console.log(process.env.PORT); // Outputs: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Production
&lt;/h3&gt;

&lt;p&gt;For production environments, it's best to use infrastructure-level tools to manage environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Platforms:&lt;/strong&gt; AWS Systems Manager, Google Secret Manager, Azure Key Vault&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containerized Environments:&lt;/strong&gt; Docker --env flag or Kubernetes Secrets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD Pipelines:&lt;/strong&gt; Define environment variables in the build/deployment pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By avoiding .env files in production, you ensure that sensitive information stays secure.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Keep .env Files Out of Version Control: Add .env to your .gitignore file to avoid accidental commits.&lt;/li&gt;
&lt;li&gt;Use Environment-Specific Files: Maintain separate .env files for development (.env.development), testing (.env.testing), and staging (.env.staging).&lt;/li&gt;
&lt;li&gt;Validate Variables: Use libraries like joi or dotenv-safe to ensure required environment variables are defined.&lt;/li&gt;
&lt;li&gt;Limit Access: Only include variables that are absolutely necessary for the environment.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Environment configuration is a cornerstone of modern application development. By leveraging .env files and the dotenv library, developers can simplify local development and testing workflows. However, for production, it's essential to adopt secure practices for managing sensitive information. With a solid understanding of these tools and techniques, you'll ensure your applications are both secure and maintainable.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
