Why Do You Need To Know Interface Fundamentals? 🔊
Understanding the roots of what "interface" really means
In Java, the interface
keyword is how you create an interface type.
The interface type has many rules, one of them is to force another class to implement the methods specified in it, as long as that class declares an implements
reference towards that interface:
If Car
does not implement the start()
method required by the Vehicle
interface, then a compilation error will occur:
In the context of the mechanics of a programming language like Java, an “interface” represents a keyword to declare a type that contains a specific set of rules for interactions between objects in a Cybernetic Environment.
However, when software engineers talk about "interface", they might be referring to something much deeper than a keyword in a programming language.
In the context of engineering, an "interface" represents something that provides a connection between two systems (or parts of it), in a way they could not have been directly connected.
"Interface" can have a more conceptual and broad definition.
It all depends on the context.
There is a difference between "interface" in the context of the mechanics of a programming language and "interface" in the context of engineering
Let's imagine you're the person charged to design a city. It's reasonable to assume you'll need to create many types of roads and signs. There are dirt roads (because the Return On Investment is not big enough to make them better), back roads (that have a lower width for residential areas), and highways (built to avoid the traffic jam). There are traffic lights (to organize the flow), speed signs (to inform the secure speed), and traffic lanes (to prevent accidental crashing).
You can say the road affords a car, truck or van to go from one point to another securely. The sign affords a conductor to be able to understand where they need to go.
You can also say the city is the environment and the road is an interface that contains common characteristics: It allows a vehicle (car, truck or van) to drive through, and signs to be added (traffic lights, speed signs, and traffic lanes).
Each type of road (dirt road, back road or highway) will implement different kinds of signs. Some highways won't need a traffic light but will need speed signs and lanes. Some dirt roads won't need traffic lanes but might need traffic lights and speed signs.
A road is an interface that accepts a vehicle — which is also an interface — and affords it to drive through
Each country might have its own road implementation. In Australia, you'll drive on the left side and there will be different signs such as the arrow traffic light. In Brazil, you'll drive on the right side and there's no arrow traffic light.
Many vendors and countries can implement a vehicle differently, but there are standards for its common interface:
- They should make it with wheels to be able to run.
- It should fit on the road seamlessly.
- It should have a window so that the driver can see the signs.
If the vehicle doesn’t implement the standard interface correctly — let’s say a car that flies or doesn't run— then it won’t be able to function efficiently in common transit. That’s why it's useful to communicate architecture in terms of interfaces (road or vehicle) instead of concrete terms (dirty road in Australia, van or truck in Brazil) when we're referring to the general type of connection in an environment.
An interface allows efficient means of generalizing attributes. It allows communicating affordances instead of having to consider the many types of implementations that interface can have.
What a real life object or environment affords another object to do can be specified in the form of an "interface"
The Video Graphics Array (V.G.A.) connector of a computer is also an interface. It allows many different types of screens to be plugged. Any screen manufacturer will be able to create a product that will work seamlessly when plugged in a machine that exposes the "V.G.A." common way of connecting.
It doesn't even need to be a computer!
The interface represents the concept of capability, of being able to connect something to a specific set of characteristics. Everything else can be different, as long as the means to connect conform to the same standard format.
But is this useful only when we're implementing a game that is like real life and has roads and vehicles? Is this useful only when we're writing code in an object oriented environment using a constrained language like Java?
It's not.
Let's talk front-end.
Imagine you have to create a set of tabs for a page containing a movie's description using the component pattern:
The tabs container component will afford a tab to be registered on it. It will also activate the first registered tab on initialization so that something is visible when the user hasn't clicked on anything yet:
When each tab initializes, it will register itself in the tabs container. It will also afford a client (in this case, the tabs container) to activate it:
Note this line in the TabController
that is calling the register
function with the "current tab controller" as an argument:
tabsController.register(currentTabController);
… and this one in the register function of TabsContainerController
that receives the argument with the name "tab":
register: (tab) => {
registeredTabs.push(tab);
},
You can say the tabs container affords to register a tab. However, the tab is registering its own controller, not a new "tab" object instance. By reading the code, that means the tab controller implements the tab interface. Even though there's no explicit interface
or new Tab()
instance anywhere, the name of the argument and the way it's being used by the TabsContainerController
indicates what that argument represents.
It wouldn't make sense to write the code with the argument called "tab controller":
register: (tabController) => {
registeredTabs.push(tabController);
},
The tabs container doesn't need to know that what's being passed is a controller. Also, it should never use any functionality that is specific to a controller and not related to a tab.
It only has to know 3 things:
1. "Something" like a tab is passed as an argument:
register: (tab) => {
2. That "something" can be stored by reference in an array of registered tabs:
registeredTabs.push(tab);
3. That "something" has an activate()
functionality:
if (index === 0) {
tab.activate();
}
Those are the only things theTabsContainerController
requires from a "tab".
If it registers like a tab and it activates like a tab, then it must be a tab, even though it's a controller.
Or in other words:
If it walks like a duck and it quacks like a duck, then it must be a duck
— Duck Typing on Wikipedia
In JavaScript, the interface
keyword exists but is a reserved keyword and doesn't do anything. Duck typing is the solution to make sense of the structure of your code as long as you understand what an interface really means.
I have said before that understanding the syntax or the tool is not enough. You need to understand the fundamentals behind a concept in order to efficiently write software and be productive.
For an interface, it's the same.
Programming goes far beyond than just solving puzzles and writing code that is hard to understand.
Just as building a badly designed car will make it hard to comprehend and expensive to fix in the future, building a badly designed code will also make it hard to comprehend and expensive to change later.
Even if it can run for a few miles before you notice the mistake.