Good Code - A small walkthrough !
Even if I say nobody cares about your
code the quality nonetheless does influence a project. Functional
correctness reigns supreme, but if we put that aside what should we look at
next?
Cohesion and coupling are the two most significant
aspects of code impacting software quality.
Cohesion
Cohesion is how well the bits of a module fit
together. A set of functions, an interface, is considered cohesive when each
function is closely related to another. For example, drawLine and drawCircle are closely
related and belong nicely together in a single Draw module. If functions differ in their behavior a module becomes less cohesive. For
example, drawLine and calculateBalance don’t seem to be
related at all, So putting them into the same module doesn't make any sense at all.
We can roughly measure cohesion by how simply
and precisely the module can be described. Short and precise sentences are
preferred to longer, verbose, and generic ones. Example, contrast the sentence “The Draw Module draws the UI elements on to the screen” to “This module draws Items on the screen and calculates balances”. In the 2nd Sentence we can’t even give the module a name. If we
can’t give a module a name there’s a good chance it lacks cohesion.
Words like “assorted” , “different” and “variety” are a
potential indication of a low cohesion. A module that provides “an assortment
of calculations” doesn’t sound as cohesive as a module that provides “All Data Formatters used in the application”.
Why
A highly cohesive module is easier to
understand than a less cohesive one. While looking at the code, or interface,
we can keep a single unifying theme in our head. As all functions relate to
that theme it is easier to understand the code, and thus easier to extend the
code, debug errors, or simply use the interface.
Cohesive modules tend to reuse the same types
throughout their interface. Atleast Some parameters to drawLine should be the similar as
those to drawCircle(X position,Y position). Once we’ve learned
the basic types used in a module it is far easier to use the rest of the
module.
Clean and coherent interfaces also make a
module much easier to replace and test. Since all the functions are related, it
makes it easier to replace all of them or swap out the module.
Coupling
Coupling is how dependent modules are on the
inner workings of each other. Tightly coupled modules rely extensively on the
specific state of each other, sharing variables and many types. Loosely coupled
modules are fairly independent: they have a few well defined APIs and share a
limited amount of, or no data.
The extent of coupling between modules is
determined by the complexity of the exposed interface, where every public
function and type is part of the interface. A module that has a high ratio of
public information compared to private information will result in tight
coupling. A module that exposes a minimal interface will result in loose
coupling.
Transitivity is also an indicator of coupling.
Say we have a series of modules, where each depends on each other in turn i.e. A -> B -> C. Ideally module A should know
nothing about module C. The more it does
know the more it is coupled to module B.
Why
The higher the coupling is between modules the
harder it is understand what the code is doing. The more details two modules
share the more difficult it is to understand them. Independent code is great
for readability since we can make sense of it in isolation.
The more coupled modules are the harder it is
to replace them. This also means it is harder to debug them since it is unclear
where one module ends and another begins. As any changes ripple through
connected code, refactoring of highly coupled code is also very difficult.
Module isolation is very important for team
structure. Programmers can be productive on individual modules without needing
to understand the entire code base. They are also less likely to interfere with
the work of others.
Quality metrics
While programming all we have to do is keep
the above discussed points in our head and design for them. For any new
function or type think, “does this really belong here?”, and whenever you need access
to data from another module think, “Should I really be accessing this
directly?”
The biggest refactoring tends to be decoupling
code and improving cohesion.
Here below are some more points that we should
consider when writing code
Simplicity means you don't
do in ten lines what you can do in five. It means you make extra effort to be
concise, but not to the point of obfuscation. It means you abhor open coding
and functions that span pages. Simplicity—of organization, implementation, and
design—makes your code more reliable and bug free. There's less to go wrong.
Readability means what it
says: that others can read your code. Readability means you bother to write
comments, to follow conventions, and pause to name your variables wisely. Like
choosing "taxRate" instead of "tr".
Modularity means your
program is built like the universe. The world is made of molecules, which are
made of atoms, electrons, nucleons. Likewise, good programs erect large systems
from smaller ones, which are built from even smaller building blocks. You can
write a text editor with three primitives: move, insert, and delete. And just
as atoms combine in novel ways, software components should be reusable.
Design means you take
time to plan your program before you build it. Thoughts are cheaper than
debugging. A good rule of thumb is to spend half your time on design. You need
a functional spec (what the programs does) and an internal blueprint. APIs
should be codified in writing.
Efficiency means your
program is fast and economical. It doesn't hog files, data connections, or
anything else. It does what it should, but no more. It loads and departs
without fuss. At the function level, you can always optimize later, during
testing. But at high levels, you must plan for performance. If the design
requires a million trips to the server, it is bad!.
Elegance is like beauty:
hard to describe but easy to recognize. Elegance combines simplicity, efficiency,
and brilliance, and produces a feeling of pride. Elegance is when you replace a
procedure with a table, or realize that you can use recursion—which is almost
always elegant:
Comments