Pokazywanie postów oznaczonych etykietą clean code. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą clean code. Pokaż wszystkie posty

wtorek, 11 sierpnia 2015

The Clean Code Trap

   Often times instead of just smoothly bashing away at the keyboard to produce fresh lines of code I hit the creative block. I sit in front of the screen with one thought in my mind "this isn't clean... I can't do that". After dozens of such incidents I've came to agree with one obvious conclusion: making the software work is the main goal, following principles and patterns is just a tool.

Important Distinction

   Clean Code is mostly about how easy it is to change or add new features, how easy it is to understand by a human being and how easy it is to test it.

   Clean Code isn't about following all the principles, SOLID, patterns and other hard rules you've read over the course of your career. These are just all optional tools, that may help you in making your code cleaner.

The Cost of Principles

   Every time you constraint your code to a principle or a pattern, you make a tradeoff. By making your code more abstract, easy to change or test you're making it more complex, add more classes, interfaces and indirection - it makes it harder to read and grasp by a human being.

   The hard task of Object Oriented Design is to find the golden mean to all that. It's hard, but there are a lot of rules of thumbs for each pattern that you can follow and one general I've come up with:

Don't let patterns create code, let the code create the patterns.

   Don't make the code and constantly look for occasions to force a pattern in. Don't create patterns just for the sake of creating patterns. Familiarize yourself with all the principles, all their pros and cons, know them by heart, and while creating code the need to use one will come naturally.

   Each pattern is a mean to some end, you have to ask yourself and find hard reasons to use one each time. It works similarly with anti-patterns: when you have a need to use one, but just battle with yourself because you know you shouldn't, ask yourself why shouldn't I use one in context of my code. Here are some examples:

I Feel Bad When I...

  • Downcast - Using downcasting is said to be a code-smell - a bad OOP design. "You should use polymorphism instead". Don't be afraid to use it! It's there for a reason. If you can't find another way, or just feel it's natural to do it in your context, just do it.
     
  • Use Singletons - It's thought to be an anti-pattern by many. I don't like it, but sometimes it just saves you a lot of hassle, dependency injection, delegating etc.
     
  • Use Static Classes/Methods - You can't test them, you can inject them, but they're the easier way to use utility methods.
     
  • Use Magic Strings/Numbers - My rule of thumb is: I create a constant for a magic/number string mostly when a) it's unclear what it is b) it's duplicated in the code. Don't be afraid to write Object.Height = 0; if it makes sense to you - all programmers know what it means.
     
  • Don't create interfaces for each dependency - It's reasoned, that we need to create an interface for each dependency, because it's the only way we can mock it in unit tests. For a lot of languages you can mock an object and it's behaviors without using an interface. For example, for Objective-C you use method swizzling and in Java you use reflection (implemented in Unit Test frameworks). It saves you a lot of time, complexity and you don't have 100 useless inteface files just for the sake of unit tests. It was such a relief when I deleted 15 protocols in my iOS project. You still need to pass concrete dependencies, but that's good.
     
  • Use Cross Cutting Concerns - If it doesn't bother you, that's fine! Getting rid of these is hard and usually bloats the code or makes you use libraries.
   When you hit a creative block, ask yourself: is it really that bad in the context of my code, or am I just being blocked by those stupid rules again? It's important to remember: these rules are easy to understand and apply in the void, out of context, but it turns out that it's a whole different thing when trying to apply on living software. Sometimes doing something which is deemed a bad thing in general, might be reasonable in your code.

   If you really, really feel you're doing something bad: just do it!!



Shia really wants you to do it
   Because you're here to make software for real people for the most part.Making it nicely is the second objective. Just do it and forget about it. Mark it as TODO if it makes you feel better. 

   Go take a walk, be with your loved ones and I guarantee you that you'll find the right way after you've stopped thinking about it :)

Bonus: Your Code Is Too SOLID




piątek, 26 grudnia 2014

Your code sucks - things you need to know about clean code and architecture

    
 Although the title is an exaggeration, all code I've seen in my (short) professional career did indeed suck. Because it's my first post, it'd be appropriate to talk about something very important to me: code quality. 


I want this post to be something of a quick collection of references for programmers on how can they recognize if their code sucks and how should they try to fix it. I'll avoid getting into details or code examples.

I'd like to say it's targeted to junior programmers, but I know for a fact that there are some senior programmers out there that didn't hear of such basic concepts as Dependency injection or Don't-Repeat-Yourself principle.

Clean up your code, would you ?

I wish I ruled the world and that's just for one selfish reason: force all programmers to read this book. If all developers followed the simple rules described in Clean Code by Robert C. Martin the IT world would be so much nicer.

It would most definitely prevent such classes as Start from being created. It's actually a pretty decent one compared to some other classes on the repo of Polish Electoral Calculator client, which is only... one of the most important programs in the country. 

There are a few basic rules a decent developer should follow:

  • Replace comments with meaningful method/variable names. 
    Code should comment itself
  • Methods should do one thing and one thing only
  • Methods should be very short 
    If a method is longer than 10-30 lines, consider dividing it into separate methods
  • Don't keep dead code - your repo is your history, not commented code
  • Don't use magic strings and magic numbers
    The only exception I use are log and error mesage strings. It would be tiresome to create a constant for every possible log.
  • If a class is very long, consider dividing it
  • Don't use snake expressions
    If one expression is long, divide it into several different expressions
  • Don't repeat yourself
    If you have two blocks of similiar looking code, it means it probably needs to be put in one method
And probably many more I missed. The point here is: if you didn't know about at least one of these rules, that's more the reason to browse through the book.

My two cents

I find comments and macros very useful when it comes to arranging insides of your file. 

I like to keep my private methods and public methods divided by comments/macros.


I also put comments before every method to put method/parameters/return information for documentation (check out automatic documentation generators for IDE you're using, to see what format to use) and put a clear sign that "this method starts here". When you open the DOOM 3 source files you immediately notice when methods start. Actually, DOOM3 source code is pretty good example of clean code, here's a good blog post about that:" The exceptional bueaty of DOOM 3`s source code".


“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” - Someone

Design Patterns

If you're a developer and you've never heard of design patterns, well then better hurry: click.
Even if you find out that you don't like to use design patterns, you have to know them by heart. Why? It has an undeniable advantage: it's a universal language of software architecture.

You are the architect

Your classes are your blocks, your program is your city. The bigger the city, the better architect you have to be to prevent the city from falling apart.

Architecture is a huge chunk of computer software. It's not something you learn in a short blog post. It's also unique for every programming language or kind of program. But hey, we can always cover some basics, right ?

The most basic thing you need to follow is:

 Keep your program modular (loosely coupled)

It's easier to look at a program that's just simple modules talking to each other, than a growing spaghetti monster. It's also easier to switch stuff around.

Example

Let's say you have a Client class that uses a SQLite Database object to write and read from that database. One day your project manager tells you that SQLite sucks and he wants to to write and read to a file instead.

Interface


How can we switch writing to database to writing to a file ? They seem like two very distant things. Yeah, but they have something in common, they're both writing to some local storage. Let's make an interface/protocol/abstract class LocalStorage. Make SQLiteImplementation, and FileReadWriteImplementation, conform to this interface and make the Client talk to LocalStorage object. It explains a one simple rule:



 Always separate your interface, from your concrete classes if you have more than one implementation.

It's done using a simple design pattern called Bridge, or Strategy. They're the same thing implementation-wise but have different uses. 

IoC

How can we tell the Client which implementation to use ? Doesn't the Client create his own LocalStorage objects ? Well, it does, if the code is tightly coupled. 

In a perfect scenario, something from outside tells the Client which local storage to use. It's called Inversion of Control and the most popular implementation of that principle is Dependency Injection. We inject (tell the Client) the dependencies (Client depends on the database) to the class. Which brings us to our next rule:


 Use Dependency Injection (IoC)


It makes code highly reusable, losely coupled, easy to test, plus it has a great advantage while creating Unit Tests.



A little extra: Using mocks in unit testing


How do you write unit tests for server calls? Calls to databases without actually connecting to one ? Or how do you unit test if you still haven't finished some modules ? It's easy if you're using Dependency Injection.



Let's say we want to test our Client but we don't have access to the database. Just create a class LocalStorageMockImplementation that extends the LocalStorage interface and inject that class into the Client. Now you can test your client properly. Here's a quick tutorial if you want to know more.

Let it sink in


In my opinion, these are the basics that every developer should know, before writing a single line of code. It's not a lot to take in, and by sticking to these rules, you create a readable, highly reusable, changeable code - a miracle I have yet to experience.