Black Box Solutions

Creating software solutions one box at a time.

So what is a “black box” in the world of programming? The “black box” concept describes functionality that takes input and delivers a predictable output. What happens inside the box is left to the programmer to code, but the user who uses the black box is unaware of the internal workings. All the user knows is the input and has an expectation of the output. We can relate this to everyday activities such as eating at a restaurant. We review a menu of options which is the input to the kitchen, and we expect the deliverable to be what we ordered from the menu. We don’t care to know all the steps to create our meal; we just want to know that we will get our hot and delicious five-star meal๐Ÿ˜‹. We can also think of applications as sort of a black box. An example could be using your favorite internet browser. You don’t care about how it gets data; you just know that when you type in the search box, results will display.

Switching back to programming, the idea of creating a black box is so that we can start developing reusable/testable functions. When combined with other testable functions, an application that is robust and easy to maintain starts to emerge.

To demonstrate the benefits of a black box, I will create an example using Typescript and create a simple “add” function. We are using Typescript because it is a strongly typed language that will allow us to not worry about making sure the input variables “x” and “y” are of another type.

Let’s begin by following the instructions below. The assumption here is you have already installed the latest version of Node.js.

Step One: Open a Command Prompt or PowerShell in Windows Operating System and create a new directory in a location you want to initiate the new application. Give it a meaningful name like “black-box-calculator”:

mkdir black-box-calculator

Step Two: Navigate in into the new directory with the command below:

cd black-box-calculator

Step Three: Initiate a new application with the npm command:

npm init -y

Step Four: Install Typescript as a dev dependency:

npm install --save-dev typescript

Step Five: Use npx to initiate a Typescript configuration

npx tsc --init

Step Six: Use npm to install “jest” which is a testing library we will be using. We are also going to need to install types for Typesscript:

npm install --save-dev jest @types/jest ts-jest

Step Seven: Update package.json

  • Add => "scripts": { "test" : "jest" }
  • Remove => “main” : “index.js”

Step Eight: Create a jest.config.js at the root level.

Step Nine: Make a new directory called “src” where we will put our source files into.

mkdir src

Step Ten: Create calculator.test.ts file in the “src” directory and place the contents below into the file.

JavaScript
import { add, subtract, multiply, divide } from "./calculator";

test("adds 4 + 2 to equal 6", () => {
  expect(add(4, 2)).toBe(6);
});

test("subtract 4 - 2 to equal 2", () => {
    expect(subtract(4, 2)).toBe(2);
});

test("multiply 4 * 2 to equal 8", () => {   
    expect(multiply(4, 2)).toBe(8);
});

test("divide 4 / 2 to equal 2", () => {
    expect(divide(4, 2)).toBe(2);
});

test("divide 4 / 0 to equal Error", () => {    
    expect(() => divide(4, 0)).toThrow('Cannot divide by zero');
});

Step Eleven: Create calculator.ts file in the src directory and place the contents below into the file.

JavaScript
export function add(a: number, b: number) {
  return a + b
};

export function subtract(a: number, b: number) {
  return a - b
};

export function multiply(a: number, b: number) {
    return a * b
}

export function divide(a: number, b: number) {
    // Divide by zero error
    if (b === 0) {
        throw new Error('Cannot divide by zero')
    }
    
    return a / b;
}

Step Twelve: Now run the script “npm run test“, and you should receive the following result.

Alright, great job!๐Ÿ‘ We created four functions and tested them, and now they are ready to be used in any project you would want to implement them in. If you are working on a big project with other developers OR you use these yourself in another project, you can, or others can use them without knowing what is happening inside.

Now let us push the envelope and incorporate the “calculator.ts” into a small application. To keep it simple, I will create an application that uses Webpack as a web server, allowing us to dynamically transpile our typescript file into a javascript file and use it in an html file.

Step One: Install Webpack packages:

npm install webpack webpack-cli webpack-dev-server html-webpack-plugin ts-loader --save-dev

Step Two: Create a file “webpack.config.js” and place the contents below into the file.

JavaScript
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development",
  entry: {
    index: "./src/index.ts",
  },
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
  },
  devtool: "inline-source-map",
  devServer: {
    static: "./dist",
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "Development",
      template: "src/index.html",
    }),
  ],
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
};

Step Three: Create 2 new files in the src directory: “index.ts” and “index.html”. The first file below is our code that we will place into the “index.ts” file.

JavaScript
import { add, divide, multiply, subtract } from "./calculator";

const signElement = document?.getElementById("sign") as HTMLInputElement;
const inputOneElement = document?.getElementById(
  "inputOne"
) as HTMLInputElement;
const inputTwoElement = document?.getElementById(
  "inputTwo"
) as HTMLInputElement;

signElement.innerHTML = "+";
inputOneElement.value = "0";
inputTwoElement.value = "0";

document?.getElementById("btn-subtract")?.addEventListener("click", () => {
  signElement.innerHTML = "-";
});

document?.getElementById("btn-add")?.addEventListener("click", () => {
  signElement.innerHTML = "+";
});

document?.getElementById("btn-multiply")?.addEventListener("click", () => {
  signElement.innerHTML = "x";
});

document?.getElementById("btn-divide")?.addEventListener("click", () => {
  signElement.innerHTML = "/";
});

document.getElementById("btn-equals")?.addEventListener("click", () => {
  let total = 0;

  try {
    switch (signElement.innerHTML) {
      case "+":
        total = add(
          parseInt(inputOneElement.value),
          parseInt(inputTwoElement.value)
        );
        break;
      case "-":
        total = subtract(
          parseInt(inputOneElement.value),
          parseInt(inputTwoElement.value)
        );
        break;
      case "x":
        total = multiply(
          parseInt(inputOneElement.value),
          parseInt(inputTwoElement.value)
        );
        break;
      case "/":
        total = divide(
          parseInt(inputOneElement.value),
          parseInt(inputTwoElement.value)
        );
        break;
      default:
        total = 0;
        break;
    }

    document.getElementById("result")!.innerHTML = total.toString();
  } catch (error: any) {
    document.getElementById("result")!.innerHTML = error.message;
  }
});

Now we need to update our “index.html” file with the code below:

JavaScript
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello World</h1>
    <input type="number" id="inputOne" />
    <span id="sign"></span>
    <input type="number" id="inputTwo" />
    <button id="btn-equals">=</button>
    <span id="result"></span>
    <div>
      <button id="btn-subtract">-</button>
      <button id="btn-add">+</button>
      <button id="btn-multiply">x</button>
      <button id="btn-divide">/</button>
    </div>
  </body>
</html>

Step Four: Update package.json file and under “scripts” add => "start": "webpack serve --open"

Step Five: Now run: npm start

By this point, you should see the application.

Conclusion

If you like to get the complete source code of this project click here. Of course, this is just the tip of the iceberg. I usually wouldn’t recommend writing an application like this since there are already products like Angular, React, and Vue that do a better job of manipulating the DOM. However, this demonstrates how to create and use a black box and how something like Webpack is a black box. We set up Webpack with a configuration file, and off we go. We don’t need to know how the internal workings of Webpack work, just an understanding of the inputs it needs.

I hope this article helps in understanding the idea of a black box. So with that said, I come full circle and end this with, “This has been the first Black Box Solution.”

Leave a Reply

Your email address will not be published. Required fields are marked *

Dennis Garcia

Full Stack Engineer with expertise in building system applications in SQL, .NET Core, and React

Latest Posts



Categories


Tags