0% found this document useful (0 votes)
3 views67 pages

Clean Code

The document discusses the importance of writing clean code, emphasizing that it requires practice, observation of others, and understanding the consequences of bad code. It outlines principles for clean code, such as using meaningful names, avoiding duplication, and ensuring functions do one thing, while also highlighting the pitfalls of comments and the need for clarity in code. Overall, it advocates for a disciplined approach to coding to enhance readability and maintainability.

Uploaded by

marcioromualdo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views67 pages

Clean Code

The document discusses the importance of writing clean code, emphasizing that it requires practice, observation of others, and understanding the consequences of bad code. It outlines principles for clean code, such as using meaningful names, avoiding duplication, and ensuring functions do one thing, while also highlighting the pitfalls of comments and the need for clarity in code. Overall, it advocates for a disciplined approach to coding to enhance readability and maintainability.

Uploaded by

marcioromualdo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 67

By Marcio Romualdo da Silva

Clean Code
● Learning to write clean code is hard work.
● It requires more than just the knowledge of principles and patterns.
● You must practice it yourself, and watch yourself fail.

● You must watch others practice it and fail.


● You must see them stumble and retrace their steps.
Bad Code
● Why did you write it bad code?

● Were you trying to go fast? Were you in a rush?

● Perhaps you felt that you didn’t have time to do a good job; that your boss
would be angry with you if you took the time to clean up your code.

● Perhaps you were just tired of working on the project and wanted it to be
over.

● Or maybe you looked other stuff that you had promised to get done and
the time was short.
The Total Cost of Owning a Mess

● As the mess builds, the productivity of the team continues to decrease,


approaching zero.

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.

Furthermore, they, and everyone else on the team, are under horrific pressure
What Is Clean Code?
● simple and direct

● readable

● elegant and efficient

● with dependencies minimal to ease maintenance

● with meaningful names

● contains no duplication
Meaningful Names - Use Intention-Revealing Names
● Compare:
int d; // elapsed time in days

● To:
int elapsedTimeInDays;
Meaningful Names - Use Intention-Revealing Names
● What is the purpose of this code?

public List getThem() {


List list1 = new ArrayList();
for (int[] x : theList) {
if (x[0] == 4) {
list1.add(x);
}
}
return list1;
}
Meaningful Names - Use Intention-Revealing Names
● We can improve the code considerably:

public List getFlaggedCells() {


List flaggedCells = new ArrayList();
for (int[] cell : gameBoard) {
if (cell[STATUS_VALUE] == FLAGGED) {
flaggedCells.add(cell);
}
} return flaggedCells;
}
Meaningful Names - Make Meaningful Distinctions
● Number-series naming (a1, a2, .. aN) is the opposite of intentional naming.

public static void copyChars(char a1[], char a2[]) {


for (int i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
Meaningful Names - Make Meaningful Distinctions
● This function reads much better when source and destination are used for
the argument names.

public static void copyChars(char source[], char destination[]) {


for (int i = 0; i < source.length; i++) {
destination[i] = source[i];
}
}
Meaningful Names - Use Pronounceable Names
● Compare:
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
/* ... */
}

● To:
class Customer {
private Date generationDate;
private Date modificationDate;
private final String recordId = "102";
/* ... */
}

● Intelligent conversation is now possible: “Hey, Michael, take a look at this record!
Meaningful Names - Use Searchable Names
● If a variable or constant might be seen or used in multiple places in a body
of code, it is imperative to give it a search-friendly name.

● Compare:
int s = 0;
for (int j=0; j<10; j++) {
s += (t[j])/5;
}

● To:
int NUMBER_TASKS = 10;
int sum = 0;
for (int j=0; j < NUMBER_TASKS; j++) {
sum += (taskEstimate[j]) / WORK_DAYS_PER_WEEK;
}

● The intentionally named code makes for a longer function, but consider
Meaningful Names - Avoid Encodings
● Hungarian Notation (sName, iAge, etc)
● Java programmers don’t need type encoding.

● Nowadays HN and other forms of type encoding are simply impediments.


They make it harder to change the name or type of a variable, function, or
class.

● They make it harder to read the code. And they create the possibility that
the encoding system will mislead the reader.

● PhoneNumber phoneString;
// name not changed when type changed!
Meaningful Names - Prefixes
● You also don’t need to prefix variables anymore.

● Compare:
public class Part {
private String m_dsc; // The textual description
void setName(String name) {
m_dsc = name;
}
}

● To:
public class Part {
String description;
void setDescription(String description) {
this.description = description;
}
}

● 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.
Functions
● The functions should be small.

● Transparently obvious.

● Do one thing.
Functions
● FUNCTIONS SHOULD DO ONE THING.

● One 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.
Functions - Use Descriptive Names
● Don’t be afraid to make a name long.
● A long descriptive name is better than a short enigmatic name.
● A long descriptive name is better than a long descriptive comment.

● Don’t be afraid to spend time choosing a name. You should try different
names and read the code again.
● Modern IDEs like Eclipse (Alt+Shift+R) make it trivial to change names.

● Choosing descriptive names will clarify the design of the module in your
mind and help you to improve it.
Functions - Function Arguments
● The ideal number of arguments for a function is zero.

● Next comes one, followed closely by two.

● Three arguments should be avoided where possible.

● More than three requires very special justification.

● Arguments are even harder from a testing point of view. Imagine the
difficulty of writing all the test cases to ensure that all the various
combinations of arguments work properly.
Functions - Flag Arguments
● Flag arguments are ugly. Passing a boolean into a function is a terrible
practice.

● 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!

● The method call render(true) is just plain confusing to a poor reader.


Mousing over the call and seeing render(boolean isSuite) helps a little, but
not that much.

● We should have split the function into two: renderForSuite() and


renderForSingleTest().
Functions - Argument Objects
● When a function seems to need more than two or three arguments, it is
likely that some of those arguments ought to be wrapped into a class of
their own.

● Compare:
Circle makeCircle(double x, double y, double radius);

● To:
Circle makeCircle(Point center, double radius);
Functions - Have No Side Effects
● Side effects are lies. Your function promises to do one thing, but it also does other hidden
things.

public class UserValidator {


private Cryptographer cryptographer;

public boolean checkPassword(String userName, String password) {


User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
session.initialize();
return true;
}
}
return false;
}
}

● The side effect is the call to session.initialize(), of course.


Functions - Have No Side Effects
● The checkPassword function, by its name, says that it checks the
password. The name does not say that it initializes the session. So a caller
who believes what the name of the function says runs the risk of erasing
the existing session data when to check the password of the user.

● This side effect creates a temporal coupling. That is, checkPassword can
only be called at certain times. If it is called out of order, session data may
be lost.

● If you must have a temporal coupling, you should make it clear in the name
of the function. In this case we might rename the function
checkPasswordAndInitializeSession, though that certainly violates “Do one
thing.”
Functions - Don’t Repeat Yourself
● Duplication may be the root of all evil in software. Many principles and
practices have been created for the purpose of controlling or eliminating it.

● Design Patterns, Spring Framework, DisplayTag, Prototype Javascript


Framework, are all, in part, strategies for eliminating duplication.
Functions - How to Write Functions
● When I write functions, they come out long and complicated.
● They have lots of indenting and nested loops.
● They have long argument lists.
● The names are arbitrary, and there is duplicated code.

● So then I refine the code,


● splitting out functions,
● changing names,
● eliminating duplication.
Comments
● The proper use of comments is to compensate for our failure to express
ourself in code.

● Comments lie. Not always, and not intentionally, but too often. .

● The reason is simple. Programmers can’t realistically maintain them.


Comments - Do Not Make Up for Bad Code
● One of the more common motivations for writing comments is bad code.

● We write a module and we know it is confusing and disorganized. We


know it’s a mess. So we say to ourselves, “Ooh, I’d better comment that!”

● No! You’d better clean it!

● Rather than spend your time writing the comments that explain the mess
you’ve made, spend it cleaning that mess.
Comments - Explain Yourself in Code
● Compare:
// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

● to:
if (employee.isEligibleForFullBenefits())

● It takes only a few seconds of thought to explain most of your intent in


code.

● In many cases it’s simply a matter of creating a function that says the
same thing as the comment you want to write.
Comments - Good Comments
● Some comments are necessary or beneficial.

--Legal Comments
Sometimes our corporate coding standards force us to write certain
comments for legal reasons.

// Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.


// Released under the terms of the GNU General Public License version 2 or
later.
Comments - Good Comments
--Explanation of Intent

// This is our best attempt to get a race condition


// by creating large number of threads.
for (int i = 0; i < 25000; i++) {
WidgetBuilderThread widgetBuilderThread =
new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}

● You might not agree with the programmer’s solution to the problem, but at
least you know what he was trying to do.
Comments - Good Comments
-- Clarification

● Sometimes it is just helpful to translate the meaning of some obscure code


into something that’s readable.

assertTrue(a.compareTo(b) == 0); // a == b
assertTrue(a.compareTo(b) != 0); // a != b
assertTrue(a.compareTo(b) == -1); // a < b
assertTrue(b.compareTo(a) == 1); // b > a

● There is a substantial risk, of course, that a clarifying comment is incorrect.


So take care that they are accurate.
Comments - Good Comments
-- Warning of Consequences

● Sometimes it is useful to warn other programmers about certain


consequences.

public static SimpleDateFormat makeStandardHttpDateFormat() {


// SimpleDateFormat is not thread safe,
// so we need to create each instance independently.
SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
Comments - Good Comments
-- TODO Comments

● It is sometimes reasonable to leave “To do” notes in the form of //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 a please for


someone else to look at a problem.

● It might be reminder to make a change that is dependent on a planned


event.

● Whatever else a TODO might be, it is not an excuse to leave bad code in
the system.
Comments - Good Comments
-- Amplification

● A comment may be used to amplify the importance of something that may


otherwise seem inconsequential.

String listItemContent = match.group(3).trim();


// the trim is real important. It removes the starting
// spaces that could cause the item to be recognized as another list.
Comments - Good Comments
-- Javadocs in Public APIs

● There is nothing quite so helpful and satisfying as a well-described public


API.

● The javadocs for the standard Java library are a case in point.

● It would be difficult to write Java programs without them.

● 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 presentation:


● Javadocs can be just as misleading and dishonest as any other kind of
comment.
Comments - Bad Comments
● Most comments fall into this category.

● Usually they are excuses for poor code or justifications for insufficient
decisions.
Comments - Bad Comments
-- Redundant Comments

// Utility method that returns when this.closed is true. Throws an exception


// if the timeout is reached.
public synchronized void waitForClose(long timeoutMillis) throws Exception {
if (!closed) {
wait(timeoutMillis);
if (!closed)
throw new Exception("MockResponseSender could not be closed");
}
}

● The comment probably takes longer to read than the code itself.
Comments - Bad Comments
-- Misleading Comments

● 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.

/**
*
* @param title The title of the CD
* @param author The author of the CD
* @param tracks The number of tracks on the CD
* @param durationInMinutes The duration of the CD in minutes
*/
public void addCD(String title, String author, int tracks, int durationInMinutes) {
CD cd = new CD();
cd.title = title;
cd.author = author;
cd.tracks = tracks;
cd.duration = duration;
cdList.add(cd);
}

Comments like this just propagate lies, confusion and disorganization.


Comments - Bad Comments
-- 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.

* Changes (from 11-Oct-2001)


* --------------------------
* 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
* 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 13-Mar-2003 : Implemented Serializable (DG);
* 29-May-2003 : Fixed bug in addMonths method (DG);
* 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
* 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);

● 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, they should be completely removed.
Comments - Bad Comments
-- Noise Comments

● Sometimes we see comments that are nothing but noise. They restate the obvious and provide no new
information.

/**
* Default constructor.
*/
protected AnnualDateRule() {
}

/** The day of the month. */


private int dayOfMonth;

/**
* Returns the day of the month.
*
* @return the day of the month.
*/
public int getDayOfMonth() {
Comments - Bad Comments
-- Attributions and Bylines

/* Created by Marcio Silva */


/* Added by Marcio Silva */

● Source code control systems are very good at remembering who added
what, when.

● There is no need to pollute the code with little bylines.


Comments - Bad Comments
-- Commented-Out Code

● Few practices are as odious as commenting-out code. Don’t do this!

InputStreamResponse response = new InputStreamResponse();


response.setBody(formatter.getResultStream(), formatter.getByteCount());
// InputStream resultsStream = formatter.getResultStream();
// StreamReader reader = new StreamReader(resultsStream);

● 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 not delete it.

● Why are those two lines of code commented? Are they important? Were they left
as reminders for some imminent change? Or are they just cruft that someone
commented-out years ago and has simply not bothered to clean up?

● Nowadays, we’ve good source code control systems. 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.
Comments - Bad Comments
-- Too Much Information

● Don’t put interesting historical discussions or irrelevant descriptions of details into your comments. The
comment below was extracted from a module designed to test that a function could encode and
decode base64.
● Someone reading this code has no need for the arcane information contained in the comment.
/*
RFC 2045 - Multipurpose Internet Mail Extensions (MIME)
Part One: Format of Internet Message Bodies
section 6.8. Base64 Content-Transfer-Encoding
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
When encoding a bit stream via the base64 encoding, the bit stream
must be presumed to be ordered with the most-significant-bit first.
That is, the first bit in the stream will be the high-order bit in
the first 8-bit byte, and the eighth bit will be the low-order bit in
the first 8-bit byte, and so on.
Formatting
● We should take care that our code is nicely formatted.

● We should choose a set of simple rules to format our code, and


consistently apply those rules.

● If we are working on a team, then the team should agree to a single set of
formatting rules and all members should comply.
Formatting
---The Purpose of Formatting

● First of all, let’s be clear. Code formatting is very important.

● Code formatting is about communication, and communication is the


professional developer’s first order of business.

● Perhaps we thought that “getting it working” was the first order of business
for a professional developer.

● The functionality that we create today has a good chance of changing in


the next release, but the readability of our code will have a profound effect
on all the changes that will ever be made.
Formatting
--- Vertical Openness Between Concepts

● Nearly all code is read left to right and top to bottom.

● Each line represents an expression or a clause, and each group of lines


represents a complete thought.

● Those thoughts should be separated from each other with blank lines.
Formatting
● Compare:

package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));
}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
Formatting
● To:
package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {


public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
Pattern.MULTILINE + Pattern.DOTALL
);

public BoldWidget(ParentWidget parent, String text) throws Exception {


super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));
}

public String render() throws Exception {


StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
Formatting
-- Dependent Functions

● If one function calls another, they should be vertically close, and the caller
should be above the callee, 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.
Formatting
public class WikiPageResponder implements SecureResponder {

public Response makeResponse(FitNesseContext context, Request request) throws Exception {
String pageName = getPageNameOrDefault(request, "FrontPage");

loadPage(pageName, context);
if (page == null) {
return notFoundResponse(context, request);
} else {
return makePageResponse(context);
}
}
private String getPageNameOrDefault(Request request, String defaultPageName) {
return …
}

protected void loadPage(String resource, FitNesseContext context) throws Exception {


….
}
private Response notFoundResponse(FitNesseContext context, Request request) throws Exception {
return …
}
private SimpleResponse makePageResponse(FitNesseContext context) throws Exception {
return …
}
Formatting
-- Horizontal Formatting

● The rule is: we should never have to scroll to the right.

● Nowadays, the monitors are too wide, that we can get 120 or more
characters across the screen.
Formatting
-- Horizontal Alignment

● We used horizontal alignment to accentuate certain structures. Line up all the variable names in a set of declarations,
or all the values in a set of assignment statements.
● In Java, this kind of alignment is not useful.

● Compare:

public class FitNesseExpediter implements ResponseSender {


private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;
public FitNesseExpediter(Socket s, FitNesseContext context) throws Exception {
this.context = context;
socket = s;
input = s.getInputStream();
output = s.getOutputStream();
requestParsingTimeLimit = 10000;
}
Formatting
● To:

public class FitNesseExpediter implements ResponseSender {


private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;

public FitNesseExpediter(Socket s, FitNesseContext context) throws Exception {


this.context = context;
socket = s;
input = s.getInputStream();
output = s.getOutputStream();
requestParsingTimeLimit = 10000;
}
...
Formatting
-- Indentation

● Compare:
public class FitNesseServer implements SocketServer { private FitNesseContext
context; public FitNesseServer(FitNesseContext context) { this.context =
context; } public void serve(Socket s) { serve(s, 10000); } public void
serve(Socket s, long requestTimeout) { try { FitNesseExpediter sender = new
FitNesseExpediter(s, context);
sender.setRequestParsingTimeLimit(requestTimeout); sender.start(); }
catch(Exception e) { e.printStackTrace(); } } }

● To:
public class FitNesseServer implements SocketServer {
private FitNesseContext context;

public FitNesseServer(FitNesseContext context) {


this.context = context;
}
public void serve(Socket s) {
serve(s, 10000);
}
public void serve(Socket s, long requestTimeout) {
try {
FitNesseExpediter sender = new FitNesseExpediter(s, context);
sender.setRequestParsingTimeLimit(requestTimeout);
sender.start();
} catch (Exception e) {
e.printStackTrace();
Formatting
-- Breaking Indentation

● It is sometimes tempting to break the indentation rule for short if


statements, short while loops, or short functions.

● Compare:

public class Example {


public String getBackPage() { if (isLogged()) { return “/main”; } return “/login”; }
public long getAmountTotal() {
long total = 0;
for(int i=0;i++;i>list.size()) total+=list[i];
return total;
}
public String render() throws Exception {return ""; }
}
Formatting
● To:
public class Example extends SuperClass {
public String getBackPage() {
if (isLogged()) {
return “/main”;
}

return “/login”;
}

public long getAmountTotal() {


long total = 0;

for (int i=0;i++;i>list.size()) {


total+=list[i];
}

return total;
}

public String render() throws Exception {


return "";
}
Formatting
-- Team Rules

● Every programmer has his own favorite formatting rules, but if he works in
a team, then should follow 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.


Objects and Data Structures
● Procedural Code:
● The shape classes are simple data structures without any behavior.
● Data structure expose their data and have no meaningful functions.

public class Square {


public Point topLeft;
public double side;
}

public class Rectangle {


public Point topLeft;
public double height;
public double width;
}

public class Circle {


private Point center;
private double radius;

public void setCenter(Point center) {


this.center = center;
}
public Center getCenter() {
return center;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
Objects and Data Structures
● All the behavior is in the Geometry class.

public class Geometry {


public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException {
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
} else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}
}
Objects and Data Structures
● Polymorphic code:
● Now consider the object-oriented solution.

public class Square implements Shape {


private Point topLeft;
private double side;
public double area() {
return side*side;
}
}
public class Rectangle implements Shape {
private Point topLeft;
private double height;
private double width;
public double area() {
return height * width;
}
}
public class Circle implements Shape {
private Point center;
private double radius;
public final double PI = 3.141592653589793;
public double area() {
return PI * radius * radius;
}
}

● Here the area() method is polymorphic.


● No Geometry class is necessary.
● Objects hide their data behind abstractions and expose functions that operate on that data.
Objects and Data Structures
● Objects expose behavior and hide data.
● This makes it easy to add new kinds of objects without changing existing
behaviors.

● Easy:
public class Triangle implements Shape {
private Point topLeft;
private double side;
public double area() {
return (side*side) / 2;
}
}

Hard:
● It makes it hard to add new behaviors to existing objects.
perimeter() ?
Objects and Data Structures
● Data structures expose data and have no significant behavior.
● This makes it easy to add new behaviors to existing data structures.
● It makes it hard to add new data structures to existing functions.

public class Geometry {


public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException {
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
} else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}

public double perimeter(Object shape) throws NoSuchShapeException {


if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * 4;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width * 2;
} else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * 2;
}
throw new NoSuchShapeException();
}
Objects and Data Structures
● Hybrids
● Hybrid structures are half object and half data structure.

● They have functions that do significant things, and they also have either
public variables or public gets and sets that make the private variables
public.

● Other external functions to use those variables as data structure.

● Such hybrids make it hard to add new functions and also make it hard to
add new data structures.

● They are the worst of both worlds. Avoid creating them.


Classes
● Classes Should Be Small

● With functions we measured size by counting physical lines.


● With classes we use a different measure. We count responsibilities.

● Classes should have one responsibility - one reason to change.

public class ExampleServlet extends HttpServlet {


public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
… get parameters…

List resultCentral = ExampleTrx.execute();


List resultDB = ExampleDAO.selectLot(operationId);

….set session…

}
}
Classes
● The problem is that too many of us think that we are done once the
program works.

● We fail to switch to the other concern of organization and cleanliness.

● We move on to the next problem rather than going back and breaking the
classes into decoupled units with single responsibilities.
Classes
● Organizing for Change
● For most systems, change is continual.

● Every change subjects us to the risk that the remainder of the system no
longer works as intended.

● In a clean system we organize our classes to reduce the risk of change.

● Compare:
public class LotDao {
public long insertLot(header, details)
public List selectLot(operationId)
public List selectLots(initialDate, finalDate, account)
public boolean updateLot(header. details, operationId)
public boolean deleteLot(operationId)
public boolean deleteLots(operationIds)
….
}
Classes
● To:
public class InsertLotDao {
public long insertLot(header, details)

}
public class SelectLotDao {
public List selectLot(operationId)
public List selectLots(initialDate, finalDate, account)

}
public class UpdateLotDao {
public boolean updateLot(header. details, operationId)

}
public class DeleteLotDao {
public boolean deleteLot(operationId)
public boolean deleteLots(operationIds)

Fim

Thank you very much! 

You might also like