0xCODE
Published in

0xCODE

The Pareto Principle In Software Engineering — Applying the 80/20 Rule

The Pareto Principle states the following:

“80% of consequences come from 20% of causes”

This is also called the 80/20 rule, and it can be applied to software engineering practices. This states that 80% of the problems encountered with building applications can be attributed to just 20% of the causes. This is of course an approximation and not an absolute figure. Most of what developers will encounter when testing the application is due to a small number of bugs that create so many problems.

This is based on a general shorthand 80/20 probability distribution or the Pareto Distribution. This corresponds to the Pareto Index α, where:

This states that 80% of effects come from 20% of causes. This can be written as a 4:1 ratio. In software, this can mean that a single bug can be the cause of many problems. The 4 problems were caused by just a single bug and not 4 separate bugs.

The Vital Few And The Trivial Many

The 80/20 rule is not an exact value but more of an example of how small things are the cause of larger problems. In a nutshell 80% of bugs can be fixed by solving just 20% of the problem. The wrong approach is to think that each problem is not related to other problems, because in many cases there is a relation.

Identifying the bugs using assertions and basic unit tests early on is the best practice. Once the application is many layers deep, things become much harder to identify. If a few bugs were missed during the first version of an application, once you have the next build it creates more problems as new functions and routines are added.

Integer Underflow/Overflow Problem Example

Consider an example using integer underflow (example in Solidity). Let’s write a smart contract that will show the rollover problem.

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.0;
contract RolloverExample {
uint8 public myUint8;
function decrement() public {
myUint8--;
}
function increment() public {
myUint8++;
}
}

I am using the 0.6.0 compiler in the example. There were no errors when I deployed the smart contract to a local Javascript VM environment. The initial value of the myUint8 variable should be 0 when you click myUint8 getter function.

The increment and decrement functions work just fine, no errors. When you increment a value from 0, it increments by 1 or myUint8++. When you check the value after incrementing, it adds 1 to the current value. You should then see 1. Increment again and the value becomes 2.

Now if you had hit the decrement button, the value should decrement by 1. We did not initialize or set a value for myUint8, so it defaults to 0. When you decrement that value should be -1. Instead you see the value goes to 255, which is an example of integer underflow called a rollover. This is because the uint8 variable was meant to store values only between 0 to 255. Nothing less or greater than that range, so it reverts to 255 when you decrement from 0. If it goes over a certain range, it is called an overflow.

Figure 1. When you invoke the decrement function, there are no errors. The problem is the expected value is not what you will get, using the uint8 data type. Instead of -1, the value rolls over to 255.

There are several ways to fix this problem. You can use a different variable type, don’t use the uint8 to store the value or the best fix is to have the latest compiler version. Change the compiler to version 0.8.0 and it catches the problem. When you invoke the decrement function, an error is generated with a message in the console.

transact to RolloverExample.decrement errored: VM error: revert.

revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.
call to RolloverExample.myUint8

If you expand the message (from Remix IDE console), you will see more information:

status      false Transaction mined but execution failed

When you call myUint8, the value reverts back to the initial state which is 0.

Figure 2. With the 0.8.0 compiler, the error was caught. The value of myUint8 does not rollover to 255, but reverts back to 0.

A developer will then have to create an error routine or just replace the uint8 with another data type. If it has to store values less than 0, then it was not a good choice for the data type. If this was not caught early on, it can create more problems as the application is built. Suppose the application needs to store values less than 0, and you have several functions that require it, you have a much bigger problem producing more errors.

This is why developers need to update to the latest software upgrades that fix known issues. The same can be said with operating systems like Windows, which are riddled with bugs. Upgrading or updating to the latest software versions often fix the bugs, so that is important in the development process.

Validation Testing

Before engineers deploy production quality applications, they must perform quality assurance. This through validation or unit testing, in which the application is put under stress test for load and validating the functions work correctly.

In the following example, the Chai Javascript testing framework is used make assertions that a function works properly. In the following snippet:

it("All tokens should be in my account", async () => {     let instance = await Token.deployed();     
let totalSupply = await instance.totalSupply();
await expect(instance.balanceOf(initialHolder)).to.eventually.be.a.bignumber.equal(totalSupply);

In this unit test, we want to make sure that all tokens in a smart contract are in a user account. There is then a routine that must be run to validate this. Testing makes sure that functions are working properly. In this example, the function can be validated when it returns the following:

Figure 3. A successful unit test validates that “All tokens should be in my account”

Synopsis

From what we have learned, a small number of causes can lead to a large number of outcomes. The 80/20 rule is just based on the Pareto Distribution, which uses the power law in statistics. When one quantity changes, it can affect other quantities proportionately relative to that change.

Developers who build applications, no matter at what scale, must have a form of unit testing and assertions to validate functions. This helps to identify bugs in the program logic, best performed at the earliest stages of development. Many times the cause of application errors were just small issues. When they are identified early on using the Pareto Principle, it helps prevent larger problems.

(Photo Banner Credit: By Pixabay)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Vincent Tabora

Vincent Tabora

Editor HD-PRO, DevOps Trusterras (Cybersecurity, Blockchain, Software Development, Engineering, Photography, Technology)