Principles – Quick notes

Robustness principle – Postel’s law, after Jon Postel

Programs that send messages to other machines (or to other programs on the same machine) should conform completely to the specifications, but programs that receive messages should accept non-conformant input as long as the meaning is clear.


Rule of least power

In programming, the rule of least power is a design principle that “suggests choosing the least powerful [computer] language suitable for a given purpose”.


Principle of least astonishment

The principle of least astonishment (POLA), also called the principle of least surprise (alternatively a “law” or “rule”)
applies to user interface and software design.
“If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature.”

When two elements of an interface conflict, or are ambiguous, the behavior should be that which will least surprise the user; in particular a programmer should try to think of the behavior that will least surprise someone who uses the program.


Pareto principle

The Pareto principle (also known as the 80/20 rule, the law of the vital few, or the principle of factor sparsity).
It states that, for many events, roughly 80% of the effects come from 20% of the causes.

It was also discovered that in general the 80% of a certain piece of software can be written in 20% of the total allocated time. Conversely, the hardest 20% of the code takes 80% of the time.


Keep it simple, stupid (keep it simple and straightforward)

The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided. 


Don’t repeat yourself 

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Don’t repeat yourself (DRY, or sometimes do not repeat yourself) is a principle of software development aimed at reducing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy.


Check the values of all data from external sources

When getting data from a file

  • Verify that if it has valid extensions/file type
  • Verify that it does not exceeds certain file size

When getting data from a a user, the network, or some other external interface

  • Check to be sure that the data falls within the allowable range.
  • Make sure that numeric values are within tolerances
  • Strings are short enough to handle.
  • If a string is intended to represent a restricted range of values.
  • Be sure that the string is valid for its intended purpose;

Otherwise reject it.

Provide methods in pairs with their opposites

When working with class or module sometimes you would need equal and opposite operations. The methods should be symmetric. Please make sure they are not added causally that would add not symmetric verbs.

Not symmetric

  • turnOn()/disable()
  • openConnection()/shutConnection()
  • increaseVolume()/turndownVolume()
  • push/remove

If you are adding symmetric methods, then make sure they feel symmetric one.

Symmetric

  • turnOn()/turnOff()
  • openConnection()/closeConnection()
  • readFile()/writeFile()
  • increaseVolume()/decreaseVolume()
  • activateAlarm()/deactivateAlarm()
  • push()/pop()


Functions in JavaScript are objects

Functions in JavaScript are objects.

How to know in the browser?

Navigate to the console of the browser near you and type this simple function Person shown below and hit enter. Next, type Person followed by dot (.) see the methods on Person function. Pretty simple.

Thus the function is an object and has the methods as other objects in JavaScript.

We can call functions on function. Let’s invoke call function and see the output.

Invoking call method on function Person.

Prototype object:

Objects are keyed collection/associative array that has a hidden link to the prototype object. Try the following code in any browser console and understand it.

Object and prototype object has a linking.

We can access the prototype object using Object.prototype.

We can get an original object back from the prototype object using constructor (Object.prototype.constructor) property.

Pictorial representation of Object and it’s prototype object.

Oh, wait! We were talking about Function.

Like Object, Function is linked to Function.prototype.

Let me show you using Person function, it’s prototype object and their linking in the browser console.

Pictorial representation of Person function and it’s prototype object.

Avoid deeply nested ternary operator

?: is a ternary operator introduced to write elegant if-else clause.

It is a concise way of writing simple conditionals. However, those should be easily understandable by any human. It should not be used to write deeply nested complex conditionals that hamper the readability.


When to use?

When you have very simple if-else that could be covered in one line and returns value.


Example:

Display text as “Weekend” if it’s a Sunday otherwise “Working day”

Another one:

Determine the restaurant to visit depending upon cash in your wallet.

When NOT to use?

As said earlier, they are used to simplify the conditional so that they add value and make code simple and elegant.

However, that does not mean you should blindly rewrite ALL if-else clause with the ternary operator. Please avoid them when expression becomes complex and difficult to understand.


Bad Example

The implementation of the fizz buzz generator.



const output = number % 3 === 0 && number % 5 === 0 ? "FizzBuzz"
 : number % 3 === 0 ? "Fizz" 
 : number % 5  === 0 ? "Buzz" 
 : number;

In my career, I have seen people writing deeply nested clauses using the ternary operator. I kept the above example to convey my thoughts.

The above snippet adds unnecessary mental mapping to remember and process each conditional and symbols ?: ?: ?: more like a machine.

Please don’t be a human code compressor.

Better alternative

Conventional if-else over ternary when a condition becomes complex.

Day by day, high-level languages are introducing more features so that developers could write more human-readable expressive code. We should keep this point in our mind and avoid a few things like writing deeply nested complex ternary conditionals. Instead, go for conventional control flow statements like if-else or if-return-early.

Thoughts mentioned in this post are based on my personal experience. It is just a guideline. IMO, we should be compassionate about our co-worker while writing the code and should avoid clever-complex clauses using ternary operators and rather should focus on elegance.

Primitive Obsession – The code smell

https://www.collinsdictionary.com/dictionary/english/primitive

Programming languages divide their types mainly into two categories.

  • Primitive types (A built-in types like string, boolean, int, decimal…)
  • Objects (class/function): User-defined types using class-based/prototype-based objects.

A primitive data type is a data type for which the programming language provides built-in support. Example: number, string, boolean, date and so on.

There are situations when developers should represent their idea/concept using user-defined types (Abstraction or encapsulation).

Whereas they choose to use primitive types (inbuilt int, string…) to represents the concept.

“Talk is cheap. Show me the code.” ― Linus Torvalds

Consider the above API for scheduling meetup.

If you observe carefully, all the parameters: topic, description, date, location id, and max participants when they stand together represent the concept/idea called meetup.

Almost all the data types are primitive types (Built-in types: string, int, DateTime and so on).

Problem?

Overutilization of these primitive types to solve a problem makes the code more verbose/procedural and logic to deal with them is scattered.

Solution:

Since all method parameter stands together to represent the concept called Meetup.

Here, we could group all these parameters together to represent the idea/concept called meetup. So, introduce an object to gather these data values.

Upon replacing data values with an object API would look like:

This is how the API should have been. However, the developer chooses to go with all built-in types (segregated). IMO, this overutilization of primitive types in almost all cases can be treated as an obsession about primitives which can be called a primitive obsession.

I have explained only one scenario and there are other scenarios too.

Test case structure

A commonly applied structure for test cases has

  • Setup: Arrange the state of the unit under test in order to run the test.
  • Execution: Act on the unit under test so that it performs the expected behavior and receive output if needed.
  • Validation: Assert/Verify the outcome of execution.
  • Cleanup: Restore unit under test to a pre-test state.