Implementing for today (not for tomorrow)

When we start programming professionally for some company it’s too easy to fall in the situation of implementing something with too many just in case’s, or what if’s.

I used to say that we were taught that way when we studied Software Engineering or Programming, but now I’m not that sure about it. I think that we just didn’t get the point. When we were told about writing reusable code we automatically thought: “okay, this is about writing code today so that I can reuse it tomorrow, right?”.

Then we realize that we really don’t know what the requirements will be tomorrow, and we end up with lots of awesome classes and methods and interfaces we wrote that are now completely useless. Now we need to maintain them and they are difficult to adapt, so in the short term they start to smell badly and within a couple of months that code is completely rotten.

So, the solution seems to be easy at first:

Implement to fit the requirements of today. As long as your code fits the SOLID principles, KISS and DRY and a couple more, you are safe and sound.

First thing first: we software engineers are cool when inventing acronyms; aren’t we?

Okay, but let’s go to the point…

The problem is that sometimes you come up with some solution that is “surely” SRP but only “poorly” OCP, “reasonable” LSP and “yeah, why not?” DIP.

Then you ask some workmate and he suggest an approach that is “pityful” SRP but a “confident 100%” OCP.

Regarding patterns, sometimes Iterator is almost okay but it makes the “iterated” a little bit couple to the “iterator”. Sometimes the best approach is not easy: Adapter, Mediator or Proxy?

Regarding object oriented detailed design: inheritance, interfacing, delegation or just composition?

Which one is better?

Let’s consider an example like the following: you have to implement a system that handles employees. Some employees are paid in a month rate and other ones by hour, some other ones have a basic income and the rest depends on the sales rate they achieve in that month. Finally some other ones can choose how they want to be paid: by hour or in a month rate.

Regarding the database, it’s easy to identify an inheritance in the Entity Relationship diagram. Inheritance is designed in one of 3 ways:

  • Implement the parent table and the children tables
  • Implement only the parent table
  • Implement only the children

Regarding the code, you can go for the Template Method pattern and use inheritance with an abstract Employee class and the actual Employee types inheriting from it or go for a Strategy pattern and use delegation (assuming .NET programming) to calculate the income.

That’s what it comes to my mind as a first approach.

So, which one is better?

It depends.

It depends on what? We implement for today, don’t we? So there must be a perfect solution to this problem.

But silver bullets never ever exist in software, d’you remember?

The trick here for experienced developers is to anticipate to the change somehow. If I was in such a situation like the one depicted above I would ask my customer something like:

  • Is it possible that a customer changes his / her income mode?
  • Is it possible that new payment options arise?
  • Is all the employees data required to be loaded in every operation?

Going back to the database, we know that if we use only one EMPLOYEE table we will have lots of nulls for those columns that don’t apply for some specific payments. That’s not cool, we are wasting lots of disk space. If we use the “children-only” option then we will have lots of redundancy in the common columns (again, a waste). Finally, if we use the parent table AND the children we will need a JOIN to load all the employee information, which may damage the performance of the overall system.

About the code, we all know that inheritance is hard to maintain because if new children classes appear and they don’t fit in the common parent we start to have several levels of hierarchy and in a couple of years we have a hierarchy too rigid, hard to maintain, hard to test and hard to refactor without breaking anything. On the other hand, if payment options don’t change then the Template Method may be easier to understand and more natural and elegant to use than the Strategy pattern.

So, software designs aren’t often good for every single situation. Solutions are good for some requirements in a certain point in time, and we should base our decisions on that. As long as we have a clean design, if eventually we need to do a change and then we realize that our code is not prepared for that kind of change, we refactor with the support of our tests. But let’s face it: there’s no perfect design. It depends on the requirements. Even the very best piece of software design may fail the SOLID principles under some twisted change of requirements. Let’s embrace refactor, then.

The important thing to get here is that, when we need to give some solution to a certain problem we need to find several solutions so that the right questions arise and therefore those questions will lead us to choose the more appropriate solution according to the answers we get. Then we choose the simplest, cleanest, SOLID-est solution ever possible for today’s requirements, anticipating tomorrow changes if (and only if) we have a strong certainty what those are.

Mentoring

Currently I’m working in a team where almost everyone has fewer experience than me regarding .NET technologies and Web development. I have to recognize that I have been programming in .NET for about ten years by now (not all the time, I hate when I’m asked this question when applying for a job position because I consider it plain stupid: no one does the same thing for more than a couple of months).

But I still have little experience in web, just a couple of years of ASP.NET development and a couple of years more in PHP when I started to work as a professional developer… and I really remember little of PHP programming.

So, at the very beginning we had to get things done and we were little experienced. I put in the senior developer shoes and started studying ORMs, Dependency Injection tools, the new stuff in ASP.NET MVC 5, jQuery, Bootstrap, AngularJS, SharePoint…

And started to train the rest of the people in the things I read and learnt on weekends. Did that made my an expert in something? Absolutely not, I just wanted to share what I was learning with my pals.

Eventually I had the opportunity to do some speech in a software event. Several of my colleagues were invited to participate as well, but they were a little bit reluctant at the very beginning:

– What if there’s someone who knows more than me and corrects me or fools me in public?

I haven’t talked in public more than just a few times, but I’ve never found someone that rude. People go to events with a positive feeling of learning something or sharing some insights or knowledge about the topics covered in the talk; it rarely happens that some expert in something goes to some talk just to fool someone… and I think that the audience would not have fun with such a troll.

If that eventually happens, there are ways to workaround uncomfortable situations:

– Hum, I’m not sure about that; maybe you’re right.

– I agree with you at some extent, but…

– I don’t have the answer right now; lemme check it and I’ll come back to you then; could you give me your e-mail address after the talk, please?

– I see your point but you have to consider that…

– If you don’t mind I’ll be glad to discuss this issue with you after the talk, now let’s move on to the next topic so that the audience don’t get bored and we don’t run out of time, I hope you understand, d’you agree?

And don’t be afraid of saying that you’re wrong. Be humble upfront. If you feel that you know a little bit about a topic then share it! You can just start being humble: “hey guys, I’ve worked with this some time but I don’t know yet all the gory details about it, you know”. Besides, realizing that you’re wrong some time after you wrote or said something is ok, it means you’ve continued working on that, it means that you’ve learnt, you have a deeper understanding on the topic. That’s an improvement, good for you!

Please, don’t get me wrong: I’m not saying that it’s good to talk about something by merely reading about it. It’s good to train, to play, to research a little bit further and then talk about it or teach other people about it.

To give an example I was asking my workmates to avoid conversions such as “.ToList()” just to iterate on a collection with a foreach loop because it’s non-sense, but then I was introduced to EntityFramework and the problem of buffering a query in EF to avoid keeping connections open, so I had to go back and say: “Hey dude, when I said: don’t use .ToList() never, ever… ok, when it’s about EF things are not that easy…”.

So, I’d like to emphasize: share your knowledge with others. If eventually someone finds a mistake in something you said or wrote that’s cool, you can learn from your mistakes. If you don’t share your insights there’s little room for improvement and learning. No-one will blame you for being wrong. All of us are eventually wrong about something, and that’s okay.