Pokazywanie postów oznaczonych etykietą architecture. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą architecture. 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




czwartek, 23 kwietnia 2015

Demystifying decoupling and cohesion in Software Architecture


Decoupling and cohesion are phrases that are thrown around in software very often. You kind of know what they mean, but do you really? 

Decoupling

Coupling in software architecture usually applies to modules in OOP. It measures how dependent are modules from each other - how strong is the connection between them. Why should that bother us? The main problem is that if modules are highly coupled, that usually means that when you change something somewhere, you create a ripple effect and you have to change other modules as well.

 How do we measure it? There's no one rule, but there are some guidelines.
  • If a change in class A forces you to change other modules, it's a sign that these modules may be highly coupled
  • If you use some custom classes, instead of primitives to pass data around modules, you increase the strength of the relationship
  • If module B has a pointer to object A, and vice versa
In order to decouple modules:
  • Think of your modules as independent, as if the rest of the program didn't exist
  • Prefer abstractions - they tend to help you think of your modules as independent
  • Design patterns of course
  • Cohesive code is often decoupled
  • Prefer composition, over inheritance.
  • Use layers of architecture

                                                                                                                 source

Interfaces != Decoupling



One very common misconception is that Dependency Injection magically decouples your code. If you do this right, by abstracting your modules, it will help you to layout your code in  modules to be independent, hence decoupled. If you just create an interface for every dependency and inject it, it doesn't decouple the code, it just gives you an illusion of doing so, because interfaces aren't abstractions.

You can have decoupled code, without using one interface.

Cohesion

Cohesion is strongly connected to decoupling but there is a subtle difference. 

"In computer programming, cohesion refers to the degree to which the elements of a module belong together."

If you have low cohesive code, it's almost definitely strongly coupled. SOLID's Single Responsiblity Rule commands to created modules, with single responsibility, hence cohesive.

Your module is cohesive, if:
  • The functionalites of the class have a lot in common and the class' responsibility can be described in a simple sentence without "and", "or".
  • Doesn't use unrelated dependencies (network module using database module)

                                                                                                                           source

wtorek, 24 lutego 2015

When to use dependency injection ?

Dependency injection is a great pattern that implements Inversion Of Control. I wrote about it in my first post.

Overusing a pattern is as bad as not using any architecture at all. It's called overengineering. As I mentioned before, it's hard to draw the line between no architecture and too much architecture.

How do we know when to use dependency injection and when don't ?

As mentioned here, this are great examples for when to use DI:

  • You need to inject configuration data into one or more components.
  • You need to inject the same dependency into multiple components.
  • You need to inject different implementations of the same dependency.
  • You need to inject the same implementation in different configurations.
  • You need some of the services provided by the container.

I also mentioned that creating an interface for every class just for the sake of it, might be a bad idea. It breaks RAP and YAGNI rules.

So what if we really want to use DI and play right by SOLID, but not overdo it ?

Breaking SOLID

If you stop using DI for some modules, doesn't that mean that you break the dependency inversion principle ?


"High-level modules should not depend on low-level modules. Both should depend on abstractions"


I was really confused so I sought help on StackOverflow asking:




I was lucky to get an answer from a StackOverflow veteran. You should read it carefully. It states that you should seek common behaviour from all the modules and try to extract one generic interface (an abstraction). I won't get into detail, because it's all described here in examples:

- Generic queries
- Generic commands

Should I use IoC containers ?

The opinions are mixed. IoC are great in managing dependencies but involve a lot of complexity. There are books with hundreds of pages about IoC container frameworks.

In my opinion, you should consider IoC containers only if your project is really big, with a huge dependency tree.

One great thing about IoC is resolving dependency carrying. Dependency Carrying is when you create object A at the beginning and you carry it through all dependencies just because one class needs it. 



poniedziałek, 26 stycznia 2015

Why you should use MVVM instead of MVC

The View-Controller in MVC is responsible of interpreting the Model (business logic) and managing UI. See that "and" in the middle ? It's a sign that a class might be breaking the Single Responsibility Principle. 

In theory, MVC sounds pretty nice, in practice it usually ends up the same: view controllers end up bloated and huge. They mix a lot of logic inside, which makes them hard to reuse and to test.

Microsoft to the rescue!

I have experience with Windows Presentation Foundation and I've learned a one very useful pattern there: MVVM. MVVM is almost like MVC, with slight different distribution of tasks. 

                                                           source

ViewController is now a part of the view. It's responsible for the UI: animations, dynamic changes, adding views, removing views, etc.

ViewModel is something that can be used in different projects, not only iOS. It's your business logic.

It takes data from the model, and interprets it. 

This way you achieve decoupling and you can test your business logic very easily. Something that was very challenging with ViewController.

Data Binding

MVVM is very powerful when combined with data binding. You can set your View to react to changes in the ViewModel via callbacks/events. This way you don't have to think what to do when certain data changes in the ViewModel, it's done "automatically".


Reactive Cocoa

How would we implement data binding on iOS ? Probably through some event system or Key-Value Observation (KVO). There's a cleaner way: functional reactive programming. We can achieve the functional programming in Objective-C thanks to a framework called ReactiveCocoa. Reactive Cocoa is built upon KVO and it saves you a lot of time, also making your code cleaner. MVVM and ReactiveCocoa is a great match for creating independent, clean and reusable modules of a system. Here's a great tutorial to get you started.




czwartek, 22 stycznia 2015

Cross Cutting Concerns

A programmer writes code to query his database. He uses the log function over and over again. Then you get to the UI and use the same logger. You end up with using the same class cross cutting through all of your app modules.




You can think of many concerns that'll cut your app like caching, analytics, security. Why are Cross Cutting Concerns bad ?



  • Single Responsibility Principle is violated. Example: You have a network module that also logs, secures, sends analytics etc.
  • It breaks the modularity of your app.
  • It makes the code practically not reusable. Business logic should be separated from implementation code.

Decorator Pattern

How do we fix this ? There has to be some pattern, right ? Well, there is. You can  use the Decorator pattern to decorate the operation with all the concerns.

Here's a lengthy post about having abstracted commands, that can be decorated.

Of course, there's a drawback to all that: a lot of abstractions. Of course, abstracting your modules in your code is good, but this forces you to abstract every little action you want to log (for example). You can end up with hundreds of interfaces, just for the sake of removing cross cutting concerns. Quite costly, huh ? There has to be a better way.

Aspect Oriented Programming

Wikipedia for Aspect Oriented Programming might look a little scary, but it can be as simple as that: you set up blocks of code to be executed before, or after a certain method in a certain class. 

The Aspects library for Objective-C uses method swizzling to achieve that. Very clean, doesn't need additional classes/abstractions, it isolates your concerns.

poniedziałek, 19 stycznia 2015

Drawing clear lines in software architecture

While reading the web I've stumbled upon an interesting article "Reusable Software? Just Don't Write Generic Code" that instructed:

"Do not introduce an abstraction layer unless it is clear that you will have multiple implementations (YAGNI principle)."

This comes on strong for one important reason:
  • it explicitly tells you not to do something, which in my opinion needs strong arguments in software architecture.

Evil interfaces!


According to Jos de Jong introducing an interface for every implementation is bad because:
  • it violates YAGNI principle
    it says not to program something, just for the sake of it. Write something only if you are going to need it.
  • it violates RAP principle
    it says that adding an interface for every implementation adds "indirection and code clutter, which just makes the code harder to understand"
  • it breaks encapsulation
    it exposes external classes to internal implementation.


YAGNI is of course a good and sensible principle, but not something to be followed blindly. The RAP principle description gives you a thesis but no proof. It says that adding an interface for one implementation is bad, but doesn't tell you why - other than it might look bad. It breaks encapsulation, I agree but it's not necessarily bad, which I'll explain later.

What about unit test mocks and dependency injection ? Shouldn't we use interfaces to get these working? According to Jos: not necessarily. He says you can still inject concrete classes and test with concrete implementations, instead of mocks.

but: "
When you test that code path with the actual dependency, you are not unit testing; you are integration testing. While that's good and necessary, it isn't unit testing."

That means that if you want to unit test... you have to use mocks (just don't overuse them!)

Well, at least in some languages. In dynamically typed languages like Objective-C you can create stubs and mocks without creating a concrete class (which I strongly advise you to).

Good interfaces!


By injecting concrete classes instead of interfaces you break two of the five very important SOLID principles.

If your project will be maintained for a long time, there's going to be a huge probability that you will need a different implementation for some module you didn't expect. You're going to break the open/close principle and create a nasty code smell by going through every reference to implementation A and changing it by hand to implementation B. 

You also break the dependency inversion principle that says one should "Depend upon Abstractions. Do not depend upon concretions".

Sure, you also kind of break the YAGNI rule, but ask yourself, what the lesser of the evils here ? A question you have to ask yourself very often in programming.

Component-based software engineering

Why do we inject interfaces, instead of concretions, even though it introduces code clutter and breaks encapsulation? I've found a great explanation that's hard to argue with on Stackoverflow.

"...When we use IoC/dependency injection, we're not using OOP concepts. Admittedly we're using an OO language as the 'host', but the ideas behind IoC come from component-oriented software engineering, not OO..."

Great out of the box thinking. Of course, we're breaking OO a little bit here, but we don't care, because we're using another concept that's meta OO to have our software modularised.

Lesser evil

So we have extremely contrary points of view on software architecture. The best way out of this mess would be to find common characteristics between all of our modules and abstract their behavior into shared modules (example). You can't always do that, though.

As I said: programming is very often about choosing the lesser of two evils. It's mostly never a clear line like "this is bad", and "this is good". These are just tools, and we have to use them for the right job. How? Experience, time, and patience.