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.
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.
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.
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.
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:
<!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