Best Practices Contents Bad Practices Good Practices Bad
Best Practices
Contents • Bad Practices • Good Practices
Bad Practices
Duplicate Code! • Every time you need to make a change in the routine, you need to edit it in several places. – Called “Shotgun Surgery”. • Follow the “Once and Only Once” rule. • Don’t copy-paste code!
Accessible Fields • Fields should always be private except for constants. • Accessible fields cause tight coupling. • Accessible fields are corruptible. • If a field needs to be accessed, use “get” and “set” convention.
Using Magic Numbers • Magic numbers are not readable, and can lead to “Shotgun Surgery”. for (int i = 1; i =< 52; i++) { j = i + random. Int(53 - i) – 1 swap. Entries(i, j) } • Replace with constants. final int DECKSIZE = 52; for (int i = 1; i =< DECKSIZE; i++) { j = i + random. Int(DECKSIZE + 1 - i) – 1 swap. Entries(i, j) }
Temporary Fields • If a variable need not be shared across methods, make it local. private int x; int method() { x = 0; // if you forget to initialize, you're dead. . . // do some stuff return x; } int method() { int x = 0; . . . // do some stuff return x; }
Initializing Strings with “new” • Don’t: String str = new String(“This is bad. ”); • Do: String str = “This is good. ”;
Using floats and doubles for currency calculations • Binary numbers cannot exactly represent decimals. • Use Big. Decimal for currency calculations. –. . . using the constructor that takes a String as a parameter.
Returning null • Causes Null. Pointer. Exceptions. • Instead, return… – empty objects – custom-made “Null Objects”
Subclassing for Functionality • Implementation inheritance is difficult to debug. • Ask yourself: “Is this a kind of…? ” • Alternatives: – Prefer interface inheritance. – Prefer composition over inheritance.
Empty Catch Block • No indication that an exception has occurred!
Using Exceptions Unexceptionally • Use exceptions only for exceptional conditions. • Bad: try { obj = arr[index]; } catch (Array. Index. Out. Of. Bounds. Exception) { // do something } • Good: if (index < 0 || index >= arr. size()) { // do something } else { obj = arr[index]; }
Excessive Use of Switches • Use of “if” and “switch” statements usually a sign of a breach of the “One Responsibility Rule”. • Consider polymorphism instead.
instanceof • If you’re using instanceof often, it probably means bad design. • Consider adding an overridden method in supertype. • instanceof should only be used – as validation prior to casting – when you have to used a poorly-written library
Static Methods • Static methods are. . –. . . procedural • They break encapsulation - the method should be part of the object that needs it –. . . not polymorphic • You can't have substitution/pluggability. – You can't override a static method because the implementation is tied to the class it's defined in. • Makes your code rigid, difficult to test.
System. exit • Only use in stand-alone applications. • For server applications, this might shut down the whole application container!
Good Practices
Validate Your Parameters • The first lines of code in a method should check if the parameters are valid: void my. Method(String str, int index, Object[] arr) { if (str == null) { throw new Illegal. Argument. Exception(“str cannot be null”); } if (index >= arr. size || index < 0) { throw new Illegal. Argument. Exception(“index exceeds bounds of array”); } … }
Create Defensive Copies • Create local copies, to prevent corruption. void my. Method (List list. Parameter) { List list. Copy = new Array. List(list. Parameter); list. Copy. add(somevar); . . . }
Modify Strings with String. Builder • String objects are immutable. – You may think you’re changing a String, but you’re actually creating a new object. – Danger of Out. Of. Memory. Errors. – Poor peformance. • String. Builder is mutable. – All changes are to the same object.
Favor Immutability • If your objects don’t change… easier to debug. • Fields are private and final. • No setters, only getters.
Prefer “final” for Variables • Usually, variables / parameters do not need to change. • Get into the habit of using final by default, and make a variable not final only when necessary.
Declare Variable Just Before Use • Easier to read and refactor.
Initialize Variables Whenever Possible • Helpful in debugging, makes it clear what initial value is. • Makes sure you don’t use the variable before it’s ready for use.
Follow Code Conventions • Improves readability – For other programmers. – For yourself. • Readability means… – …less bugs. – …easier to debug.
Refer to Objects by Interfaces • Maintainability - changes in implementation need only be done at a single point in code • Polymorphism – implementation can be set at runtime. // bad: Array. List list = new Array. List(); list. add(somevar); // good: List list = new Array. List(); list. add(somevar);
Consider Using Enums instead of Constants • Constants: – Not typesafe – No namespace • You often need to prefix constants to avoid collisions – Brittleness • When you change the order, you need to change a lot of code. – Printed values are uninformative
Buffer I/O Streams • Requesting OS for I/O resources is expensive. • Buffering provides significant increase in performance.
Close Your I/O Streams • If you don’t close, other applications may not be able to use the resource. • Close using the “finally” block in a try-catch.
Design Close to Domain • Code is easily traceable if it is close to the business it is working for. • If possible, name and group your packages according to the use cases. – Easy to tell client %completion of feature. – If user reports a bug, easier to find where it is.
If You Override equals() Override hashcode() • Always make sure that when equals() returns true, the two object have the same hashcode. • Otherwise, data structures like Sets and Maps may not work. • There are many IDE plug-ins and external libraries that can help you with this.
Write Self-Documenting Code • Comments are important, but… • …even without comments your code should be easily readable. • Ask yourself: “If I removed my comments, can someone else still understand my code? ”
Use Javadoc Liberally • Provide as much documentation about your code as possible.
Bubble-Up Exceptions • If code is not part of the user interface, it should not handle its own exceptions. • It should be bubbled-up to presentation layer… • • Show a popup? Show an error page? Show a commandline message? Just log to an error log?
References • “Effective Java” by Joshua Bloch • Refactoring by Martin Fowler • http: //javapractices. com
- Slides: 38