Clean Code Basic Principles
Clean Code Basic Principles
· Bad Code (example of some app that is discontiunied because of non-clean code)
'As productivity decreases, management does the only thing they can, they add more staff to the
project in hopes of increasing productivity. But that new staff is not versed in the design of the system.'
Redesign of project (New tiger team for creating new software design, and old team for mainteniance
old design while new design reaches the abilities of old one)
'You will not make the deadline by making the mess.' -> 'The only way to make the deadline and zhe only
way is to go fast is to keep the code as clean as possible at all times'
Code-sense
What is clean code (elegant, efficient, clean code does one thing well, readability, crisp abstraction,
literate, care, meaningful names, expressiveness)
Boy Scout Rule (says 'Leave the campground cleaner than you found it.')
2) Good names (Use Intention-Revealing Names, Avoid Disinformation, Make Meaningful Distinctions,
Use Pronounceable Names, Use Searchable Names, Avoid Encodings, Avoid Mental Mapping, Use
Solution and Problem Domain Names, Don't Add Gratuitous Context)
· The problem isn’t the simplicity of the code but the implicity of the code. We want to know
more information from source code (we want explicite code)...
Avoid disinformation:
· We need to avoid names such as (hp, six , sco etc.) beacuse they are the names of Unix platforms
or variants.
· Even if you are coding a hypotenuse and 'hp' looks like a good abbreviation, it could be
disinformative because it can have two meanings.
· A truly awful example of disinformative names would be the use of lower-case L or uppercase O
as variable names, especially in combination. The problem, of course, is thatthey look almost
entirely like the constants one and zero, respectively
· Programmers create problems for themselves when they write code solely to satisfy a compiler
or interpreter (programmer ignores potential warnings)
· Use Pronounceable Names (don't use x1, x2, x3... because these names doesn't have any
information)
· Don't use similar meaning words such as ProductInfo and ProductData, because if we want to
instance an Object, we will not know what we exactly want to instance without looking at the
code in class files. Also this can be applied on methods.
· Noise words are redundant (Ex. we don't name variable nameString, numberInt, ..., instead use
name, number ...)
· Humans are good at words. A significant part of our brains is dedicated to the concept of words.
And words are, by definition, pronounceable. So, you need to use pronounceable words
· Single-letter names and numeric constants have a particular problem in that they are noteasy to
locate across a body of text
· Likewise, the name 'e' is a poor choice for any variable for which a programmer might need to
search. It is the most common letter in the English language and likely to show upin every
passage of text in every program. In this regard, longer names trump shorter names, and
any searchable name trumps a constant in code.
Avoid encodings:
· We have enough encodings to deal with without adding more to our burden.
· Encoding type or scope information into names simply adds an extra burden of deciphering
· It hardly seems reasonable to require each new employee to learn yet another encoding
“language” in addition to learning the (usually considerable) body of code that they’ll be working
in.
· It is an unnecessary mental burden when trying to solve a problem. Encoded namesare seldom
pronounceable and are easy to mistype.
· Java programmers don’t need type encoding. Objects are strongly typed, and editing
environments have advanced such that they detect a type error long before you can run a
compile!
· Besides, people quickly learn to ignore the prefix (or suffix) to see the meaningful part of the
name.
· The more we read the code, the less we see the prefixes.
· Readers shouldn’t have to mentally translate your names into other names they already know.
· This problem generally arises from a choice to use neither problem domain terms nor solution
domain terms.
· This is a problem with single-letter variable names (except i, j and k for loop counters)
· It’s just a placeholder that the reader must mentally map to the actual concept.
· There can be no worse reason for using the name 'c' than because 'a' and 'b' were already taken
· In general programmers are pretty smart people. Smart people sometimes like to show off their
smarts by demonstrating their mental juggling abilities.
· One difference between a smart programmer and a professional programmer is that the
professional understands that clarity is king. Professionals use their powers for good and write
code that others can understand.
Class Names:
· Class names always should be start with capitalised letter and have noun or noun phrase names
like (such as Customer, Vehicle ...)
· Avoid Class names like Manager, Processor, Data, or Info in the name of a class.
· Methods should have verb or verb phrase names (like postPayment, deletePage, or save)
· Accessors, mutators, and predicates should be named for their value and prefixed with get, set,
and is according to the javabean standard
· Say what you mean. Mean what you say (don't use names such as holyShit(), dumbSpace(), also
this paradigm applies anywhere in clean code)
· For instance, it’s confusing to have fetch, retrieve, and get as equivalent methods of different
classes.
· A consistent lexicon is a great boon to the programmers who must use your code.
Don't pun:
· Using the same term for two different ideasis essentially a pun.
· If you follow the “one word per concept” rule, you could end up with many classes that have, for
example, an add method. As long as the parameter lists and return values of the various add
methods are semantically equivalent, all is well.
· We want to use the popular paperback model where by the author is responsible for making
himself clear and not the academic model where it is the scholar’s job to dig the meaning out of
the paper
· Remember that the people who read your code will be programmers.
· So go ahead and use computer science (CS) terms, algorithm names, pattern names, math
terms, and so forth.
· Choosing technical names forthose things is usually the most appropriate course
· Separating solution and problem domain concepts is part of the job of a good pro-grammer and
designer.
· The code that has more to do with problem domain concepts should have names drawn from
the problem domain.
· There are a few names which are meaningful in and of themselves—most are not.
· Instead, you need to place names in context for your reader by enclosing them in well-named
classes, functions, or namespaces.
· Example of this is if we have variables named lastName, we can rename it with addLastName if
we have add or remove class
· The improvement of context also allowsthe algorithm to be made much cleaner by breaking it
into many smaller functions
· In an imaginary application called “Gas Station Deluxe,” it is a bad idea to prefix every class
with GSD.
· Shorter names are generally better than longer ones, so long as they are clear. Add no more
context to a name than is necessary.
· The names accountAddress and customerAddress are fine names for instances of the
classAddress, but could be poor names for classes
Final words:
· The hardest thing about choosing good names is that it requires good descriptive skills and a
shared cultural background.
· If you are maintaining someone else’s code, use refactoring tools to help resolve these problems.
It will pay off in the short term and continue to pay in the long run
3) Functions (Needs to be small, Do One Thing, Sections within Functions, One Level of Abstraction per
Function, Reading Code from Top to Bottom, Use Descriptive Names, Avoid using Function Arguments,
Avoid using Flag Arguments, Use good Verbs and Keywords, Have No Side Effects, We need to prefer
using Exceptions than Error codes, Don't Repeat Yourself - DRY, Structured Programming)
· Functions arethe first line of organization in any program. Writing them well is the topic of this
chapter.
Small:
· The second rule of functions is that they should be smaller than that.
· In the eighties we used to say that a function should be no bigger than a screen-full.
· This implies that the blocks within if statements, else statements, while statements, and so on
should be one line long.
· The indent level of a function should not be greater than one or two.
Do One Thing:
· Functions should do one thing and they should do it well and they should do it only
· After all, the reason we write functions is to decompose a larger concept (in other words, the
name of the function) into a set of steps at the next level of abstraction
· So, another way to know that a function is doing more than “one thing” is if you can extract
another function from it with a name that is not merely a restatement of its implementation
· In order to make sure our functions are doing “one thing”, we need to make sure that the
statements within our function are all at the same level of abstraction.
Reading Code from Top to Bottom (also known as 'The Stepdown Rule'):
· We want every function to be followed by those at the next level of abstraction, so that we can
read the program, descend ingone level of abstraction at a time as we read down the list of
functions.
· To say this differently, we want to be able to read the program as though it were a set of TO
paragraphs, each of which is describing the current level of abstraction and referencing
subsequent TO paragraphs at the next level down.
· It turns out to be very difficult for programmers to learn to follow this rule and write functions
that stay at a single level of abstraction.
· It is the key to keeping functions short and making sure they do “one thing.”
· Making the code read like a top-down set of TO paragraphs is an effective technique for keeping
the abstraction level consistent.
Switch Statements:
· Even a switch statement with only two cases is larger than I’d like a single block or function to be
· It’s also hard to make a switch statement that does one thing
· Unfortunately we can’t always avoid switch statements, but we can make sure that each switch
statement is buried in a low-level class and is never repeated.
· My general rule for switch statements is that they can be tolerated if they appear only once, are
used to create polymorphic objects, and are hidden behind an inheritance relationship so that
the rest of the system can’t see them
· Of course every circumstance is unique, and there are times when I violate one or more parts of
that rule
· Ward's principle says 'You know you are working on clean code when each routine turns out to
be pretty much what you expected'
· Half the battle to achieving that principle is choosing good names for small functions that do one
thing (the smaller and more focused a function is, the easier it is to choose a descriptive name)
· Don’t be afraid to make a name long (long descriptive name is better than a shortenigmatic
name)
· Usea naming convention that allows multiple words to be easily read in the function names, and
then make use of those multiple words to give the function a name that says what it does
· Don’t be afraid to spend time choosing a name. Indeed, you should try several different names
and read the code with each in place.
· Choosing descriptive names will clarify the design of the module in your mind and help you to
improve it.
· Be consistent in your names (Use the same phrases, nouns, and verbs in the function names you
choose for your modules)
· More than three (polyadic) requires very special justification and then shouldn’t be used anyway
· Output arguments are harder to understand than input arguments (because the output
arguments often cause us to do a double-take)
Common Monadic Forms:
· There are two very common reasons to pass a single argument into a function. You may be
asking a question about that argument, as in boolean fileExists(“MyFile”) or you may
beoperating on that argument, transforming it into something else and returning it
· A somewhat less common, but still very useful form for a single argument function, is an event
· Try to avoid any monadic functions that don’t follow these forms, for example, void
includeSetupPageInto(StringBuffer pageText).
· Using an output argument instead of a return value for a transformation is very confusing
· It immediately complicates the signature of the method, loudly proclaiming that this function
does more than one thing.
· It does one thing if the flag is true and another if the flag is false!
Dyadic Functions:
· The two arguments have no natural ordering. The expected, actual ordering is a convention that
requires practice to learn
· Dyads aren’t evil, and you will certainly have to write them. However, you should be aware that
they come at a cost and should take advantage of what mechanims may be available to you to
convert them into monads.
Triads Functions:
· Functions that take three arguments are significantly harder to understand than dyads.
· The issues of ordering, pausing, and ignoring are more than doubled.
Argument Objects:
· When a function seems to need more than two or three arguments, it is likely that some of
those arguments needs to be wrapped into a class of their own
· Reducing the number of arguments by creating objects out of them may seem like cheating, but
it’s not.
· When groups of variables are passed together, the way 'x' and 'y' are in the example above, they
are likely part of a concept that deserves a name of its own.
Argument Lists
· String.format(regex, Object)
· If the variable arguments are all treated identically, as they are in the example above, then they
are equivalent to a single argument of type List.
· Choosing good names for a function can go a long way toward explaining the intent of the
function and the order and intent of the arguments.
· Side effects are lies. Your function promises to do one thing, but it also does other hidden things
(ex. calling of initializeForm after login validation in same function)
Output Arguments:
· Anything that forces you to check the function signature is equivalent to a double-take. It’sa
cognitive break and should be avoided.
· If your function must change the stateof something, have it change the state of its owning
object.
· The real solution is to separate the command from the query so that the ambiguity cannot occur.
· Returning error codes from command functions is a subtle violation of command query
separation.
· This does not suffer from verb/adjective confusion, but does lead to deeply nested structures.
· When you return an error code, you create the problem that the caller must deal with the error
immediately.
· On the other hand, if you use exceptions instead of returned error codes, then the error
processing code can be separated from the happy path code
· They confuse the structure of the code and mix error processing with normal processing, so it is
better to extract the bodies of the Try/Catch blocks out into functions of their own.
· In the above, the delete function is all about error processing (it is easy to understand and then
ignore)
· Error handling can be ignored. This provides a nice separation that makes the code easier to
understand and modify
· Error handing is one thing. This, a function that handles errors should do nothing else.
· This implies (as in the example above) that if the keyword try exists in a function, it should be
the very first word in the function and that there should be nothing after the catch/finally blocks.
· Returning error codes usually implies that there is some class or enum in which all the error
codes are defined.
· Classes like this are a dependency magnet (many other classes must import and use them).
· This, when the Errorn enum changes, all those other classes need to be recompiled and
redeployed.
· Programmers don't want to add new errors because then they have to rebuild and redeploy
everything, so they reuseold error codes instead of adding new ones
· When you use exceptions rather than error codes, then new exceptions are derivatives of the
exception class.
· It’s not easy to spot duplication with other code and aren’t uniformly duplicated.
· Still, the duplication is a problem because it bloats the code.
· Many principles and practices have been created for the purpose of controlling or eliminating it
(such as Object Oriented Programming).
Structured Programming:
· Dijkstra said that every function, and every block within a function, should have one entry and
one exit.
· Following these rules means that there should only be one return statement in a function, no
break or continue statements in a loop, and never, ever, any goto statements.
· Writing software is like any other kind of writing (when you write a paper or an article, you get
your thoughts down first, then you massage it until it reads well).
· The first draft might be clumsy and disorganized, so you wordsmith it and restructure it and
refine it until it reads the way you want it to read.
· In the end, I wind up with functions that follow the rules I’ve laid down in this chapter.I don’t
write them that way to start. I don’t think anyone could.
Conclusion:
· Functions are the verbs of that language, and classes are the nouns.
· This is not some throwback to the hideous old notion that the nouns and verbs in a
requirements document are the first guess of the classes and functions of a system. Rather, this
is a much older truth.
· The art of programming is, and has always been, the art of language design.
· This chapter has been about the mechanics of writing functions well.
· If you follow the rules here in, your functions will be short, well named, and nicely organized.
But never forget that your real goal is to tell the story of the system, and that the functions you
write need to fit cleanly together into a clear and precise language to help you with that telling.
· Comments are not like Schindler’s List. They are not “pure good.” Indeed, comments are, at best,
a necessary evil
· The proper use of comments is to compensate for our failure to express ourself in code.
· Comments are always failures. We must have them because we cannot always figure out how to
express ourselves without them, but their use is not a cause for celebration
· Unfortunately the comments don’t always follow them— can’t always follow them, because of
code changing and envolving.
· Inaccurate comments are far worse than no comments at all. They delude and mislead.
· They set expectations that will never be fulfilled (they lay down old rules that need not, orshould
not, be followed any longer)
· Truth can only be found in one place and that place is the code. Only the code can truly tell you
what it does.
· One of the more common motivations for writing comments is bad code.
· We write a module and we know it is confusing and disorganized and we know it’s a mess, so we
say to ourselves, “Oh, I’d better comment that!”, No, you’d better to clean it!
· Clear and expressive code with few comments is far superior to cluttered and complex code with
lots of comments.
· Rather than spend your time writing the comments that explain the mess you’ve made, spend it
cleaning that mess.
· In many cases it’s simply a matter of creating a function that says the same thing as the
commentyou want to write
Legal Comments:
· Copyright and authorship statements are necessary and reasonable things to put into a
comment at the start of each source file.
· Comments like this should not be contracts or legal tomes (about not to 100 lines or more ...)
· Where possible, refer to a standard license or other external document rather than putting all
the terms and conditions into the comment
Informative Comments:
· It is sometimes useful to provide basic information with a comment, but in most scenarions it is
better to use good names or create a classes or methods
Explanation of Intent Comments (Objašnjava nameru kako je zamišljeno ili zašto to radi):
· Sometimes a comment goes beyond just useful information about the implementation and
provides the intent behind a decision.
· Sometimes it is just helpful to translate the meaning of some obscure argument or return value
into something that’s readable (in general it is better to find a way to make that argument or
return value clear in its own right), but when its part of the standard library (or in code that you
cannot alter), then a helpful clarifying comment can be useful
· This explains both why the clarification is necessary and why it’s risky.
· So before writing comments like this, take care that there is no better way, and then take even
more care that they are accurate.
· Nowadays, of course, we’d turn off the test case by using the @Ignore attribute with
anappropriate explanatory string.
TODO Comments:
· TODOs are jobs that the programmer thinks should be done, but for some reason can’t do at the
moment
· It might be a reminder to delete a deprecated feature or aplea for someone else to look at a
problem.
· Whatever else a TODO might be, it is not an excuse to leave bad code in the system.
· Nowadays, most good IDEs provide special gestures and features to locate all the TODO
comments, so it’s not likely that they will get lost.
Amplification Comments:
· A comment may be used to amplify the importance of something that may otherwise seem
inconsequential.
· If you are writing a public API, then you should certainly write good javadocs for it, but keep in
mind the rest of the advice in this chapter.
· Most comments fall into this category. Usually they are crutches or excuses for poor code or
justifications for insufficient decisions, amounting to little more than the programmer talking to
himself.
Mumbling:
· Plopping in a comment just because you feel you should or because the process requires it,is a
hack. If you decide to write a comment, then spend the time necessary to make sure itis the best
comment you can write.
· Any comment that forces you to look in another module for the meaning of that comment has
failed to communicate to you and is not worth the bits it consumes.
· Sometimes, with all the best intentions, a programmer makes a statement in his comments that
isn’t precise enough to be accurate. And this can make very big problems when other
programmer wants to use this peace of code
· It is just plain silly to have a rule that says that every function must have a javadoc, or every
variable must have a comment
· Comments like this just clutter up the code, propagate lies, and lend to general confusion and
disorganization
· This clutter adds nothing and serves only to obfuscate the code and create the potential for lies
and misdirection
Journal Comments:
· Sometimes people add a comment to the start of a module every time they edit it.
· These comments accumulate as a kind of journal, or log, of every change that has ever been
made.
· I have seen some modules with dozens of pages of these run-on journal entries.
· Long ago there was a good reason to create and maintain these log entries at the start of every
module.
· We didn’t have source code control systems that did it for us.
· Nowadays, however, these long journals are just more clutter to obfuscate the module and they
should be completely removed.
Noise Comments:
· Sometimes you see comments that are nothing but noise (such as 'give me a break').
· As we read through code, our eyes simply skip over them, eventually the comments begin to lie
as the code around them changes.
· Rather than venting in a worthless and noisy comment, the programmer should have recognized
that his frustration could be resolved by improving the structure of his code.
· Javadocs can also be noisy. What purpose do the following Javadocs (from a well-known open-
source library) serve? Answer: nothing.
· They are just redundant noisy comments written out of some misplaced desire to provide
documentation.
· There are rare times when it makes sense to gather certain functions together beneath a banner
like this, but in general they are clutter that should be eliminated — especially the noisy train of
slashes at the end.
· Think of it this way. A banner is startling and obvious if you don’t see banners very often, so use
them very sparingly, and only when the benefit is significant.
· If you over use banners, they’ll fall into the background noise and be ignored.
· Although this might make sense for long functions with deeply nested structures, it serves only
to clutter the kind of small and encapsulated functions that we prefer
· So if you find yourself wanting to mark your closing braces, try to shorten your functions instead.
· Source code control systems are very good at remembering who added what and when.
· You might think that such comments would be useful in order to help others know who to talk to
about the code, but the reality is that they tend to stay around for years and years, getting less
and less accurateand relevant.
Commented-Out Code:
· Others who see that commented-out code won’t have the courage to delete it.
· They’ll think it is there for a reason and is too important to delete.
· So commented-out code gathers like dregs (talog) at the bottom of a bad bottle of wine.
· There was a time, back in the sixties, when commenting-out code might have been useful.
· But we’ve had good source code control systems for a very long time now.
· Those systems will remember the code for us. We don’t have to comment it out any more. Just
delete the code. We won’t lose it. Promise.
HTML Comments:
· HTML in source code comments is an abomination, as you can tell by reading the code below.
· It makes the comments hard to read in the one place where they should be easy to read — the
editor/IDE
· If you must write a comment, then make sure it describes the code it appears near.
· Don’t put interesting historical discussion or irrelevant descriptions of details into your
comments.
· The connection between a comment and the code it describes should be obvious.
· If you are going to the trouble to write a comment, then at least you’d like the reader to be able
to look at the comment and the code and understand what the comment is talking about.
· The purpose of a comment is to explain code that does not explain itself. It is a pity when a
comment needs its own explanation.
Function Headers:
· A well-chosen name for a small function that does one thing is usually better than a comment
header.
Function Headers:
· As useful as javadocs are for public APIs, they are anathema to code that is not intended for
public consumption.
· Generating javadoc pages for the classes and functions inside a system is not generally useful,
and the extra formality of the javadoc comments amountsto little more than cruft and
distraction.
5) Formatting:
· When people look under the hood, we want them to be impressed with the neatness,
consistency, and attention to detail that they perceive.
· If instead they see a scrambled mass of code that looks like it was written by a bevy of drunken
sailors, then they are likely to conclude that the same in attention to detail pervades every other
aspect of the project
· You should choose a set of simple rules that govern the format of your code, and then you
should consistently apply those rules.
· If you are working on a team, then the team should agree to a single set of formatting rules and
all members should comply (it helps to have an automated tool that can apply those formatting
rules for you).
· Code formatting is important. It is too important to ignore and it is too important to treat
religiously.
· The functionality that you create today has a good chance of changing in the next release, but
the readability of your code will have a profound effect on all the change sthat will ever be
made.
· The coding style and readability set precedents that continue to affect maintainability and
extensibility long after the original code has been changed beyond recognition.
· Your style and discipline survives, even though your code does not
Vertical Formatting:
· It appears to be possible to build significant systems (FitNesse project is close to 50,000 lines)
out of files that are typically 200 lines long, with an upper limit of 500.
· Although this should not be a hard and fast rule, it should be consideredvery desirable.
· Small files are usually easier to understand than large files are.
· Think of a well-written newspaper article. You read it vertically. At the top you expect a headline
that will tell you what the story is about and allows you to decide whether it is something you
want to read.
· The first paragraph gives you a synopsis of the whole story, hiding all the details while giving you
the broad-brush concepts. As you continue down-ward, the details increase until you have all
the dates, names, quotes, claims and others
· We would like a source file to be like a newspaper article. The name should be simple, but
explanatory.
· The name, by itself, should be sufficient to tell us whether we are in the right module or not.
· The topmost parts of the source file should provide the high-level concepts and algorithms.
Detail should increase as we move downward, until at the end we find the lowest level functions
and details in the source file.
Vertical Openness Between Concepts (Empty line between two methods and classes):
· Nearly all code is read left to right and top to bottom. Each line represents an expression ora
clause, and each group of lines represents a complete thought.
· Those thoughts should be separated from each other with blank lines
· This extremely simple rule has a profound effect on the visual layout of the code.
· Each blank line is a visual cue that identifies a new and separate concept
Vertical Density:
· If openness separates concepts, then vertical density implies close association. So lines of code
that are tightly related should appear vertically dense (zbijen) and we need more head and eye
focus to achieve code.
Vertical Distance:
· Concepts that are closely related should be kept vertically close to each other
· Clearly this rule doesn’t work for concepts that belong in separate files, but then closely related
concepts should not be separated into different files unless you have a very good reason.
· Indeed, this is one of the reasons that protected variables should be avoided.
Variable Declarations:
· Control variables for loops should usually be declared within the loop statement
· In rare cases a variable might be declared at the top of a block or just before a loop in a long-ish
function.
Instance Variables:
· This should not increase the vertical distance of these variables, because in a well-designed
class, they are used by many, if not all, of the methods of the class
· The important thing is for the instance variables to be declared in one well-known place and
everybody will should know where to go to see the declarations.
Dependent Functions:
· If one function calls another, they should be vertically close, and the caller should be above the
called, if at all possible.
· This gives the program a natural flow. If the convention is followed reliably, readers will be able
to trust that function definitions will follow shortly after their use.
· It was better to pass that constant down from the place where it makes sense to know it to the
place that actually uses it
Conceptual Affinity:
· The stronger that affinity (veza), the less vertical distance there should be between them
· As we hav seen, this affinity might be based on a direct dependence, such as one function
calling another, or a function using a variable, but there are other possible causes of affinity.
· Affinity might be caused because a group of functions perform a similar operation.
Vertical Ordering:
· That is, a function that is called should be below a function that does the calling.
· This creates a nice flow down the source code module from high level to low level.
· As in newspaper articles, we expect the most important concepts to come first, and we expect
them to be expressed with the least amount of polluting detail and we expect the low-level
details to come last.
Horizontal Formatting:
· How wide should a line be? - It should not be longer than 80-120 characters per line
· Programmers clearly prefer short lines and this suggests that we should strive to keep our lines
short.
· I used to follow the rule that you should never have to scroll to the right, but monitors are too
wide for that nowadays, and younger programmers can shrink the font so small that they can
get 200 characters across the screen. Don’t do that.
· We use horizontal white space to associate things that are strongly related and disassociate
things that are more weakly related.
· Assignment statements have two distinct and major elements: the left side and the right side.
The spaces make that separation obvious (jasnom).
· On the other hand, I didn’t put spaces between the function names and the opening
parenthesis.
· This is because the function and its arguments are closely related. Separating them makes them
appear disjoined instead of conjoined.
· I separate arguments within the function call parenthesis to accentuate the comma and show
that the arguments are separate.
Horizontal Alignment:
· The code should be aligned on left side without unnecessary white spaces
Indentation:
· There is information that pertains to the file as a whole, to the individual classes within the file,
to the methods within the classes, to the blocks within the methods, and recursively to the
blocks within the blocks.
· Each level of this hierarchy is a scope into which names can be declared and in which
declarations and executable statements are interpreted.
· To make this hierarchy of scopes visible, we indent the lines of source code in pro-portion to
their position in the hiearchy.
· Statements at the level of the file, such as mostclass declarations, are not indented at all.
· Methods within a class are indented one levelto the right of the class.
· Implementations of those methods are implemented one level tothe right of the method
declaration.
· Block implementations are implemented one level to the right of their containing block, and so
on
· Programmers rely heavily on this indentation scheme. They visually line up lines on the left to
see what scope they appear in.
· This allows them to quickly hop over scopes, such as implementations of if or while statements,
that are not relevant to their current situation.
· Your eye can rapidly discern the structure of the indented file.
· You can almost instantly spot the variables, constructors, accessors, and methods.
· It takes just a few seconds to realize that this is some kind of simple front end to a socket, with a
time-out. The unindented version, however, is virtually impenetrable without intense study.
Breaking Indentation:
· It is sometimes tempting to break the indentation rule for short if statements, short while loops,
or short functions. Whenever I have succumbed to this temptation, I have almost always gone
back and put the indentation back in. So I avoid collapsing scopes.
Dummy Scopes:
· Sometimes the body of a while or for statement is a dummy, as shown below. I don’t like these
kinds of structures and try to avoid them.
· When I can’t avoid them, I make sure that the dummy body is properly indented and surrounded
by braces.
Team Rules:
· Every programmer has his own favorite formatting rules, but if he works in a team, then the
'team rules'.
· A team of developers should agree upon a single formatting style, and then every member of
that team should use that style.
· We want the software to have a consistent style. We don’t want it to appear to have been
written by a bunch of disagreeing individuals.
· The reader needs to be able to trust that the formatting gestures he or she has seen in one
source file will mean the same thing in others.
· There is a reason that we keep our variables private. We don’t want anyone else to depend on
them.
· Why, then, do so many programmers automatically add getters and setters to their objects,
exposing their private variables as if they were public?
Data Abstraction:
· A class does not simply push its variables out throug getters and setters.
· Rather it exposes abstract interfaces that allow its users to manipulate the essence of the data,
without having to know its implementation.
· This is not merely accomplished by using interfaces and/or getters and setters.
· Serious thought needs to be put into the best way to represent the data that an object contains.
Encapsulation:
· In object oriented computer programming languages, the notion of encapsulation (or OOP
Encapsulation) refers to the bundling of data, along with the methods that operate on that data,
into a single unit.
· Encapsulation may also refer to a mechanism of restricting the direct access to some
components of an object, such that users cannot access state values for all of the variables of a
particular object.
· Encapsulation can be used to hide both data members and data functions or methods associated
with an instantiated class or object.
Polymorphism:
· In computer science, it describes the concept that objects of different types can be accessed
through the same interface. Each type can provide its own, independent implementation of this
interface.
· If you’re wondering if an object is polymorphic, you can perform a simple test. If the object
successfully passes multiple is-a or instanceof tests, it’s polymorphic.
· Static polymorphism - Method overloading (Two same function names with different set of
parameters)
Data/Object Anti-Symmetry:
· Objects hide theirdata behindabstractions and expose functions that operate on that data.
· They are virtual opposites. This difference may seem trivial, but it has far-reaching implications
· Object-oriented programmers might wrinkle (zadići) their noses at this and complain that it is
procedural — and they’d be right, but the sneer may not be warranted.
· Procedural code (code using data structures) makes it easy to add new functions without
changing the existing data structures.
· Object Oriented code, on the other hand, makes it easy to add new classes without changing
existing functions
· Procedural code makes it hard to add new data structures because all the functions must
change.
· Object Oriented code makes it hard to add new functions because all the classes must change
· So, the things that are hard for OOP are easy for procedures, and the things that are hard for
procedures are easy for OOP!
· In any complex system there are going to be times when we want to add new data types rather
than new functions (for these OOP are most appropriate)
· On the other hand, there will also be times when we’ll want to add new functions as opposed to
data types. In that case procedural coding will be more appropriate.
· Mature (zreli) programmers know that the idea that everything is an object is a myth.
· Sometimes you really do want simple data structures with procedures operating on them
· There is a well-known heuristic called the Law of Demeter that says 'a module should not know
about the innards(unutrašnjost) of the objects it manipulates'
· The method should not invoke methods on objects that are returned by any of the allowed
functions. In other words, talk to friends, not to strangers.
Hybrids:
· This confusion sometimes leads to unfortunate hybrid structures that are half object and half
data structure.
· They have functions that do significant things, and they also have either public variables or
public accessors and mutators that, for all intents and purposes, make the private variables
public, tempting other external functions to use those variables the way a procedural program
would use a data structure.
· Hybrids make it hard to add new functions, but also make it hard to add new data structures.
They are the worst of both worlds, so avoid creating them.
Hiding Structure:
· This allows variables to hide its internals and prevents the current function from having to
violate the Law of Demeter by navigating through objects it shouldn’t know about
· The quintessential form of a data structure is a class with public variables and no functions.
· Data Transfer Objects are very useful structures, especially when communicating with databases
or parsing messages from sockets, and so on
· They often become the first in a series of translation stages that convert raw data in a database
into objects in the application code.
Active Record:
· They are data structures with public (or bean-accessed) variables, but they typically have
navigational methods like 'save' and 'find'.
· Unfortunately we often find that developers try to treat these data structures as though they
were objects by putting business rule methods in them.
· This is awkward because it creates a hybrid between a data structure and an object.
· The solution, of course, is to treat the Active Record as a data structure and to create separate
objects that contain the business rules and that hide their internal data (which are probably just
instances of the Active Record).
Conclusion:
· This makes it easy to add new kinds of objects without changing existing behaviors.
· Data structures expose data and have no significant behavior. This makes it easy to add new
behaviors to existing data structures but makes it hard to add new data structures to existing
functions
7) SOLID Principles:
· In software engineering, SOLID is a mnemonic acronym for five design principles intended to
make software designs more understandable, flexible, and maintainable.
· The principles are a subset of many principles promoted by American software engineer and
instructor Robert C. Martin
· Although the SOLID principles apply to any object-oriented design, they can also form a core
philosophy for methodologies such as agile (agilnom) development or adaptive software
development.
· First principle of SOLID is 'Single Responsibility Principle (SRP)' and that is a computer-
programming principle that states that every module, class or function in a computer program
should have responsibility over only a single part of that program's functionality (do only one
exact thing), and it should encapsulate that part.
· Second principle of SOLID is 'Open Closed Principle (OCP)' and in object-oriented programming,
the open–closed principle states software entities (classes, modules, functions, etc.) should be
open for extension, but closed for modification. That is, such an entity can allow its behaviour to
be extended without modifying its source code
· Third principle of SOLID is 'Liskov Substituon Principle (LSP)' and we should be able to replace
the parent class and the inheriting class and there should be not a problem (in essence, it should
be possible for successor (child class) class lenses to behave like superclass (parent class)
objects)
· Fourth principle of SOLID is 'Interface Segregation Principle (ISP)' and in the field of software
engineering, the interface-segregation principle (ISP) states that no client should be forced to
depend on methods it does not use. ISP splits interfaces that are very large into smaller and
more specific ones so that clients will only have to know about the methods that are of interest
to them. Such shrunken interfaces are also called role interfaces. ISP is intended to keep a
system decoupled and thus easier to refactor, change, and redeploy.
· Fifth principle of SOLID is 'Dependency Inversion Principle (DIP)' and that means the abstraction
should be used instead of concrete implementation because abstraction does not depend on
details, but details depend on abstraction, relieves the application (High-level modules should
not depend on low-level modules. Both should depend on abstractions (e.g., interfaces) and
abstractions should not depend on details. Details (concrete implementations) should depend
on abstractions).
References: