Finding the Smallest Number in JavaScript

Read
Finding the Smallest Number in JavaScript
📸

A Story About How Engineers Think, Not Just How They Code#

Written for Self-Taught Developers, Career Switchers, and Curious Recruiters#

Most people think programming is about knowing syntax.

It is not.

Programming is about how you think when the syntax is not there.

This article explains a very small JavaScript problem in a very intentional way. Not to show cleverness, but to show clarity of thought.

If you are a beginner, this will slow things down for you. If you are a recruiter or senior developer, this will show you how I reason.

Why I Am Writing This#

I come from a non-technical background. Before web development, my academic training was in the arts.

That background taught me how to break ideas into structure, observe patterns, and explain complex things simply.

Ironically, those skills are exactly what programming demands.

This blog is written the way I wish programming was explained to me when I started. It is a demonstration of method, not just knowledge.

The Problem Looks Small, But It Is Not#

The question is simple:

Find the smallest number in an array.

Most tutorials solve this in one line. That approach hides the most important part: the thinking process.

Inside this small problem live concepts used in real production systems: validating inputs, making assumptions explicit, comparison logic, iteration, and the separation of logic and UI.

Understanding this deeply once makes many other problems easier later. This is the power of foundational thinking.

Step 1: Understanding the Question Like a Human#

Before writing code, I stop and ask: What is really being asked?

From a computer perspective: input is an array, output is a number.

From a human perspective:

  • Do I actually have a list?

  • Are the values all comparable numbers?

  • What should happen if the input is empty?

  • What should happen if the input is nonsense?

Good code does not start with typing. It starts with good questions.

Step 2: Translating the Problem Into Real Life#

I always remove code first. Imagine this:

You recently moved to a new city. You are tracking daily expenses to control spending. Your notes look like this:

[120, 80, 200, 50, 150]

Each number represents money spent in a day. Someone asks: "Which day had the lowest expense?"

You do not think in terms of loops or algorithms. You scan, you compare, you remember. That natural, efficient reasoning is what our code should mirror.

Step 3: The Thinking Pattern the Brain Uses#

When observed closely, the brain follows a simple, optimized pattern:

  1. Assume the first value you see is the smallest (or assume a very large number).

  2. Look at the next value.

  3. If it's smaller, update your assumption.

  4. Repeat until the list ends.

Programming is not about inventing new logic. It is about making this invisible, intuitive process explicit and unambiguous for a machine.

Step 4: Validation Comes Before Logic#

Before comparing anything, we must check if comparison even makes sense. This is where robust software begins.

Case 1: The input is not a list.

"150"

Real-world meaning: You have one receipt, not a list. There is nothing to compare.
Code response: Return an error signal (e.g., false).

Case 2: The list is empty.

[]

Real-world meaning: No data was recorded.
Code response: Return null.

Case 3: The list contains non-numbers.

[100, "coffee", 50]

Real-world meaning: Numbers and text cannot be compared meaningfully.
Code response: Return an error signal.

This validation step is where many beginner solutions quietly break. An engineer thinks about these edges first.

Step 5: The Core Logic in Slow Motion#

Let's walk through our expense list with human reasoning:

[120, 80, 200, 50, 150]

  • Assume smallest: Start with a very large mental placeholder (Infinity).

  • See 120: 120 is smaller than Infinity. New smallest is 120.

  • See 80: 80 is smaller than 120. New smallest is 80.

  • See 200: 200 is larger than 80. Ignore. Smallest is still 80.

  • See 50: 50 is smaller than 80. New smallest is 50.

  • See 150: 150 is larger than 50. Ignore.

Final result: 50.

Notice: we track only one value. We never look back. This is efficient, linear thinking, and it directly informs our algorithm.

Step 6: Translating Thought Into JavaScript#

Now we mirror our reasoning in code. No UI, no framework. Just pure logic.

24 lines
function findSmallestNumber(arr) {
  // Validation Layer
  if (!Array.isArray(arr)) {
    return false;
  }
  if (arr.length === 0) {
    return null;
  }
  for (let value of arr) {
    if (typeof value !== "number" || !isFinite(value)) {
      return false;
    }
  }

  // Core Logic Layer
  let smallest = Infinity;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < smallest) {
      smallest = arr[i];
    }
  }
  return smallest;
}

Step 7: Why This Code Is Intentionally Boring#

Every line has a direct correspondence to a step in our thought process:

  • Array.isArray check -> "Do we have a list?"

  • length check -> "Is there data?"

  • Validation loop -> "Is all data comparable?"

  • let smallest = Infinity -> "Assume a very large number."

  • for loop -> "Compare each item."

  • return smallest -> "State the conclusion."

There is no clever trick here. That is the point. Readable, predictable code is maintainable code.

Step 8: Why Infinity Is the Correct Assumption#

In real life, if you want to find the shortest person in a room, you might start by looking at the first person. But in code, starting with Infinity is like imagining a person taller than anyone who could possibly walk in. The first real number you see will always be smaller, cleanly initializing our logic. It's a guaranteed, foolproof starting point.

Step 9: Separating Logic From UI#

In real applications, logic is reused. If we mix it with buttons and inputs:

  • Testing becomes difficult.

  • Bugs are harder to isolate.

  • Changing the UI risks breaking the logic.

Our findSmallestNumber function knows nothing about the DOM, React, or Tailwind. It simply takes an array and returns a result. This separation of concerns is a hallmark of mature software design.

Step 10: Turning Logic Into a Usable Interface#

Now we build something visible. The user enters numbers, clicks a button, and gets a result. The core logic remains untouched, proving its reusability.

Step 11: React + Tailwind Implementation#

71 lines
import { useState } from "react";

// The pure logic function remains unchanged
function findSmallestNumber(arr) {
  if (!Array.isArray(arr)) return false;
  if (arr.length === 0) return null;
  for (let value of arr) {
    if (typeof value !== "number" || !isFinite(value)) {
      return false;
    }
  }
  let smallest = Infinity;
  for (let num of arr) {
    if (num < smallest) {
      smallest = num;
    }
  }
  return smallest;
}

// UI Component that CONSUMES the logic
export default function FindSmallestNumberUI() {
  const [input, setInput] = useState("");
  const [result, setResult] = useState("");

  function handleFind() {
    // Convert UI input to the array our logic expects
    const arr = input
      .split(",")
      .map(v => Number(v.trim()));

    const output = findSmallestNumber(arr);

    // Map logic results to user-friendly messages
    if (output === false) {
      setResult("Invalid input. Please enter numbers separated by commas (e.g., 10, 20, 5).");
    } else if (output === null) {
      setResult("No values provided.");
    } else {
      setResult(`The smallest number is ${output}.`);
    }
  }

  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-100">
      <div className="bg-white p-6 rounded shadow w-full max-w-md">
        <h1 className="text-xl font-semibold mb-4">
          Find the Smallest Number
        </h1>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          placeholder="e.g., 10, 20, 5"
          className="w-full border px-3 py-2 rounded mb-4"
        />
        <button
          onClick={handleFind}
          className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 transition"
        >
          Find Smallest
        </button>
        {result && (
          <p className="mt-4 p-3 bg-gray-50 rounded text-gray-800">
            {result}
          </p>
        )}
      </div>
    </div>
  );
}

What This Exercise Actually Demonstrates#

This article was never about finding a minimum value. It was a case study in my approach to problem-solving:

  1. Clarify First: I dissect the question before writing a single character.

  2. Reason from First Principles: I translate the problem into a real-world analog.

  3. Validate Assumptions: I explicitly handle edge cases before implementing "happy path" logic.

  4. Separate Concerns: I isolate pure logic from presentation.

  5. Prioritize Communication: I write code for the next person who will read it.

These are transferable skills across any stack or framework.

A Note for Recruiters and Senior Developers#

This is the thinking pattern I bring to unfamiliar problems. I value:

  • Clarity over cleverness.

  • Robustness over speed.

  • Maintainability over shortcuts.

I am not just looking for a solution; I am designing a system, even for a problem that fits in one line. This mindset scales from a simple function to a complex application.

Closing Thought#

My background in the arts taught me to slow down, deconstruct, and find the underlying narrative. Programming, it turns out, is not about speaking to computers. It is about structuring human thought so clearly that a computer can execute it.

If this article made sense to you, then you already understand more than syntax. You understand how engineers think. And that is the hardest, most valuable part to learn.

Back to Articles

Rahul Verma

Full Stack Developer passionate about building modern web applications. Sharing insights on React, Next.js, and web development.

Learn more about me

Enjoyed this article?

Check out more articles on similar topics in the blog section.

Explore More Articles