Monday, November 3, 2008

40 Tips for better Programming

How to code better? I collected some tips about self-improvement for programmers. Tips are ordered in no particular order and divided into seven categories.

It was hard, but I excluded some cool tips for sake of simplicity. I didn't mention tricks for programming concurrent software, scalable software, and many more. Optimization tricks were unfairly omitted too.

General tips

These tips are a philosophical counterpart to the rest of this article.

Use priority queue to implement user's requirements. - It is better to implement high priority features or the hardest features first. It minimizes risks of being stuck in the middle of the project.

Fix bugs before writing new code. This is a special case of the first tip. Read more...

Improve yourself. Read books and blogs. There is always something new and useful to read out there.

Have quiet working conditions. It is scientifically proved that you can improve your productivity just by removing distractions. Quite workplace is just the most typical example of this method.

Minimize your work. It is obviously beneficial. Every following programming tip is a concrete example how to do it.

KISS principle. Or 'Keep It Simple, Stupid'. The key value is the simplicity of your system. Some methodologies even put it before the functionality in hierarchy of their priorities. Seeking the simplicity is the key to minimizing your present work. Read more...

Write maintainable code. - To minimize your future work. You can do it by coding readable code and by testing.


Or 'You Ain't Gonna Need It'. Don't pre-implement features that you are not sure are needed. Don't be megalomaniac. Read more...

Less source code is almost always better. It reduces number of bugs. It reduces ugly code.

Don't optimize prematurely. Optimizations require writing less readable and less simple code. You should optimize only when necessary and when you can prove that it will gain indispensable performance. Read more...

Remove dead code. E.g. unused functions. E.g. comments left for possible future use. You use source control software, right?

Don't reinvent the wheel

Don't program code that is already written better, tested, more robust, etc. Read more...

Use best tools possible. Research (use e.g. Google Trends). Use the right tools for the job.

Use version control. This should be obvious. Not doing source backups is amateurish and leads to hell. Shit happens.

Track bugs professionally. Use professional tool. This tip is more important when working in teams. Since this article is not teamwork-oriented, this tip is here by mistake. But, whatever.

Don't repeat yourself

Or DRY for short. Duplication in code (or anything else for that matter) should be avoided. It means that when any change comes up, you'd have to change all the duplicated blocks of code. Read more...

Running tests require one step. Otherwise no one runs them.

Build requires one step. You are going to do it often.

Generate Code. By generating code, you can reduce repetitive tasks when e.g. adding 17th entity to your domain model.

Don't write comments. Comments violate the DRY principle. Your code should be clearly readable without comments. Your code could be self-documented. Also you can document your program with tests and BDD. Read more...

Prefer polymorphism to if/else switch/case statements. Switches have this tendency to reoccur with same cases all over the code. Same functionality could be achieved by proper usage of classes and polymorphism.

Use unchecked exceptions. There is no need to write throws and catches to every using method in your class hierarchy. Don't use checked exceptions. Read more...

Do code reviews. They are good to be sure there is no duplication in code. Also code readability could benefit from them. Read more...

Write readable code

Code readability is good for maintainability of your application and the teamwork. Even if you are the only programmer, you should code readable code. It is possible that you will have to encounter the same code once or twice again in the future.

Use WTF metric. The less number of 'wtf?'s when reviewing your code the better. Another popular formulation is - follow the principle of least surprise. In other words - write readable code. WTF metric is a good heuristics what does the word 'readable' means. Read more...

Choose names carefully. Method names must be meaningful. Variable names too. Every kind of programmer should be able to read your code.

Functions should have one level of abstraction. You shouldn't call high-level business method right next to opening a file for writing.

Function should do one thing. Remember - simplicity. Don't create function beasts that have more than 1000 lines of code and do too much.

Functions should have ideally no arguments. Function arguments hurts readabilty. Return values even more. Ideal number of arguments is zero, than one, two, three. More than 3 arguments are unacceptable.

Write consistently. Following the principle of least surprise. Follow standard conventions of your environment (e.g. J2EE conventions). When you are on legacy code, follow their style.

Don't abuse your programming language. E.g. use varargs for printf-like methods only. E.g. don't use interfaces just to declare constants.

Code in your user's language. You should call your key objects from user's domain the same as the user. Even if he is half-crazy slovak-speaking asshole.

Use Fluent Interfaces in the Builder Pattern
. According to Effective Java 2nd Edition, this is the best way to construct objects. This tip is an example of too concrete tips.

Refactor. Always improve your code. Refactor early, refactor often. Read more...

Don't use local variables. After reading Martin Fowler's (the) Refactoring book, I came to a conclusion that he does not like local variables. He almost always tries to refactor them using 'extract method' refactoring. In his opinion this improves readability of methods and also reusability of little pieces of code (those that are extracted). The only exception is when it is not so good to extract method there (the original method is long and uses lots of local variables) AND they have an explanatory purpouse there.

Worship encapsulation

Encapsulation is good. The main purpose is IMO to prevent that stupid everyone else from messing up with your precious code. But it improves readability too, so it is just a subcategory of bigger readability category.

Minimize accessibility of classes and members. Your interfaces should be the simplest possible.

Don't use global variables. Singletons are evil. Static (utility) classes are evil.

Favor composition over inheritance. Improves encapsulation when inheritance is prohibited. I have almost never seen this done in practice. Probably because of violation of much more important DRY rule.

Refer to objects by their interfaces instead of concrete classes. In other words, don't couple by classes, but rather by interfaces.

Loose coupling. Minimize class dependencies to maximize your future options of concrete implementation. Read more...

Apply the Law of Demeter. "An object A can request a service (call a method) of an object instance B, but object A cannot “reach through” object B to access yet another object, C, to request its services." Read more...


Because if you don't, you are working on a legacy code (by definition from 'Working on Legacy Code'). You cannot safely change anything. You don't know if you won't break something when adding functionality. And so on... Even TDD is finally considered good these days. Read more...

Tests should be fast. Otherwise no one will run them.

Test early. Or you hardly will.

Test often. Before every commit to source control system. Read more...

Test automatically. Because you can.

Use test coverage tool. It is a good metric of your code. Everything should be tested. Anything tested less than 100% smells. Read more...

Fail Fast
.

Code defensively. Check your method parameters for validity. Copy mutable parameters. Copy mutable returned fields. Etc. Read more...

Do daily builds.

Do you have some good tips I forgot?

Sunday, November 2, 2008

Review of Effective Java 2nd Edition

I have read Effective Java 2nd Edition recently. It contains 78 "items" where Joshua Bloch depicts usage of Java language the right way. All in all, I liked this book very much. Especially the chapters 2, 4 and 8 were most valuable to me. Except some introductory "items", whole book is a set of interesting articles similar to a blog.

Next I'll write down a summary of the most items of this book. I use bold font when I found an item important and italic font when I found it surprising.

Chapter 2 - Creating and Destroying Objects

The interesting stuff starts here.
Item 1 introduces you to the static factory methods and their advantages and disadvantages over constructors (boring).
Item 2 is much more useful - it introduces the "Builder pattern" as the best method to initialize objects. More widespread term is IMO the "Fluent Interfaces".
Item 3 shows us how to implement a singleton the right way - through a single-element enum (remember that enum can have methods).
Item 4 is about achieving noninstantiability of classes - through private constructor.
Item 5 is about optimizing code by using primitive types, not using Calendar and not being stupid when instantiating Strings.
Item 6 is about memory optimization through being aware of memory leaks when you program a class that manages its own memory.
Item 7 has a descriptive name - avoid finalizers.

Chapter 3 - Methods Common to All Objects

This chapter is about methods of java.lang.Object. Items 8, 9 and 11 are about overriding equals, hashCode and clone. In one word - it is hard. If I must do it, I rather use reflection-driven library from Apache Commons Lang. I found Item 10 interesting, because it encourages everyone to always override toString to improve user-friendliness of you class. I agree and I use Apache Commons Lang to do the job for me. Item 12 is about implementing Comparable, which is obviously similar to implementing equals.

Chapter 4 - Classes and Interfaces

Item 13 - Minimize accessibility of classes and members. In other words, "worship encapsulation".
Item 14 - Don't use public fields in public classes. IMO use static code analysis and soon you'll write every field of every class private...
Item 15 is much more interesting - it is called Minimize mutability. This is very good in multithreaded applications. More on this item can be found here.
Item 16 - Favor composition over inheritance. It is well known practice in the blogs but I've never seen this done in practice.
Item 17 is about pitfalls of enabling inheritance of your class. I didn't read it because I have never had to design a class for future inheritance.
Item 18 - name of this item is IMO bad, so I won't write it. It tells us to use interfaces (not concrete classes, not even abstract classes) as types of objects. Reasons are obvious.
Item 19 - Don't use interfaces just to export constants.
Item 20 - Don't use tagged classes. Tagged classes are classes with a 'tag' field which defines what the class really is. You will see many switches in tagged classes over this tag field. Use class hierarchy instead. This principle is IMO just a special case of not using switches. Switches stink. Use class hierarchies instead if appropriate.
Item 21 - What is Java way for function pointers? Right - the strategy pattern. You define the one-method interface. Then you pass its implementation instance as a parameter. If you need the implementation just once, use anonymous class. Otherwise use public static inner classes.
Item 22 - Favor static inner classes over nonstatic. I don't use inner classes so I didn't read this item.

Chapter 5 - Generics

Most of this chapter is just introductory material. It is probably so becouse there were no generics in the first edition of the book.
Item 23 - Don't use raw types in new code.
Item 24 - Eliminate unchecked warnings. Do it by following the item 23.
Item 25 - Prefer lists to arrays.
Item 26 - Favor generic types.
Item 27 - Favor generic methods.
Item 28 - This is IMO the only useful item in this chapter. Use bounded wildcards to increase API flexibility. For producers use extends, for consumers use super.

Chapter 6 - Enums and Annotations

Item 30 - Favor enums to integer and string constants.
Item 31 - Don't use ordinal value of an enum. Use instance fields instead.
Item 32 - Use EnumSet instead of bit fields.
Item 33 - Don't use ordinals to index arrays. Use EnumMap instead.
Item 34 is about simulating extensible enum types with interfaces.
Item 35 - Favor annotations over naming patterns.
Item 36 - Use @Override.
Item 37 encourages us to use marker interfaces (like Serializable) to define types. Annotation is not appropriate here, because it does not define a type.

Chapter 7 - Methods

Item 38 - Check your method parameters for validity.
Item 39 - Make defensive copies of mutable objects passed to you or from you as a class if you cannot trust your client (or you can afford the performance penalty).
Item 40 - Choose method names carefully. Avoid long parameter lists. Prefer two-element enum types over boolean parameters.
Item 41 - If you must overload a method, the overloaded method should have its unique number of parameters.
Item 42 - Use varargs for printf-like methods only.
Item 43 - Return emtpy collections instead of nulls.
Item 44 - Document your exposed API (using Javadoc).

Chapter 8 - General Programming

Item 45 - Minimize the scope of the local variables.
Item 46 - Prefer for-each loops to traditional for loops.
Item 47 - Don't reinvent the wheel. Reuse other programmers' code.
Item 48 - Don't use float or double where exact results are needed. It can miss the result by something like 0.00000000001, which is annoying. Use long or BigDecimal instead.
Item 49 - Favor primitive types to boxed primitives.
Item 50 - Don't overuse strings, where other types are more appropriate (a number, boolean, a complex class, ...).
Item 51 - Use StringBuilder instead of string concatenation.
Item 52 - Refer to objects by their interfaces instead of concrete classes.
Item 53 - You should use reflection only if you need to instantiate classes not available to you at compile time.
Item 54 - Be careful when using native methods. I don't use them so I didn't read this item.
Item 55 - Any pre-mature optimization is evil! This is one of the most important items in this book. If you absolutely must optimize (either for performance or the memory), measure the performance gains.
Item 56 - Use generally accepted naming conventions of Java.

Chapter 9 - Exceptions

Item 57 - use exceptions only for exceptional conditions. Never use them for program flow control.
Item 58 - Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.
Item 59 - Use checked exception only for recoverable conditions.
Item 60 - Reuse exception already in the Java programming language.
Item 61 - Use exception translation from lower levels of your design to higher levels. But don't over-use it, sometimes is better if lower levels don't throw any exception at all.
Item 62 - Document your exceptions.
Item 63 - Your exceptions should output meaningful messages with all values participating on exception displayed.
Item 64 - You should implement failure atomicity of methods that throw exceptions. All these methods should leave the object in consistent state.
Item 65 - Don't use empty catch blocks. You shouldn't ignore exceptions.

Chapter 10 - Concurrency

Mr Bloch designed the java.util.concurrency, so approximately half of the items here introduce new features of it.
Item 66 - When more threads use same mutable data, reads and writes must be synchronized.
Item 67 - Don't over-synchronize. Do as little in the synchronized block as possible.
Item 68 - Prefer new executors and tasks from java.util.concurrent to threads.
Item 69 - wait and notify have almost no use these days. Use concurrent collections and synchronizers from new java.util.concurrent.
Item 70 - you have to clearly document how concurrent your class is.
Item 71 is interesting - it is about lazy initialization. The advice here is not to use it if you don't have to. It is just a performance optimization. If you must do it, use double-check idiom to avoid double initialization in multithreaded environments.
Item 72 contains two advices - threads should not run if they aren't doing useful work and don't use Thread.yield. The key point here is to be less dependent on thread sheduler and therefore provide more portability.
Item 73 in one sentence - don't use thread groups, they are obsolete.

Chapter 11 - Serialization

Whole chapter is about serialization. I have never needed it, so I didn't read this chapter and I find it rather useless.