Skip to main content

Principles of Good Programming

The principles of good programming are closely related to principles of good design and engineering. The following programming principles have helped me over the years become a better programmer, and I believe can help any developer become more efficient and to produce code which is easier to maintain and that has fewer defects.
DRY – Don’t repeat yourself – This is probably the single most fundamental tenet in programming is to avoid repetition. Many programming constructs exist solely for that purpose (e.g. loops, functions, classes, and more). As soon as you start repeating yourself (e.g. a long expression, a series of statements, same concept) create a new abstraction.
Abstraction Principle – Related to DRY is the abstraction principle “Each significant piece of functionality in a program should be implemented in just one place in the source code.”
KISS (Keep it simple, stupid!) – Simplicity (and avoiding complexity) should always be a key goal. Simple code takes less time to write, has fewer bugs, and is easier to modify.
Avoid Creating a YAGNI (You aren’t going to need it) – You should try not to add functionality until you need it.
Do the simplest thing that could possibly work – A good question to ask one’s self when programming is “What is the simplest thing that could possibly work?” This helps keep us on the path towards simplicity in the design.
Don’t make me think – This is actually the title of a book by Steve Krug on web usability that is also relevant in programming. The point is that code should be easily read and understood with a minimum of effort required. If code requires too much thinking from an observer to understand, then it can probably stand to be simplified
Open/Closed Principle – Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. In other words, don’t write classes that people can modify, write classes that people can extend.
Write Code for the Maintainer – Almost any code that is worth writing is worth maintaining in the future, either by you or by someone else. The future you who has to maintain code often remembers as much of the code, as a complete stranger, so you might as well always write for someone else. A memorable way to remember this is “Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.” 😛
Principle of least astonishment – The principle of least astonishment is usually referenced in regards to the user interface, but the same principle applies to written code. Code should surprise the reader as little as possible. The means following standard conventions, code should do what the comments and name suggest, and potentially surprising side effects should be avoided as much as possible.
Single Responsibility Principle – A component of code (e.g. class or function) should perform a single well defined task.
Minimize Coupling – Any section of code (code block, function, class, etc) should minimize the dependencies on other areas of code. This is achieved by using shared variables as little as possible. “Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability”
Maximize Cohesion – Code that has similar functionality should be found within the same component.
Hide Implementation Details – Hiding implementation details allows change to the implementation of a code component while minimally affecting any other modules that use that component.
Law of Demeter – Code components should only communicate with their direct relations (e.g. classes that they inherit from, objects that they contain, objects passed by argument, etc.)
Avoid Premature Optimization – Don’t even think about optimization unless your code is working, but slower than you want. Only then should you start thinking about optimizing, and then only with the aid of empirical data. “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil” – Donald Knuth.
Code Reuse is Good – Not very pithy, but as good a principle as any other. Reusing code improves code reliability and decrease development time.
Separation of Concerns – Different areas of functionality should be managed by distinct and minimally overlapping modules of code.
Embrace Change – This is the subtitle of a book by Kent Beck, and is also considered a tenet of extreme programming and the agile methodology in general. Many other principles are based on the concept that you should expect and welcome change. In fact very old software engineering principles like minimizing coupling are related directly to the requirement of making code easier to change. Whether or not you are an extreme programming practitioner, this approach to writing code just makes sense.
Prefer Composition over Inheritance – The “composition over inheritance” principle states that objects with complex behaviors should do so by containing instances of objects with individual behaviors rather than inheriting a class and adding new behaviors.
Over reliance on inheritance can lead to two major issues. First, the inheritance hierarchy can become messy in the blink of an eye. Second, you have less flexibility for defining special-case behaviors, particularly when you want to implement behavior from one inheritance branch in another inheritance branch:
Composition is a lot cleaner to write, easier to maintain, and allows for near-infinite flexibility as far as what kinds of behaviors you can define. Each individual behavior is its own class, and you create complex behaviors by combining individual behaviors.

Refactor, Refactor and Refactor – One of the hardest truths to accept as an inexperienced programmer is that code rarely comes out right the first time. It may feel right when you implement that shiny new feature, but as your program grows in complexity, future features may be hindered by how you wrote that early one. Code bases are constantly evolving. It’s completely normal to revisit, rewrite, or even redesign entire chunks of code — and not just normal, but healthy to do so. You know more about your project’s needs now than when you did at the start, and you should regularly use this newly gained knowledge to refactor old code.
Clean code is better then Cleaver Code – Speaking of clean code, leave your ego at the door and forget about writing clever code. You know what I’m talking about: the kind of codee that looks more like a riddle than a solution and exists solely to show off how smart you are. The truth is, nobody really cares.
One example of clever code is packing as much logic into one line as possible. Another example is exploiting a language’s intricacies to write strange but functional statements. Anything that might cause someone to say “Wait, what?” when poring over your code.

Comments

Popular posts from this blog

gcAllowVeryLargeObjects Element

There are numerous new features coming with .NET 4.5 and here, on this blog, you can find several posts about it. But the feature we are goint to talk about today is very exciting, because we were waiting for it more than 10 years. Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio 2012, and create C# Console Application, like picture below. First lets create simple struct with two double members like example below: 1 2 3 4 5 6 7 8 9 10 11 12 public struct ComplexNumber {      public double Re;      public double Im;      public ComplexNumber( double re, double im)      {    ...

Support for debugging lambda expressions with Visual Studio 2015

Anyone who uses LINQ (or lambdas in general) and the debugger will quickly discover the dreaded message “Expression cannot contain lambda expressions”. Lack of lambda support has been a limitation of the Visual Studio Debugger ever since Lambdas were added to C# and Visual Basic.  With visual studio 2015 Microsoft has added support for debugging lambda expressions. Let’s first look at an example, and then I’ll walk you through current limitations. Example To try this yourself, create a new C# Console app with this code: using System.Diagnostics; using System.Linq; class Program { static void Main() { float[] values = Enumerable.Range(0, 100).Select(i => (float)i / 10).ToArray(); Debugger.Break(); } } Then compile, start debugging, and add “values.Where(v => (int)v == 3).ToArray()” in the Watch window. You’ll be happy to see the same as what the screenshot above shows you. I am using Visual Studio 2015 Preview and it has some limitati...

An Introduction to Windows Azure Table Storage

Windows Azure Tables are a non-relational, key-value-pair, storage system suitable for storing massive amounts of unstructured data.  Whereas relational stores such as SQL Server, with highly normalized designs, are optimized for storing data so that queries are easy to produce, the non-relational stores like Table Storage are optimized for simple retrieval and fast inserts.  This article will cover the very basics of Windows Azure Table storage and provide you with resources and suggested topics to continue your learning. Some people, when first learning about the Windows Azure platform, find it hard to understand the purpose of the Table Storage feature.  This is especially true of those who are familiar with developing applications using highly relational data.  To get a good understanding of how a Key-Value Pair system differs from a traditional relational database you can read Buck Woody’s article on the topic in his continuing series:...