Quality code pillars: a guide to better code reviews

As a code mentor and member of a software development team, I’m subject to and carry on code reviews. However, I have noticed that many times people doing the review don’t have a clear idea of what to look for. This leads to discussions on stuff like style and micro-optimizations. Having been there myself, I would like to offer some ideas on things that you could look for when doing a code review. I want to share my personal quality standard. To me, a code’s quality is measured by 3 aspects: understandability, malleability, and correctness.

Understandability

Understandability measures how easy is for us to comprehend something. In one side we have simplicity, that is, easy to understand stuff. On the other side, we have complexity, or things that are hard to understand.

A good quality code is a simple one. It’s important to notice that there’s essential complexity (the inherent problem complexity) and accidental complexity (the solution complexity). I’m referring to the latter. Strive to keep your solutions simple. I have found that communication is the main idea here: does the code communicate the ideas succinctly?

When reviewing, I look for code that is poorly encapsulated or named. Also pay attention to the semantic distance between the concept and the symbol in the code that represents it, it may reveal leaking abstractions.

Malleability

From The Titi Tudorancea Library:

The property of being physically malleable; the property of something that can be worked or hammered or shaped without breaking

Metaphorically speaking, we refer to how flexible, how easy to change our code is. That is different than how easy is to understand. One is a mental act and the other a physical act. We can think of malleability as a continuum with flexibility in one end and rigidity in the other.

A rigid code is better explained by uncle bob:

Rigidity is the tendency for software to be difficult to change, even in simple ways. A design is rigid if a single change causes a cascade of subsequent changes in dependent modules. The more modules that must be changed, the more rigid the design.

I often look for references that couple modules, objects and projects unnecesarily.

Correctness

What I mean by this is as free of errors as possible.

Typically, we deal with 3 types of errors: syntactical, semantical and runtime.
Since the compiler usually handles syntatical errors, let’s focus semantical and runtime errors.

Semantical errors are related to the business logic. This is a moving target since the rules the software try to model tend to change over time (at least this is true for a line of business application). We usually detect them using unit testing and acceptance/functional testing.

Runtime errors are usually related to resources used by the application. You can detect these using integration, load and any other kind of tests that exercise the application resources.

If the tests related to the code piece I’m reviewing are not present, I ask the developer for any.

 

Closing thoughts

So, there you have it. I would like to say that the order in which these appear is the priority order for me i.e I’ve found that if I start trying to create a flexible codebase, I tend to end up with some complex code. My suspicion for this phenomenon is that often flexibility is attained through indirection, which makes the code harder to understand (complex). So, by focusing on simplicity first, I can begin introducing flexibility as this becomes necessary and still have a codebase that a new developer can pick up rather quickly. And if you have a code that is easy to understand and easy to change, you can easily correct it.

By the way, TDD promotes simple, flexible, and correct code, but that’s a post for another time ūüėČ

So, what do you look for when doing a code review? leave your comments below

 

Models and business logic patterns

In the last post, we talked about the different models that co-exist in an application. However, some of these models may or may not exist in a given application and time. To get a better understanding of this effect, let’s review 3 different configurations and the way they affect the application models mentioned before.

Transaction script

A transaction script as described by Martin Fowler, it’s a procedural (often a structured programming) approach to organize an application logic. It contains all the steps to fulfill a request/use case/scenario/story. In my experience, this kind of applications often uses the persistence model directly. This means that this model doesn’t have a domain model but the business logic is embedded in the transaction script itself. Often the transaction script returns a different model on the result, effectively using a presentation model.

Table module

A table module is a different way to organize an application. It’s based on the idea of having a structure that represents a table, just one row at a time. The object itself it’s just an access mechanism to the data of the underlying table. It allows to move to any given record and provides access to all of its fields. You can put the business logic onto this object making it instantly available to all of the records. Often this object is directly bound to the controls of the UI. This means that the persistence, domain and the presentation model are exactly the same.

Domain model

A domain model centric configuration works by separating the domain layer from anything else. The resultant objects are focused on one thing and one thing only: hosting the business logic and rules. By doing this (keeping the domain model ignorant to persistence and presentation needs) we are forced to create a persistence and presentation model. This may initially closely resemble the domain model but can change independently to accommodate the needs of the layer it belongs to (presentation, persistence). Usually, the domain model is developed using an OOP paradigm, whereas the persistence model is often developed under a RELATIONAL paradigm (if using a relational DB) and the presentation model is done following an ACTION or OBJECT representation approach.

Closing thoughts

So there you have it. Go and check your codebase again. Which pattern it follows? Can you pinpoint the different models being used? leave your comments below…

Not all models are the same

Some time ago I used to work for a company that made gelatin capsules used for drug administration. The process was a tricky one: there were several machines that would mix the gelatin and then you have a to wait a cool down time before you could start using it. There were different kinds of gelatin with different mix and cooldown times. My job was to create a simulator that would calculate the optimistic use of the machines given the requirements for different kinds of gelatin. I was given access to a database that had everything I needed. So my initial domain model was based on the DB¬†structure. As time passed by, however, it was clear that the current model was lacking a lot for my purposes. So I just dropped the whole thing and start anew. Using a repository I then mapped the domain model to the DB¬†model. Then something funny happened: my manager could not understand my domain model since he could not reason outside of the DB one. It took me some time to figure what was confusing for him…

Not too long ago I heard something similar. I was helping a friend at work to distill a domain model that was based on a DB. I didn’t do much, just giving some pointers on how to apply OOD principles and helping him to find out how to allocate responsibilities to the right objects. As the model became more clear he came to the conclusion that some of the DB design decisions were getting in the way, so he decided to create his own domain model. Once he did that, the code became so much clear.

The fallacy of one model to rule them all

Unfortunately, a lot of people tends to start modeling the DB and then create a domain model that mimics that structure. That works for a relatively simple system but it won’t stand against a more complex one. The reason it’s simple: the DB model, serves a different purpose than solving the problem. Actually, we deal with several models on a system, each one serving a different purpose. Let’s go over them.

The persistence model

I’ll start with this because often this is the starting point when designing a system. The persistence model actually has the purpose of storing data efficiently. That’s it. We often use E/R diagrams as a tool to understand the concepts of the domain and the relationship between them. One problem with this is that often these concepts are related only on a given context and these relationships are not valid out of that scope. A very experienced developer can avoid that but I argue there are better tools for analysis than E/R diagrams. Usually, the persistence model is very granular.

The domain model

The domain model it’s the one responsible for solving a very specific problem. Hence a domain model should be very specific. Designing a domain model requires you to have an understanding of the problem. This is part of the solution and not the problem space. I believe this model should be created before any other one. If you are using OOP, this model comprises your objects and the interactions between them. Is often more coarse than the persistence model.

The presentation model

The purpose of the presentation model is to allow the user to interact with the system.

When dealing with an object-oriented system, there are 2 schools of thought regarding the user interface: task-based and object-based.

Task-based user interfaces are geared towards a task that involves several objects interacting together. It’s like a script that a set of objects has to follow to accomplish something on behalf of the user. This often results in a more coarse model that aggregate several domain objects. Objects on this model are often called view-model objects.

Object-based user interfaces are predicated on the idea that the user should be able to manipulate the objects together as he/she sees fits to accomplish anything he wants. This means exposing the underlying domain model directly to the user. Patterns and frameworks such as naked objects are examples of this idea.

Traps and tricks

One of the problems I often encounter comes from the use of ORM’s. I’m not saying that using them is bad, but you should use them carefully. They often introduce constraints from the underlying persistence mechanism, forcing us to concern with stuff other than solving the problem at hand. They also somehow promote coupling so it’s not easy to switch the underlying persistence technology, ie from a relational to a document DB.

Another problem arises when you try to expose your domain objects on a task-based UI. In my experience they become intermingled with UI logic, making them a mess that is hard to maintain. Often you end up with additional data that has nothing to do with the object original purpose.

Eric Evans figure this out long ago. That’s why on DDD he provides us with patterns to isolate the domain model from any external influence. Repositories allow the domain model to be completely independent of the persistence model whereas the application API isolates it from the UI. Unfortunately, the intent behind these patterns has been forgotten and thus misuse and abuse of these patterns arise.

Closing thoughts

Next time you start a new project, put mechanisms in place to keep your models separated.

Whenever you find yourself struggling to accomplish something because your model (be it persistence, domain or presentation) cannot accommodate that change without creating a ripple effect to the other models, take a look at the patterns mentioned here and look for ways to isolate the model. This may take some time in the present, but it will pay handsomely in the future.

Good luck out there!

What’s holding you (or your organization) from being Agile?

So you got yourself a scrum manager, had a meeting with the team, explain the scrum practices and wrote a product backlog. 4 months later things aren’t going as you expected… this Agile talk is all nonsense – you say as you walk disappointed – we were supposed to be able to ship faster, to fix bugs faster, to add new features faster… Before throwing the baby with the water, let’s consider some of the possible¬†causes.

Your codebase is not Agile

This is by far the most common reason I have found on my experience. You have a code that breaks every time you introduce a change (fragile), or that has you change a lot of places every time you add a new feature (rigid). You cannot be agile with a codebase that fights you every step of the way. Focusing on processes and ignoring the codebase is often the reason why organizations fail when trying to implement Agile methodologies.

Your mindset is not Agile

If you think that a scrum master is a manager, you’re not Agile.
If you think that a backlog is like a Gantt chart, you’re not Agile.
If you think that you need a separate team (or phase) for testing, you’re not Agile.
If you think that story points are a unit of time rather than effort, you’re not Agile.
If you think that value is determined by someone else than the end user, you’re not Agile.

Your feedback loop is too loose

To me Agile means feedback. I remember that one of the things that surprise me the most on a scrum training was this exercise where we get to create something physical, present it, get feedback on it, and turn that into a user story/task. The trainer then proceeds to explain that the sooner we get the feedback, the sooner we would be able to adjust to get on the right track. He talked about how a sprint should have several opportunities to get feedback so by the end we get the right product and not only the product right.

Lack of enough experienced developers

This one is actually kind of logic. If you don’t have enough experienced¬†developers, how do you expect to have a flexible, high-quality codebase? Having enough experienced developers that you can pair with less senior developers helps you improve the overall team level. Whereas having just a few of them tends to become a bottleneck for the whole team since everyone depends on them somehow.

Closing words

I am, by no means, an expert on Agile. These¬†are just my observations on some of the most common errors I’ve seen in my professional career.

Do you think I’m missing one? leave your comments below.

How to make your c# code more OOP with delegates pt 2

Implement the strategy pattern with delegates

Changing the default behavior of a method under testing (or any other specific circumstance)

Given the following code:

class EmailSender{
    
    public void Send (string recipient, string subject, string body) {//invoke 3rd party}
    
}

class Email{
    
    public EmailSender _sender = new EmailSender();

    public Send(){_sender.Send(recipient, subject, body);}
    
}

Imagine that you cannot change the Email class. How would you unit test it without making a call to a 3rd party service?

Answer: inject a delegate with the desired behavior.

class EmailSender{
    
    Action<string,string,string> _sendAction = _send; //default action
    
    public void Send (string recipient, string subject, string body) {
     _send.Invoke(recipient, subject, body);
    }
    
    public void _send (string recipient, string subject, string body) {//invoke 3rd party}

    internal void ActivateTestMode(  Action<string,string,string> testAction){
     _send = testAction;
    }

}

 

Specializing the rules of a domain object without inheritance

Given the following code:

public class BonusCalculator()
{
  List<Bonus> bonuses = new List<Bonus>();

  public BonusCalculator(ICollection<Bonus> bonus)
  {
    bonuses.AddRange(bonus);
  }

  public decimal CalcBonus(Vendor vendor)
  {
   var amount = 0;
   bonuses.foreach(bonus=>amount += bonus.Invoke(vendor, amount));
   return amount;
  }

}

public class BonusCalculatorFactory()
{

   public BonusCalculator GetSouthernBonusCalculator()
   {
    var bonuses = new List<Bonus>();
    bonuses.Add(new WashMachineSellingBonus()); 
    bonuses.Add(new BlenderSellingBonus ()); 
    bonuses.Add(new StoveSellingBonus ());

    return new BonusCalculator(bonuses);    
   }

}

If we want to add a new bonus that increments the 15% we would have to create a new class just to do that multiplication… So let’s try something different.

public class BonusCalculator()
{
  List<Func<Vendor, Decimal>> bonuses = new List<Func<Vendor, Decimal>>();

  public BonusCalculator(ICollection<Bonus> bonus)
  {
    bonuses.AddRange(bonus);
  }

  public decimal CalcBonus(Vendor vendor)
  {
   var amount = 0;
   bonuses.foreach(bonus=>amount += bonus.Apply(vendor, amount));
   return amount;
  }

}

Now we have to modify the factory

public class BonusCalculatorFactory()
{

   public BonusCalculator GetSouthernBonusCalculator()
   {
    var bonuses = new List();
    bonuses.Add(new WashMachineSellingBonus().Apply); 
    bonuses.Add(new BlenderSellingBonus().Apply); 
    bonuses.Add(new StoveSellingBonus().Apply);
    bonuses.Add((vendor,amount)=> amount * 1.15); 
    return new BonusCalculator(bonuses);    
   }
}

 

Easy peasy. Now depending on how it is implemented, we could start thinking about turning some of the rules into singletons.

Moving the control flow into objects

How many times have you started an operation where you want to know 1) if the operation was successful and 2) the return value. A lot of times this leads to code like:

class OperationResult{
    public bool IsSuccess{get;set;}
    public object ResultValue {get;set;}
}

interface IDataGateway{
    OperationResult UpdateName(string name);
}

class NameUpdaterCommand{
    string _name;
    IDataGateway _data;
    Log _log;

    public NameUpdaterCommand(string name, IDataGateway data, Log log){
       _data = data;
       _name = name;
       _log = log;
    }
    
    public void Execute(){
        var result = _data.UpdateName(_name);

        if(result.IsSuccess)
            _log.Write("Name updated to:" + Result.Value.ToString());
        else
            _log.Write("Something went wrong:" + + Result.Value.ToString());
    }
}

Come on, don’t be shy about it. I’ve done it myself too…

So what’s wrong with it?

Let’s see, the intention¬†behind this code it’s to¬†decide on a course of action based on the result of an operation. In order to carry on these actions, we need some additional info for each situation. A problem with this code is that you can’t handle an additional scenario. For that to happen instead of a boolean IsSuccess¬†you would have to create an enumerator of sorts. Like:

enum ResultEnum{
    FullNameUpdated,
    FirstNameUpdated,
    UpdateFailed
}

class OperationResult{
    public ResultEnum Result {get;set;}
    public object ResultValue {get;set;}
}

interface IDataGateway{
    OperationResult UpdateName(string name);
}

class NameUpdaterCommand{
    string _name;
    IDataGateway _data;
    Log _log;

    public NameUpdaterCommand(string name, IDataGateway data, Log log){
       _data = data;
       _name = name;
       _log = log;
    }
    
    public void Execute(){
        var result = _data.UpdateName(_name);

        switch(result.Result){
             case ResultEnum.FullNameUpdated:
               _log.Write("Full name updated to:" + Result.Value.ToString());
               break;
             case ResultEnum.FirstNameUpdated:
               _log.Write("First name updated to:" + Result.Value.ToString());
               break;
             case ResultEnum.UpdateFailed:
               _log.Write("Something went wrong:" + + Result.Value.ToString());
               break;
        }  
    }
}

So now every time¬†you want to add a new scenario you have to add a new enum value and a new case on the switch. This is more flexible than before but a little more¬†laborious than it should be. Let’s try to replace this enum based code with objects that represent each case:

interface IDataGateway{
    void UpdateName(string name, Action<string> firstNameUpdated, Action<string> fullNameUpdated, Action<string> updateFailed);
}

class NameUpdaterCommand{
    string _name;
    IDataGateway _data;
    Log _log;

    public NameUpdaterCommand(string name, IDataGateway data, Log log){
       _data = data;
       _name = name;
       _log = log;
    }
    
    public void Execute(){
       _data.UpdateName(_name,
                     fullNameUpdated: name  => _log.Write("Full name updated to: " + name),
                    firstNameUpdated: name  => _log.Write("First name updated to: " + name),
                        updateFailed: error => _log.Write("Something went wrong: " + error )
        );
    }
}

So now we have a shorter code. We have also moved the responsibility to control the flow to the object implementing IDataGateway. How it does it is just an implementation detail. We don’t care if it’s using an enumerator or any other mechanism as long as it works.

Phew! I think that’s enough for now. Now go improve your code!

 

How to make your c# code more OOP with delegates pt 1

Since I became a codementor¬†a recurrent theme has been handling delegates. I’ll try to clarify this once and for all. This ended up as a long post so I have decided to break it into 2 parts: in this, we get a feeling of what are delegates. The next one will deal with how and when to use them.

Extending the C# type system

The c# type system is often classified as reference and value types. I won’t go into what’s the difference between these 2 since there’s a lot of information about this topic out there. Typically a developer starts an application by extending this basic type system to better model a solution for the problem he is solving (in effect, he’s creating a DSL). There are several ways to do this: if you want to extend the value type system you usually use structs whereas for the reference type system classes and interfaces¬†are the default way.

However, there’s a 3rd way to declare a new type: delegates.

Understanding delegates

Given that a delegate type syntax it’s different than the rest of the methods to declare a new type, a lot of developers never realize that they are indeed declaring a new type. I mean consider the following:

class StockItem {
    public int SKU {get; set;}
    public string Description{get; set;}
    public decimal price{get; set;}
}

struct Point{
   public int X {get; set;}
   public int Y {get; set;}
}

interface IValidate{
    bool IsValid(object value);
}

somehow they feel alike, right? now check this out:

delegate string CallWebService(string url);

It feels odd right? It looks nothing like the other type definitions we have seen so far. It doesn’t have attributes¬†nor methods. Just what is this?!?!
Calm down, first of all, a delegate it’s an object that holds code declared somewhere else in contrast with classes which define the behavior of its instances inside themselves. With that in mind let me tell you that, what the delegate definition is saying is what kind of code it will contain: which values can accept and return. The “method name” would be the delegate name. Now that we have a type we can create instances of it!

delegate string CallWebService(string url);

class WebServiceUtils {
   public string MakeCall(string url){...}
}

public class Test{ 
            public static main (){ 
                string anUrl = "..."; 
                var caller = new CallWebService(new WebServiceUtils().MakeCall);
                caller.Invoke(anUrl) //or could be just caller(anUrl);
             }
}

So far so good. Actually, the C# team saw the potential of delegate and in C# version 2, they decided to bring some of the best things that could happen to the language: anonymous methods. Anonymous methods are an incarnation of closures, a very powerful concept. Unluckily for us, they decided to reuse the delegate keyword for this.

delegate string CallWebService(string url);

class WebServiceUtils {
   public string MakeCall(string url){ ... }
}

public class Test{ 
 public static main (){ 
 string anUrl = "..."; 
     var caller = delegate(string url) { return new WebServiceUtils.MakeCall(url); };
     caller.Invoke(anUrl) //it could be just caller(anUrl);
 }
}

I can only imagine that the C# team was thinking that since anonymous methods were only going to be used with a delegate, it made sense to use the delegate keyword to declare not only a delegate type but a delegate instance as well. Unfortunately, this leads to further confusion since now when someone talks about a delegate, he could either be talking about a delegate type or an anonymous method.

Even worse! From MSDN:

There is one case in which an anonymous method provides functionality not found in lambda expressions. Anonymous methods enable you to omit the parameter list. This means that an anonymous method can be converted to delegates with a variety of signatures. This is not possible with lambda expressions.

Basically, it means that you can write code like:

delegate string CallWebService(string url);

class WebServiceUtils {
   public string MakeCall(string url){ ... }
}

public class Test{
   public static main (){
     string anUrl = "...";
     var caller = delegate { //<-- no parameters at all!!
            //you can have access to the variables on the same 
            //scope as where the anonymous method was declared
          return new WebServiceUtils().MakeCall(anUrl);
     };
     caller.Invoke(anUrl); 
   }
}

So now you have anonymous methods that don’t conform to the delegate definition but are still regarded as valid.

As if this wasn’t enough the 3rd version of C# brought another way to declare anonymous methods: lambda expressions.

delegate string CallWebService(string url);

class WebServiceUtils {
   public string MakeCall(string url){ ... }
}

public class Test{
   public static main (){
     string anUrl = "...";
      //this is an anonymous method too
     var caller = (url) => new WebServiceUtils().MakeCall(url);//or MakeCall(anUrl)
     caller.Invoke(anUrl); 
   }
}

uff! this was a lot for a single post. Next post will see delegates in action. Stay tuned!

The OOP wars

Some time ago I had an interesting discussion with Tony Marston. Suddenly I found myself on the middle of what seems to be an ongoing war related to what’s OOP. It seems to (still) be a heated debated on some circles, so I want to share some thoughts on the topic.

The origins

So around 1962, 2 guys from Norway (Ole Johan Dahl¬†and¬†Kristen Nygaard) extended the Algol programming language to easily create simulations. They called the new language Simula. The idea was that “A discrete event system is viewed as a collection of processes whose actions and interactions completely describe the operation of the system”. Little did they know that they work would create a revolution in the programming community.

The calm before the storm

Sometime after the invention of Simula, in 1966, a newly graduated from the University of Utah came in contact with it. As he tried to understand the concepts behind this newborn language something made click in his mind. His name was Alan Kay and he was the one who coined the object-oriented programming term. His vision was profound yet simple: a net of interconnected software computing units called objects sending messages to each other. His idea was the software equivalent of the internet. He also had the idea of a network of interconnected computers by either a wired or wireless mean by the way.

Around 1979 a Danish man called Bjarne Stroustrup was working for AT&T Bell Labs, where he had the problem of analyzing the Unix Kernel with respect to distributed computing. The problem was that C was way too low level for a large system. It was then that memories from his Ph.D. thesis, which has been written using Simula, came back. Using Simula as a base, Bjourne extended C to support classes, which he called “C with Classes” and later “C++”.

The smalltalk faction

Smalltalk it’s the brainchild of Alan Kay. It’s the reification of his vision. The language itself it’s pretty compact.

Smalltalk sports a dynamic typing system, that is, the type is not enforced at compile time.

An object is a computing unit that sends and receives messages. The user defines which actions must take place when a given message is received by a specific object. If there’s not action defined for a particular message, then the object notifies the system with a ‘message not understood’ message.

Alan Kay was heavily influenced by LISP. In LISP everything is a list: code, data, everything. This allows powerful metaprogramming techniques. Kay build upon that metaphor: everything in smalltalk is an object. Everything. A number is just an object which knows how to respond to messages like “+ 3”. A string is an object that knows how to respond to messages like “reverse”. Even inline functions/closures are objects (known as blocks) that respond to a “value” message. That’s all there is to it. This is the reason why static typing is unnecessary: you just care whether the object can respond to a message or not.

The C++ camp

C++ was designed with systems creation in mind. As such it deals with stuff like performance and memory footprint. If you are familiar with C, C++ it’s a natural evolution. It can be tricky, however, to get the most out of the object extension. This is due to C++ being a multiparadigm language, meaning that you may still resort to solutions in a different paradigm that could be implemented in a cleaner way using OOP. Stroustrup talked about this in his 1995 OOPSLA paper (see the concrete types section).

It uses a static type system, so the compiler validates every type and related operation.

An object is a structure of data along with methods to manipulate that data. You directly invoke the methods on the object.

Classes are a type extension mechanism, allowing the developer to create a DSL on top of C while still having access to all the lower level features. In order to circumvent some of the problems that arise from a static type system, it introduces templating, which allows a higher reusability.

The eternal bashing warfare

So, the eternal discussion about OOP stems from these 2 schools of thought. To some, OOP is nothing more than procedural programming plus encapsulation, inheritance and polymorphism. To others (myself included) it involves a completely different mindset. The reality is that C++ is indeed an object-oriented extension on top of a procedural language whereas smalltalk is a completely new language that heavily draws from the functional realm. Therefore, the claims from each group are valid depending on the point of view. As someone who learned OOP using C++ I have found very beneficial to learn smalltalk later. Really, having nothing else than objects to work, helped me understand the boundaries between OOP and Procedural programming, helping me shape my approach to OOP design and decomposition.

Peace to the world

So, whether you belong to the smalltalk or the C++ party, remember to be tolerant to other people point of view. It’s an absolute benefit to learn to see from another perspective. So next time you find yourself on another OOP battle camp remember that the ultimate value comes from learning to work together, despite differences, than to demonstrate that you’re right and everybody else is not.

Happy Holidays!

Software developer profiles

In my last post I talked about how a developer could improve his skillset by breaking it down in 3 areas: Principles, Technology and Industry knowledge. So depending on how the time is invested, chances are that he will fall in any of the following stereotypes (T=Technology, I= Industry, P= Principles. Order indicates depth of expertise):

T+I+P

This is by far the most common type of software developer that I have found on my interviewing experience. These are students that graduated from school using visual basic (or any other RAD) and then went on to create forms over data kind of software with not really complex rules. Even when they move to JAVA, they’re still coding with a VB mindset. They can create something out of thing air quickly, but often it’s a BBOM and very hard to maintain. Depending on the time and the kind of projects he/she can start to evolve towards a more principles focused practice. Or just continue doing the same thing for the next 10 years. I usually try to figure out where on the spectrum between these 2 poles is the candidate.

I+T+P

I have seen more and more developers of this kind lately. They are usually people like the accountant that learnt SQL on it’s own. As the final user of the software, he can create and tweak the software to adjust to his necessities. Since they lack any formal engineering education the resulting code is often no better than that of a student. I have worked with this kind of developer but have never interviewed one.

P+I+T

These typically are software developers that spend a lot of time on an enterprise, creating level enterprise software. This forced them to look to better ways to create software that’s stable, maintainable and robust ultimately leading to a better understanding of the principles, patterns and practices. However the rate of adoption of new technologies in the enterprise is rather slow (some are still running on AS400) so they are behind the technological wave. Nevertheless they understanding of the more general principles allows them to pick up quickly on new technologies and languages. Whenever I came across this kind of candidate I usually recommend him/her on the spot.

P+T+I

This is the typical software developer that graduates school and enter to work in a software workshop, creating software for other clients. He understands the importance of creating good software and try to improve his skills as time goes. However unless he/she is assigned to a customer for a very long time, his understanding of the industry is limited to the scope of the projects assigned to him. Whenever I came across this kind of candidate I usually recommend him/her on the spot.

where are you now and where are you heading?

Final thoughts

In my experience the seniority of a software developer is dictated by the deep of his understanding of the principles, patterns and practices. The reason being that the quality of the overall software is deeply affected by this. You can always correct a DOM manipulation done by JQuery to use the Angular mechanisms, but correcting an faulty architecture or a leaking abstraction is a far more complex matter. That is why is important to take these decisions with a solid understanding of its consequences.
So you can have a developer with a good understanding of principles and 0 experience using Angular and expect him to write better software than a developer with 5 years of Angular and a poor understanding of the principles. The latter may be quicker, but the former will create something of a higher quality. Uncle Bob has reiterated this more than once and asked for us as software developers to raise the bar. If you follow on his works (talks and books) you’ll see that his emphasis is on the principles, not the technology.

As always, let me know what you think.

Knowledge management for software developers

There are 3 different kinds of knowledge that a software developer has to manage on his professional career. I called them principles, technology and industry knowledge. There is other relevant stuff such as soft skills but today I’m focusing on knowledge not skill sets.

Principles

Before continuing I want to clarify what I mean by principles: borrowing the title from uncle bob’s famous book I’m referring to principles, patterns and practices (with a little twist from the book’s meaning).

Principles are technology agnostic. They can be applied generally on a wide set of circumstances. An example would be the DRY principle which is universally recognized as a good practice in software engineering (no matter if you work in an OOP or a functional paradigm).

Patterns are often limited to a specific mindset, a paradigm.

A good example here could be the null object pattern. It makes sense in an OOP context, but it lacks when used in procedural programming.

Patterns are usually a trade of simplicity for flexibility the latter being derived of some of the paradigm traits. You could say that it maximize some of the paradigm benefits at the cost of simplicity: the code may be complex to understand to someone not familiarized with the paradigm but at the same time is easier to change once understood. The secret here lies in one’s ability to use the paradigm thinking process. As with everything else, practice leads to mastery.

You can find a compilation of these patterns in almost every development paradigm, with names that make it easy to refer to them when talking with other developers.

Practices¬†refer to the way we develop code. It includes stuff like¬†refactoring, testing, incremental delivery and so on. They’re usually outlined in a software development methodologies and some are expressed as conventions. While they can be widely applied, we are usually use and learn them in the context of a team or project’s specific configuration.

All of us have a certain a familiarity degree with each of these concepts. However, not all of us are conscious that they are interrelated to each other i.e. comprehension of some principles can help us decide when to apply certain patterns. This kind of knowledge ultimately leads to better code and designs.

Technology

This is probably the kind of knowledge that most developers spend the most time learning. This makes sense: with so many new technologies every other week, we must try to keep up or we’ll be at the risk of becoming obsolete. In a sense technology is like a fashion trend: we have something new this summer, but as soon as autumn arrives a new framework that promises help us code faster takes the lead. Unless someone deliberately chooses to ignore the latest trends, there is just not enough time to become really proficient with a single technology. I usually think of technology as software platforms, libraries and frameworks.

Software platforms are the environments on which the code is executed (.net, nodejs, Java). I like to think about software and not hardware platforms because software platforms are often able to run on different hardware platforms i.e. java can run on a mobile, desktop or server platform.

Software libraries provide a very specific functionality that can be used in multiple projects i.e. JQuery purpose is manipulation of the DOM. They are methodology agnostic which means they’re really flexible when it comes to workflow types. This property makes them easy to be reused and ported between team, jobs and industries.

Frameworks often provide a set of libraries to accomplish something more complex. We even have application frameworks such as Spring, which handles everything from retrieving data to displaying it. Or Angular which provide us with the tools to create a presentation layer and communicate with the backend. One difference between a framework and a library is that a library provides just you with the tools to do things while the framework also enforces a (often highly opinionated) way to do things. This makes it harder to integrates them on an ongoing project (as opposed to a library) but are a great choice if you are starting from the ground up.

Most of the time, software libraries and frameworks are tied to a software platform, so you naturally learn the ones that run on your platform of choice (like Java or nodejs). Sometimes ports of these libraries and frameworks can be made (like hibernate to nHibernate), but most often than not they will make some adjustments to take advantage of the platform particular characteristics (meaning there are changes on the API).

Industry

This is often a byproduct from working on a project. As a software developer you really don’t study accounting unless you are creating an accounting software. Or banking. Even worse, sometimes we just limit ourselves to create what the customer requirements document says, without even trying to understand the purpose of the software or the needs of its users. Eric Evans pointed this out and explains that the reason is because this kind of knowledge is not useful to us unless we intend to keep on the same industry (like manufacturing). In other words, its reusability scope is very limited when compared with the other kinds of knowledge. However as Evans also explains, a deep understanding of the industry it’s necessary if we really want to create not only a good thing but the right thing.

Mix and match

The time you spend on each of these kinds of knowledge leads to a different set of abilities. Try it out!

  1. Evaluate yourself on each of these kinds of knowledge
  2. Select the area you’re lacking the most (principles, Frameworks, you pick)
  3. Make a 3 month plan to improve
  4. Start over ūüôā

As always, your comments are welcome!