Encapsulation


Encapsulation is the process of putting data and code (that operates on data) together in a single unit, which, acts as a protective wrapper for data and code. Access to the data is provided via controlled access (public interface).

Consider an example of a simple wristwatch.

Abstraction means to provide the simplest view of a complex concept (showing only the necessary part). So, in this case, it displays only time.

Encapsulation means not only provide the simplest view of complex concept (Abstraction!) but also hide and protect internal implementation. The end user cannot see how time is being calculated; what gives energy to the wristwatch; how the internal circuits are structured and so on…

The glass and plastic body forms a protective wrapper (Encapsulation) which hides the internal implementation details (hiding the complexity) and shows the current time (…only relevant part, Abstraction!).

Encapsulation gives access to modify the data via the controlled public interface. In this case, it’s a push button which is used to change/set the time.

From this example, it is clear that the two concepts are related. Without proper encapsulation, there would be no abstraction. Encapsulation not only helps a code achieve abstraction (shows only relevant functionality) but goes one step further and hides everything else, which is irrelevant to the user.

In essence, Encapsulation picks up where abstraction leaves off. In code, you will either have both abstraction and encapsulation, or you will have neither.

https://blog.beingcraftsman.com/datta/

Why giving meaningful names to things in programming is important

Everything in this world has meaningful names. It helps our brain to understand and remember the things very easily. It means less mental mapping.

Let us take real-world examples of meaningful names given to things like hand wash (of course, you don’t use it to wash your face), face wash, shaving cream, aftershave and so on.

Similarly, in the programming, everything needs to have a meaningful name because we as a developer spend our most of the time reading the code than we do writing it.

As a developer, our daily job is to give a solution to the problem at hand.

To solve the problem at hand, we sometimes create a project, an assembly, a namespace,  directories, class files, classes, fields, methods, other members, UI elements, their translation files, translation keys and so on.

All of these things should have the meaningful name so that they convey their intent and you realize what they are doing by just looking at their name.

Perhaps they answer all the big questions that you or future maintenance developers would have.

Let’s go through the following code snippet. It is written in js.

  downld(recs){ 
        const cols = ['Name', 'Age', 'Gender'];
        let d = `data:text/csv;charset=utf-8,${cols.join(',')}rn`;
        recs.each((r) => {
            const row = [
                r.get('name'),
                r.get('age'),
                r.get('gender')
            ].join(",");

            d += `${row}rn`;
        });
        const u = encodeURI(d);
        const lnk = document.createElement("a");
        lnk.setAttribute("href", u);
        lnk.setAttribute("download", "users.csv");
        document.body.appendChild(lnk);
        lnk.click();
  }

I hope you understood what it is doing.

The above example shows that a simple code snippet could be difficult to understand when meaningful names are NOT given to variables, functions and so on.

Now think about a project that has 100+ classes and thousands of lines.

Don’t you think it will be painful for the maintenance developer as well as an original developer to read it again in the future?

This could have been easy to understand when good names would have been given.

Let us try to give the meaningful name in the code snippet.

  downloadAsCsv(users){ 
        const columnNames = ['Name', 'Age', 'Gender'];
        const csvHeader = `data:text/csv;charset=utf-8,${columnNames.join(',')}rn`;
        let csvDataRows = "";
        const newlineAndCarriageReturn = `rn`;
        users.each((user) => {
            const currentRow = [
                user.get('name'),
                user.get('age'),
                user.get('gender')
            ].join(",");

            csvDataRows += currentRow + newlineAndCarriageReturn;
        });

        const csvFileContent = csvHeader + csvDataRows;
        const encodedUri = encodeURI(csvFileContent);
        const newlink = document.createElement("a");
        newlink.setAttribute("href", encodedUri);
        newlink.setAttribute("download", "users.csv");
        document.body.appendChild(newlink);
        newlink.click();
  }

Now, do you think it’s a little better than the previous version?

The good names encourage you to write clean and good code. You can go one step ahead and split above function.

    downloadAsCsv(users){
        const csvFileContent = this.generateCsvContent(users);
        const encodedUri = encodeURI(csvFileContent);
        const newlink = document.createElement("a");
        newlink.setAttribute("href", encodedUri);
        newlink.setAttribute("download", "users.csv");
        document.body.appendChild(newlink);
        newlink.click();
    }

    generateCsvContent(users) {
        const columnNames = ['Name', 'Age', 'Gender'];
        const csvHeader = `data:text/csv;charset=utf-8,${columnNames.join(',')}rn`;
        let csvDataRows = "";
        const newlineAndCarriageReturn = `rn`;
        users.each((user) => {
            const currentRow = [
                user.get('name'),
                user.get('age'),
                user.get('gender')
            ].join(",");

            csvDataRows += currentRow + newlineAndCarriageReturn;
        });

        return csvHeader + csvDataRows;
    }

I hope you agree with me that meaningful names will make everyone (including you) more than happy after reading it.

In case of methods, when you failed to give a name to a method, you may realize it’s doing more than one thing. It is really helping you.

Even when you are able to give a meaningful name to a method, you may realize that the method doesn’t belong to this class.

I often realized that this practice of giving meaningful names helped me a lot about understanding the solutions, separations of concerns and even responsibility of the classes, methods, assembiles and so on.

Suppose your boss comes to you and asks you to fix value against gender column in generated CSV (from above example) on priority. Instead of debugging and finding the location of the code, just ask IDE to show you “generateCsvContent” routine.

Thus, help your IDE to help you by giving meaningful names to everything in programming so that you can figure out everything very easily.

Consequently, giving meaningful names will help you in some way or other.

When you revisit your code after 4 hours or 4 weeks, or 4 years, and you think you could give more meaningful names now then

DO NOT hesitate to rename it if it’s not breaking anything and has less impact on other features.

REMEMBER!

https://blog.beingcraftsman.com/datta/

Abstraction

Abstraction is the ability to work with the concept/idea while safely ignoring some of its details. Rather, handle different details at different levels.

Take an example of a simple fan regulator. As a consumer of it, I can focus only on regulating the speed. Here, changing the speed via the interface (knob) is the concept while I will ignore other details like an internal electronic circuit that consists of a diode, capacitor, resistors, DIAC, TRIAC and so on..

Internal of the fan regulator.

Thus, Abstraction is the process of showing only the relevant details with which consumer can safely work with.


Real-life analogy

When we consider a laptop as aggregate, it is an abstraction of its various parts, like a keypad, touchpad, screen, motherboard, hard-disk, processor, etc.

Similarly, A keypad as a whole, in turn, is an abstraction of a particular arrangement of keys and internal wirings.

This way, abstraction allows you to take a simpler view of a complex concept.


Similarly, in software development, abstraction should manage the complexity of the software design at a different level. A good abstraction should lead to a good (less complex) software design.

In languages like C++, Java, C#, we can achieve abstractions via abstract class and interface.

Good programmers create abstractions at the method level, class level, interface level, namespace level, and assembly level —in other words, motherboard level, keypad level, and laptop level—and that supports faster and safer programming.

As programmers, we need to provide the right level of abstraction in accordance with the need of the end consumer.

Method cohesion

Image credit: https://www.slideshare.net/agileee/lightening-talk-software-craftsmanship

The Method exhibits high cohesion when a method performs one and only one operation and do what their names say they do.

If they do anything else, they are less cohesive and poorly named.

Examples of highly cohesive methods:

  • GetProductName()
  • PrintBarcode()
  • ToLower()
  • CalculateAge()
  • CreateUser().

Cohesion – the action or fact of forming a united whole.

Cohesion in the object-oriented programming tells you whether the members (states and behavior) of the class works towards a common goal or fulfills the central purpose of the class.

See the class shown below.


class Program
{
 
public string GetData(string fileName)
 {
    // Read file content
 }

 public void PersistDocument(string documentText, string targetFileName)
 {
    // persist document into given file
 }

 public Document ParseInput(string input)
 {

    // implementation goes here.

 }

 public void View(BankAccountStatement accountStatement)

 {

    // implementation goes here.

 }

 public void DownloadAsPdf(BankAccountStatement accountStatement)

 {

    // implementation goes here.

 }

 public void DownloadAsCSV(BankAccountStatement accountStatement)

 {

    // implementation goes here.

 }

Now, look at the methods in the Program class. They are clearly doing the unrelated job. I did not see any connection between the file read, file writes, parse Input and view account statement, download bank account statement as CSV or pdf. Well, I did not see the class has a central purpose.

The program class is violating the single responsibility principle. The program class looks like a utility class that contains miscellaneous (unrelated) methods. It’s like a silver bullet for every problem.

These methods should be reorganized into more-focused classes and should work towards the central purpose and should extract them to classes that should do

  • File read and write.
  • Parse document
  • View and download bank account statement.

Hence we need to create separate classes so that they work towards one and only one purpose. The program class can be divided as shown below.


class FileDocumentStorage
{
  public string GetData(string fileName)
  {
     // implementation goes here.
  }

  public void PersistDocument(string documentText, string targetFileName)
  {
     // implementation goes here.
  }
}

The FileDocumentStorage class reads data from given file and stores the document-text into the target file. It has only one purpose (single responsibility) that is file manipulation. The methods are more related to each other.


class InputParser
{
  public Document ParseInput(string input)
  {
    // implementation goes here.
  }
}

Similarly, class InputParser parses the input string and converts it into the document object.

class BankAccountStatementForm
{
 public void View(BankAccountStatement accountStatement)
 {
    // implementation goes here.
 }

 public void DownloadAsPdf(BankAccountStatement accountStatement)
 {
    // implementation goes here.
 }

 public void DownloadAsCSV(BankAccountStatement accountStatement)
 {
    // implementation goes here.
 }
}

Lastly, BankAccountStatementForm class views the bank account statement, downloads the bank account statement as PDF or CSV. It fulfills the central purpose of Viewing the Bank account statements.

Now the refactored classes` methods are working towards the central goal and look related.

You can see your brain can easily remember or understand everything the code does.

High/Strong cohesion is always preferred it reduces the complexity of the code by designing easy to understandable classes that obey the single responsibility principle.

Eventually,

Cohesion means that the state and behavior of the class should support a central purpose.