Category Archives: English

Good models are discovered

A few weeks ago Philip Wadler said a few interesting things in his keynote Propositions as Types, which he delivered at LambdaDays conference (really great conference, check it out!). The talk was about functional programming, and how its underlying principles were “discovered” independently by various people. I’m sure you know more examples of this “coincidence”, the history of science and human invention is full of them.

The most valuable takeaway for me was the distinction between things that are “discovered” vs things that are “invented”. Things are discovered when their time comes, when all the pre-requisite work is in place, when somebody finally connects the dots. The dots have always been there, though, just hidden. That’s why many people can come to similar conclusions independently using different tools. The representation might be different, but the conclusions, the essence of the discovery are the same.

That is very different from inventing things, which is unnatural, forced, and even if it solves the problem just feels wrong and nasty.

I think the same is true for models and domains.

It doesn’t matter how you reach your conclusions, how many iterations it took you, how many times you re-wrote that piece of code. Maybe you organized workshops, maybe talked with experts over a cup or coffee, or maybe the crucial insight was inspired by an email exchange.

You look back and you’re wondering why you didn’t notice that from the very beginning. It’s just so obvious! Most of the time it’s not even a very complicated thing, it’s just “common sense”.

The main challenge is that things look obvious only when you look back. You can’t connect the dots looking forward. Only when you look back you KNOW that what you came up with is right. Maybe it’ll change in the future, who knows, but it’s right for the time being, for the current context, for the current problem.

For me the most interesting insights came when something didn’t feel right. Very often I couldn’t explain what was wrong with the existing model, at least not at first. But I didn’t let it go, I was a real PITA (usually just for myself) and looked around for answers.

After trying out a few different approaches (even if only on a piece of paper) the differences between models became noticeable. One was simpler and cleaner. The other didn’t explicitly represent an important concept. Yet another had too much noise, some concepts were unimportant in this context and should be dropped.

In software we can represent the same model in multiple ways in code. As long as the underlying concepts, business rules are the same, invariants are honoured, and business goal is achieved, then I don’t see a problem with that. And those important insights could be discovered independently by various developers working on the same project. I know that many people feel differently, but I’m one of those people who simply don’t care about “tabs vs spaces” and don’t have favourite text editor.

It’s been a while since my partner came up with a crazy idea of writing our own Expenses Tracking App. But now and then we still are not sure how could we didn’t see all those obvious things from the very beginning. Even worse, we’re not sure how exactly we did discover them. But we know they’re right, because they fit perfectly to what we want out of this app.

The good news is that if good models are discovered then eventually we’ll all find them if we persist in the search. All it takes is a lot of patience, good listening skills and never being satisfied with the first model that comes to mind… or second, or tenth 🙂

New Year Resolutions – What to learn to be a better programmer?

For the last couple of weeks I’ve been thinking about what should I learn in 2016. What conferences or workshops to attend, what books to read, what paradigms to explore. Then I came across this:

Most of the major academic studies of programming miss much that is essential to the way that professional programmer thinks and feels,” Jonathan Rowson wrote in his book The Seven Deadly Programming Sins. “They are guilty of thinking of programming as an almost exclusively cognitive pursuit, where code is written and understood only on the basis of mental patterns and inferences.” In reality, he wrote, if you want to become a great programmer, or even a good one, “your ability to recognize and utilize your emotions is every bit as important as the way you think.”

Teaching programming is really about teaching the habits that go along with thinking,” Spiegel explained to me one morning when I visited her classroom. “Like how to understand your mistakes and how to be more aware of your thought processes.

Two of the most important executive functions are cognitive flexibility and cognitive self-control. Cognitive flexibility is the ability to see alternative solutions to problems, to think outside the box, to negotiate unfamiliar situations. Cognitive self-control is the ability to inhibit an instinctive or habitual response and substitute a more effective, less obvious one. Both skills are central to the training Spiegel gives to her students.”

It’s uncomfortable to focus so intensely on what you’re bad at,” Spiegel told me. “So the way people usually study programming is they read a book about programming, which can be fun and often intellectually amusing, but it doesn’t actually translate into skill. If you really want to get better at programming, you have to look at your programs and figure out what you’re doing wrong.

Shocking? Familiar? Obvious?

Whatever you think, I made that up. The article I’m “quoting” is not about programming, but training chess champions. I replaced all words related to “chess” with “programming” (including the book title).

I know nothing about chess, but I feel we could learn a few things from Mrs Spiegel.

“Show me the code or it didn’t happen” told me my colleague after the my last post. “Good idea” I thought at first. But after giving it some more thought I’m not so sure about its value.

I think it was Leslie Lamport that said that code is the easy part of programming. Once you know what to do and how, writing it down is relatively trivial (note, I said RELATIVELY).

I sometimes wonder if it’s not even worse. If in some cases code isn’t just a distraction. Because once you see code, it’s hard to focus on anything else. Like whether that code should be even written in the first place. Often implementation doesn’t matter as much as we’d like to believe.

Tweet 1

Alberto Brandolini said that “Software development is a learning (thinking?) process. Working code is a side effect.

Seems weird to me that we focus so much on side effects.

Sure, there’s a place for learning implementation techniques, and details are valuable. It’s the foundation of our work. But I think our focus (i.e. how much time and effort we spend on that, compared to all the other things) is not quite right.

So what Mrs Spiegel would do if she was our teacher?

Most of us probably think that Spiegel was teaching the kids programming. Of course she often passed along specific knowledge: design patterns, programming paradigms, etc. “But most of the time,” Tough writes, “it struck me whenever I watched (Elizabeth Spiegel) at work, what she was really doing was far simpler, and also far more complicated: she was teaching her students a new way to think.” More than that, she was teaching students how to think.

Sounds like a good goal.

Now I only need to figure out how to do it.


Thoughts inspired by (in random order):

  • The article mentioned above that my CEO shared a couple of days ago.
  • Avdi‘s post on 10x developers.
  • Dijkstra’s letter in which he argued why it’s better to teach students Haskell rather than Java.
  • Rinat Abdullin‘s Lokad.CQRS retrospective, in particular Limitation #1: “Lokad.CQRS made developers focus on low-level implementation details, instead of high-level domain design”.
  • A few “X common DDD mistakes” posts/presentations I’ve seen. Incidentally, all of them mentioned too much focus on technical aspects and not enough attention devoted to the so-called “strategic design patterns”.
  • Recent presentation on DDD and CQRS I watched. It lasted over 1hr and the domain was mentioned very briefly only once, and no earlier than in the Q&A session. I still don’t know what problems prompted the team to use this approach, and whether in retrospect they think it was a good decision. But at least they showed lots of (infrastructure) code. There was “lots of meat” (as we say in Polish).
  • A couple of posts written by passionate programmers whom passion led to severe burn out.
  • Countless other loosely-related things, including but not limited to the recent comment from my ex-collage related to the system I used to work on, agenda for some DDD workshop I saw, and comment on another of my articles on a completely different subject published on another website. FYI, in my brain everything’s connected to everything else.

To DDD or not to DDD? What to do if your domain is boring?

I’ve heard many times that DDD should be applied to complex, interesting domains only. Even some experts that I deeply admire say that, so it must be true, right?

The problem is that I’ve never heard what exactly makes a domain interesting or complex. Especially, what makes it interesting or complex enough for the purpose of DDDifying it. I think the problem is we’ve been asking the wrong question here.

This tweet by @DDD Borat summarizes my thinking perfectly:

borat

But first let’s have a look at two examples that shaped my opinion on the subject.

Case study # 1. Anemic domain model. Boring, boring, boring LOBA (BBBLOBA).

A few years ago I’ve worked on an e-commerce system. We’ve covered basically everything you could imagine online store does, starting with displaying catalog, managing promotions, calculating prices, checkout, through emails, payments integrations, to all the backend stuff that customers never see, like refunds or shipments integration.

The business logic was randomly divided between controllers, data access classes and stored procedures. There was no business logic layer whatsoever (at least not when I started there).

One day I was particularly frustrated. Looking at yet another property bag which was proudly (and inaccurately) called our domain entity, I mumbled something about Anemic Domain Model. My colleague heard it and he sighed. “Yep, no wonder we have anemic domain model here”, he said. “There’s no interesting business logic. That domain is just soooo boring.”

I didn’t know what to say. I’ve just spent a week tracking how refunds are calculated. I found a bug, which was rejected by our QA saying “It’s too complicated, I’m not raising it”. If that wasn’t an interesting piece of business logic, then I have no idea what else it was. So I only nodded my head in faked agreement and went back to work.

Case study # 2. Domain crunching applied. Boring, boring, boring pet project.

A few months ago together with my boyfriend we got really pissed off with the mess which is called our personal finance. We didn’t know exactly where our money went and how much we spent. We used Excel before, but that didn’t seem good enough anymore. Our finances got more complicated over time. Also our expectations were higher. After a few years of tracking expenses, we knew what we wanted out of the app.

We did some research, I checked dozens of apps and none of them fit our criteria. We could hack them to fit our needs and do some calculations outside of the app. Instead we did what any programmer would do in such a situation – we decided to write our own.

Now this surely is the most boring domain one could imagine, right? Apart from maybe a TODO list, it’s the most popular pet project ever. Every programmer writes it at some point.

But over the period of a few months we’ve learned a lot about the domain. I think we can say we did the proper domain crunching. I acted mainly as the annoying customer/business expert, who is never satisfied with what they get (I’m absolutely brilliant in this role). Often I didn’t know what I was after, but I knew exactly when something felt wrong.

The first insight was that in fact we have two main parts in our app, which are to large extent independent. Tracking and analyzing. That fact impacted our model in significant way.

For example accounts are very useful for tracking. I can compare the actual total on one of our 11 accounts and the data in our app. If there’s a difference I can start looking what I missed this time. FYI I can’t force myself to enter all transactions every day, so it’s extremely important that identifying what transactions I missed is convenient. Accounts are perfect for this.

On the other hand I don’t care about accounts at the analysis stage. I don’t care if the specific payment was made from my personal account, our joint account, or my boyfriends wallet. Consequently, why in the world would I filter my expenses by account in reports? It gives me no actionable insights whatsoever. Adding such a feature would be a waste of time.

You might think “Isn’t it obvious? What’s the big deal?”. This is exactly what shows that we’re on the right track with modeling our domain. Afterwards it seems like the most obvious thing under the sun. But I can assure you it wasn’t that obvious when we started. Plus, most apps DO reports by account. Don’t ask me why would anybody use this. I have no idea. I wouldn’t.

Then we hit our first problem. I’m self-employed, so I pay taxes and health insurance myself. It’s not really an expense, in the sense that I can’t do much to make it lower. So from the perspective of optimizing expenses it was only a noise. Yet, it showed on my account and it was useful to track in some way. At first we added a flag which indicated whether the specific expense should be included in analysis. But after a while we’ve realized we have a missing concept here – an income cost. We have other expenses that shouldn’t be included in reports, but tracking my income costs on its own is actually useful information. Making this concept explicit made both things easier and less error-prone.

The next challenge came from my boyfriend. He does a lot of business trips. He covers expenses during his trips himself, and then his employer returns the money in the next salary. He goes mainly to countries more expensive than Poland, so those expenses are rather high. They completely ruined our analysis, and made tracking all expenses challenging. We still wanted to track those in the app, so we don’t forget to check if the money was returned, but those weren’t just normal expenses like groceries. That lead us to discovering another new concept – reimbursable transactions.

Since I occasionally lend money to family or friends we thought about explicitly modelling loans too. After giving it some thought we decided that using reimbursable transactions in that case is good enough. If we ever need more detailed distinctions between those two types of transactions, we can adjust our model. For now it’s good enough.

We’ve made many more discoveries like those described above. We used the app, noticed that something feels wrong, discussed it and refined our model. With each new discovery, our model got cleaner and made more sense. Looking back we were surprised we didn’t come up with all of this from the very beginning. It looks so obvious!

Back to DDD Borat

If you think about this, an e-commerce platform is way more complex and interesting than a personal finance app. Or is it?

I think we’ve been asking the wrong question here. It’s not about the domain per se. It’s not that one domain is more interesting or more complex than the other. Being interesting (whatever that means) is not an intrinsic characteristic of a particular domain.

What makes a particular domain interesting are problems you are solving.

In many cases it doesn’t make sense to go with your “domain crunching” very deep and some basic, off-the-shelf model, or slightly customized solution would do. If you can get away with CRUD, then by all means, do CRUD. If you’re a physicist then a bird is a bird, that level of abstraction would do just fine. It wouldn’t work for a biologist though.

The other thing that makes a particular domain interesting is you.

Can you notice when your model is not good enough anymore? Do you know when it’s time for a re-modeling session? Do you ever talk to your domain experts using their language? Are you truly interested in their problems and how to best solve them?

If not then no domain would be “interesting enough” to justify using DDD.

No excuses

So don’t let the popular myth to hold you back. You can apply the so-called “strategic design” principles even on your pet project.

In our case applying DDD concepts to the pet project pays off. The app is easy to use, we make fewer mistakes than in the beginning. When it was a simple CRUD app, I messed something up at least few times a week, because I forgot what flags to set in what situation. Fixing my mistakes could take us anything between 10 min. to 1 hr. Now each concept is modeled explicitly and I have no doubts how to enter all transactions, even when I’m particularly tired.

In many ways our app is simpler than the apps available on the market (e.g. our “budgets” are primitive), but it’s more sophisticated in other aspects. Above all – it makes sense to us.

To re-write or not to re-write. That is the question.

Thanks to discussions around a post for a company blog I came across the paper “An Agile Approach to a Legacy System”. It’s been published 11 years ago, but I’m surprised how relevant it is today. It reads like a novel, so I really recommend to give it a go.

A few things that really resonated with me:

– Legacy code is not (only) a technical problem. The authors mention that trust and politics are important factors. Like it or not, you can’t go away without it and very often “human factors” determine whether you succeed or not.

– If you want to build something better than the legacy system then you need to focus on the users. Find their current pains and solve their problems, provide business value. If you do your job well they’ll become the biggest advocates of your work.

– Take care of yourself and your team. Take breaks, don’t overwork yourself. Take time to bond. Take pride in your work. Work on interesting problems and have fun!

– If you rewrite legacy code you’ll reproduce legacy system. Since I’ve worked on a few systems that have been rewrites of the legacy I know what they’re talking about here 😉 You can throw in new shiny technologies and come up with better architecture diagrams but it still doesn’t feel quite right.

There is also a list of “case-studies” for projects where this approach was used.