Code is the easy part

When I shared what I’ve learned about DDD from a “boring” domain¬†some people wanted to see the code. Somebody even said “Show me the code or it didn’t happen!” ūüôā

On the one hand I understand that for programmers code is the tool of work, this is how we solve problems. On the other I was dissapointed, because in my mind code wasn’t the most interesting aspect of that project and in the post I intentionaly focused on those other aspects – how even in trivial projects learning more about the domain matters, how that knowledge is deepened and distilled over time, how business and technology interact.

But some time later I realized I was the same. For years I had been waiting for a “really interesting project”, for my holy grail of complex domain. Of course, I worked on interesting projects, occasionally solved really complicated problems… but nothing came close to the holy domain of cargo shipping.

Just looking at those large ships and how much stuff they move from one place to another, imagine planning routes, tracking where things are, troubleshooting when things get lost…

I wished I could work on a project like this.

cargo shipping

However, at some point I realized that most software is probably the “boring line of business” kind. Valuable, with the potential to make somebody’s work life hard or easy, but generally not very exciting all the time.

Seems that part of the challenge is that as programmers we think about complexity in terms of number of if statements and nested conditions (cyclomatic complexity). After getting some experience we learn that complexity is also in coupling and scale. After a few failed projects you also learn about the complexity of having too many moving parts and getting too excited about new technologies ūüėČ

But if you pay close attention then you will eventually notice, that in the end technology is the easy part. I often noticed that technology was made¬†the hard part even though it wasn’t necessary, because of overengineering, implementing features that nobody used or premature optimizations. But the real complexity was elsewhere.

Take the “boring” domain of personal finance. There’re literally hundreds of books on personal finance, thousands of blogs, and thousands of experts. Each saying different things and claiming they know the best, all the other guys are wrong. They make up their own vocabulary. They argue and challenge the “common wisdom”. They rarely agree with each other on anything. It’s easy to get overwhelmed and lost.

money

But after reading a few books you start noticing common themes, you distill the knowledge. You pick things that make sense for you, for your lifestyle, that fit¬†your personal situation. At this stage you can start making decisions on what is important and should be explicitly modelled, and¬†what can be safely ignored. You decide how optimal your solution should be, what are the trade-offs you’re willing to accept.

Often you ask experts for clarifications, but you know what you’re after, more or less. You’re not just a passive listener¬†that waits for directions, you understand the assumptions and constraints, become an active participant in defining requirements and designing solutions.

In many projects the Domain is the hard part. If you solve a problem that has never been solved, or that hasn’t been solved in that specific way, then nobody is the expert in the tradidional sense of the word. You have to come up the “right” approach together with the domain experts, you need to collaborate. There are no “ready” requirements that you can just write down, it’s a very creative work.

Even more interesting is the situation when you have multiple experts or stakeholders, who can’t agree with each other on the priorities. Yet, you need an agreement in order to write any code. As many observed before me, most people don’t really know what they want, but they’re absolutely sure it’s not the thing you created for them. Or you might discover that the “official” reason for a project is not what you thought, and you¬†optimized the wrong criteria or got hurt by office politics. That’s the People complexity.

I could go on and on and on… but you get the idea. I agree that technology is important, and always will be. We need to learn our craft and be fluent with the tools. But that’s simply not enough. There’re other kinds of complexity – domain, people, and more.

If you want to create great software that matters you need to take into account all those kinds of complexity. To me this is what DDD is about. It’s a¬†tool for tackling the ultimate complexity in the heart of software. Technology is just one aspect, and often¬†the (relatively) easy one.

real complexity

If you’re interested in hearing more, that’s one of the things I want to cover in my upcoming talk at DDD Europe.

Business or technical decision – which one is that?

It’s been a long, long time since my colleague said that “if the business can’t give us better requirements, it’s their problem, I’ll just do what I think they had in mind”. But I get frustrated every day with systems that apparently¬†were created using that approach.

I think the essential problem is that we, programmers/designers/makers, very often don’t have¬†enough “business” knowledge around the system we’re building.

I’m not talking about having more user stories or adding more detail to them.

I’m talking about the fact that it’s impossible to build a great¬†product if you don’t understand the business around it.

It’s not just hard. In the long run¬†it’s simply impossible. Because sooner or later you’ll make something that will ruin your system, that’s inevitable. Maybe you’ll be lucky and not many people will be affected. But if you don’t have enough context, you’ll keep making¬†bad decisions over and over and over again. Interestingly enough, you might not even realize you make any decisions, because you make assumptions without noticing.

After a while your only hope will be lock-in and competition that is even worse, but who wants that?

If you don’t know how your target audience thinks, what they value, what mindset they have, then how can you make sensible technical trade-offs? Is speed the priority? Or rather ease of use? Or accuracy? Or pleasant design? If you do know that, then do you actually keep that in mind when you develop every new feature or fix every bug?

If you don’t know what’s the relative importance of the specific qualities of the system you’re building, then how can you judge if the design you selected is optimal? What criteria do you use to dismiss alternative approaches? Do you even bother to come up with a few alternatives?

Last but not least, how often and for how long do you think about business consequences of technical decisions you make?


On the one hand we brag¬†that technology is making the world a better place, on the other it seems we don’t fully realize how big impact it has on daily lives of many people when it doesn’t deliver on the promises it makes.

A few small examples from my personal experience as a user:

For a long time I looked for an app to learn German vocabulary. Finally, I found something that looked like what I wanted. The content was interesting, I had lessons to every video, it was self-paced and had revisions. I was thrilled and right after the trial I bought 1-year access… and soon afterwards I stopped using the app completely.

Turns out the “learning” part is very rigid and I have to work around it. The content is not ideal, so I have to learn words that I don’t even know in English after learning it for 10 years. That’s¬†on a newbie level (sic!). I have to misuse the app to dismiss the words I’m not interested in learning, because apparently nobody thought that ability to customize what I learn would be useful. Then on some days¬†suddenly I have (literally!) hunderds of words for revision, even though I didn’t¬†fall behind the schedule.

Talk about demotivating and overwhelming.

So my idea was to keep using the content (as it is¬†really interesting) and use another app with more sensible revision part for learning vocabulary (by manually entering vocabulary¬†I want to learn). Great idea, but I¬†thought¬†about doing it 2 months ago and still haven’t¬†even started. I’m scared of opening the app, because probably all my 1000+ words are due for revision.


As a language learner I want an app that doesn’t force me to learn useless vocabulary, doesn’t torture me with boring content and doesn’t push me to work at a too fast pace, so that I don’t end up abandoning it and feeling miserable about not learning anything (again!).


Another example is generating invoices from the freelancing portal. For whatever reason (maybe local law?) the invoices are generated on a weekly basis, but the Polish tax authority requires accounting everything on a monthly basis.

Of course, I can manually reverse-engineer all the costs, all the data is there, no problem. Only it takes time and costs extra money for the accounting services, not to mention the “fun” of doing currency conversions and corrections 5 times more times than necessary every month (as I have to make that conversion for every invoice I submit, plus correct when I transfer¬†money to¬†my account). On top of that, I can’t be sure how¬†the tax inspector will judge my creativity when they analyze my documents.


As a freelancer I don’t want to spend hours manually crafting¬†reports that could easily be generated automatically (or semi-automatically) from the data you already give me, in a format that my tax authority¬†demands, so that I can sleep well and not look for the first opportunity to stop using your portal as soon as a better opportunity arises.


Of course, those are just two tiny examples, there are many, many, many more. Once you start noticing such issues, it’s impossible to unsee them. And it’s all too easy to put myself¬†in the shoes of the people¬†that created those features and wonder if I’d¬†even think about scenarios that now drive me nuts.

It’s not about the need for better user stories or being a more responsible programmer.

It’s realizing that nowadays many businesses are shaped by technology. For better or worse.

It’s about considering our work not only in the nice, sterile, non-existing box of technical requirements, but also in the context of how it impacts business and users. It’s about considering the business impact of decisions disguised as purely technical.

Because¬†it might be more efficient to generate reports on a weekly basis and your task might be to optimize DB performance, but tax law specialists might tell you that’s problematic in some countries. If you ask them.

Because the acurracy of the vocabulary revision algorithm may be ideal and that might be one of your app’s selling points, but the expert teacher might tell you that encouraging regularity and persistence is more important than precision.¬†If you ask them.

At the end of the day, it all comes down to asking constantly How this technical decision will impact business and users? Who should decide if that impact is OK?

I know that many people think PM/BA/everybody-but-them should worry about such things. In my experience assinging such responsibility to a specific person or group is only useful when you¬†look for somebody to blame for yet another disaster.¬†If the “makers” don’t think about it, then they’ll make a lot of decisions that weren’t really their to make.

For better or worse.

Beware of proxy domain experts

Today I’ve watched Greg Young’s keynote¬†from DDD eXchange 2016. The talk is really awesome, though-provoking, turning everything upside down… I really recommend.

However, the point that caught my attention most was the answer to the question from the audience (at the very end). Greg mentioned that we need to be very careful with who we consider domain experts. He even said that on one project their end-users hated the app, because their “domain experts” actually had no idea about the work that end-users were doing.

I’ve experienced that mistake myself, in one of my summer jobs. For a couple months I worked in a call-centre for a mobile operator.

When you call somebody in the middle of the day to talk about their soon-expiring-contract with a mobile operator, what do you think is the most common answer?

I need to think about it/I can’t talk¬†right now, please call me at XYZ time.

Pretty obvious, right?

The only problem was that it was impossible to do, because the calls were assigned randomly to people and it was impossible to make sure the call was assigned at a specified time! You could specify the preferred time range, but more often than not it didn’t work as you’d expect.

The result?

People entered random information and date in the system, wrote everything down in their paper calendars and handled the whole case outside the system. Some time later another unlucky operator who got that call assigned had a very bad day (you won’t believe how angry people are when you have no idea what they told your colleage a few months earlier and what they asked them to do back then).

In the end the system was an expensive phone book, that pissed off a lot of people, both working there and those that got the calls. The work was hard, stressful and annoying enough in itself, and the software we had to use only made it much worse instead of helping.

That’s what happens when you don’t realize you’re dealing with proxy domain experts.

Master paradigms, not syntax

Every now and then a programming newbie asks this question: what language should I learn? That of course is then followed by a long discussion with lots of strong opinions and no consensus.

That newbie decides to learn one of the suggested languages and gets the first job. Then they ask: what X frameworks should I learn? (where X refers to their chosen primary technology). A very similar discussion starts…

Then around an intermediate level the typical programmer starts freaking out on the point of becoming obsolete. Somebody suggests to learn a new language every year.

And it goes on and on and on…

I’ve asked those questions myself, multiple times, various people. But at some point I’ve realized that they don’t make much sense, and the answers even less so.

I think what matters is really just two things: to grow our skills over time and to not lose passion among daily struggles.

For the latter reason, I’d say it’s reasonable to just learn whatever you like and find interesting. Sometimes we have a particularly boring or depressing (think uber-legacy) project¬†at work, or our coworkers drive us crazy. Having some pet project, reading an interesting book, watching a mind-bending presentation reminds us why we still keep doing it, despite all the challenges. I don’t think the importance of it can be stressed enough. In that case it doesn’t really matter if and how soon you’d be able to apply what you learnt at work. The purpose is different.

But there’s that other thing, more difficult, especially given that in most jobs we don’t have much¬†support in planning our career. Heck, most people in IT can’t¬†even believe there are people that keep programming for 30 years, we ask where do the old programmers¬†go, so why would you plan for staying that long?

While I think coming up with a 30-year learning plan is insane (or even a 5-year for that matter), it makes sense to consciously think what¬†paradigms and principles we’d like to learn. They don’t change that often, they get refined over time, but the underlying ideas are relevant for years and it’s quite easy to catch up with the newest developments. Mastering the syntax of the new tool is relatively easy, if you understand what problem it solves and how it works on a high-level. Of course, there’ll be quirks, gotchas and edge-cases, but those you learn by doing, very often on a project you’re paid for (let’s be honest, most problems don’t manifest in pet-projects).

To make the learning efficient it makes sense to use the technology that is restrictive and will guide our learning in terms of principles. Taking languages as an example, hybrid languages are not the best way¬†to learn functional programming. ¬†I’ve learned from experience that it also makes sense to invest money and learn from the authorities in the given subject. They spent a lot of time distilling their knowledge and often package it in a easy to digest way. If they’re good teachers they will guide you instead of just talking (so you still get all the joy of discovery ;)) and will cover most important principles, so you can continue learning on your own.

But to the point, for me the biggest jumps in skills as far was learning about clean code, testing, requirements, DDD, functional programming, messaging, actors and event-driven architectures. Even when I didn’t use the relevant tools at work right away, my way of thinking changed. My designs got better. I was able to come with a few completely different approaches to solving the same problem, and thus pick the better solution. I could foresee some challenges and prevent them.

To me the biggest benefits of learning about various paradigms is¬†having more options and making better decisions. Because picking the best tool for the job shouldn’t be considered on the syntax level, it’s a paradigm-level decision.

Mechanical sympathy – not as low-level as you think

Last week I had a pleasure to attend a 1 day¬†workshop on “Understanding Mechanical Sympathy” by Martin Thompson.

The special thing about this workshop, and Martin’s work in general is that he convinced me that performance optimizations are not black magic, assembly tricks. If you think otherwise, I encourage you to watch his¬†“95% of performance is about clean representative models”¬†presentation.

Besides, he’s a great teacher – the knowledge is distilled, complex things reduced to simple basics, explained in a straightforward way. Last but not least, even though the exercises and presentations are using¬†Java, the lessons can be applied to any other programming language. For the workshop the basic knowledge of Java was sufficient.

So what did I learn?

Clean code leads to good performance

I did learn that at the uni, I’ve seen that before, even in Martin’s presentations, but only now it finally clicked for me. Martin spent a few hours (literally!) explaining how CPUs work and how they evolved across a few models. Before the workshop I believed him that clean code results in a good performance, now I feel I also understand why.

It comes down to a few simple rules. For example, one¬†must realize that CPU is a mini-distributed system. Every level down the architecture diagram (so registry, L1 cache, L2, L3, etc.) is more expensive with regards to the communication in terms of latency. On the other hand , every level up can store less data. If your class doesn’t fit into that limited space,¬†then you might be wasting a few cycles for getting necessary data to the registers¬†when its needed. Also typically¬†processors have a higher number of ALUs than for example JMP units. They also have dedicated units for performing operations on matrices and vectors. All that comes down to the fact that CPUs are better in arithmetic than in evaluating logical statements. All¬†conditionals (loops, ifs, etc.)¬†are¬†expensive.

Another important point is that¬†CPUs try to optimize the execution of our code and make a few bets: they assume that things which¬†are close to each other will be used together, things which¬†have been recently used will be used again, and that memory access will follow some kind of a pattern. That improves the performance of a “typical” (or should I rather say¬†well-written?) code, but if you’re code doesn’t follow those rules¬†you’ll pay for it. To be fair, the¬†CPUs¬†don’t expect¬†anything wicked.¬†On a higher level the hardware-friendly code can be translated to a few basic rules of clean code: small classes, high cohesion, short functions, low cyclomatic complexity, keeping loops very short and simple, etc.

I’ve never heard anybody else making the¬†argument that clean code leads to good performance, and I think it’s a great shame. I regret now I didn’t use this argument in my previous job when advocating for improving code quality. And that I didn’t know how to measure it and show¬†its impact. A few things I want to learn now after the workshop.

Things can go wrong when you measure performance

This is one of the areas I’d like to learn more about. Martin mentioned a few things to consider when measuring performance. Micro-benchmarks are generally hard to get right, even harder is to measure things that actually matter.

He suggested focusing on a higher-level tests, kind of end-to-end ones, which use realistic data and realistic use cases. The last two are very important, because compilers, etc.¬†tend to be smart and will optimize our code (e.g. remove paths that will never get executed for our crappy data, even though they’ll be for realistic one).

Gil Tene talked more about such things in his “Priming Java for Speed at Market Open” presentation. Even if you don’t use Java it’s worth watching to get an idea what can be really happening when your code is executed, especially if you use JIT compilation.

Locks are evil and concurrency is hard

I knew it before, but I didn’t realize that communication between threads¬†using locks might be slower than over the network. Apart from examples, we’ve heard a few “tales from the trenches” which were both funny and scary at the same time. Realizing you got your basic data structure¬†wrong after over a year in production is not a place anybody would like to be one day.

Pro-tip for work: if somebody suggests using concurrency and claims it’s easy, then it’s time to¬†run! They’re dangerous.

I think it’s worth a deeper thought that one of the best known experts on performance optimizations and concurrency in Java is saying that. If LMAX¬†could do¬†with just a single thread for business logic, then 90%+ systems in this world could also probably manage.

Martin ends his “The Quest for Low-latency with Concurrent Java” with Albert Einstain’s quote:
“Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius, and a lot of courage, to move in the opposite direction.” I let you guess where concurrency fits in it.

It’s all about the basics… and great¬†teachers

We have lots of hypes in programming. Every now and then somebody writes that everything has changed and people get worried how they can ever keep up with the pace of change.

After Martin’s workshop I have one more example that hypes come and go. Performance seems to be an ever-green hype, every year we have more data and want to process it faster, or we have more users and want to give them even better experience. Luckily, it seems¬†that¬†principles don’t change that often. If you understand the underlying principles then you can learn the syntax of a new language, master 95% of API of a new framework, or understand impact of new hardware features very quickly.

At the same time a lot of the complexity we deal with in our daily work is unnecessary and generated by ourselves. Because we overcomplicate things and copy-and-paste without understanding what happens under the hoods, maybe¬†we know what and how to do something, but don’t really understand why.

To be honest for me hardware and all the “low-level stuff” was one of such things that I never could fully grasp. It just didn’t seem relevant or as important as other things I could spend time on. Martin convinced me otherwise.

I’m not sure if performance will become my great passion, but even if I stop at the level of “20% of knowledge that gives 80% results” that will be great. At least now I understand where to start and “hardware and all this low-level stuff” seems less scary than ever before.

Summary

If you ever have opportunity to attend Martin’s workshop, go! It doesn’t matter what language you use or how high is the level of abstraction you operate on – it all runs on the same hardware. Learning a little bit about it will make you a better developer.

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 ūüôā

To DDD or not to DDD – Is my model right?

  • “I’m new to DDD, please, help! Can you review my design?”
  • “Can you recommend some DDD code samples?”‘
  • “Why the’re not more DDD samples out there?”

Have you heard any of those before? Maybe it was you asking?

I know how it feels when you are trying to learn something that is really difficult (hello DDD!) and all you hear is “it depends” or “you’re asking a wrong question” (thanks for helping).

The challenge is that both of those answers are true. It’s impossible to give a good answer to any of those questions without having the full context. It’s easy to notice when something is obviously wrong (and you probably know that already anyway), but how do you decide if something is good? How do you know that there’s no better model out there? How do you even know your model is good enough? Is there something like “good enough”? Does DDD come in grades or is it all or nothing thing – either you do it right or not at all?

In that respect DDD is very much like investing.

Some time ago I attended a conference for real-estate investors (landlords). There were many interesting workshops, but my biggest lesson was lunch conversation.

I sat at a table with 3 investors.¬†The first one introduced herself and said she invested in large flats for students and young professionals (flat sharing). The other said it is a really stupid idea. It’s obvious students would ruin your flat sooner or later (he ignored the first investor claiming it never happened to her in the last 10 years). So he invested only in small condos and studios for young working couples. The third observed that small flats tend to have low ROI, so it’s better to buy bigger flats for families. Another advantage is that families¬†change rented flats less often and you don’t have to look for new tenants every few months.

And so it went… For two hours!

It was fascinating. Each investor was making money. Each was happy (and comfortable) with their investment strategy. Each thought that not only is their strategy THE BEST ONE, but that it’s THE ONLY reasonable option. And it was true. Their strategy was the best and only option FOR THEMSELVES.

If you’ve asked them what you should do with your $100 000, each would give you a different answer.¬†All of them would be wrong. Because if you can’t make this decision for yourself then the only thing you should invest in is education. Blindly following¬†other’s people orders won’t make you money¬†in the long term.

Don’t get me wrong. Inspiration is important. Learning from other people’s mistakes is invaluable. It’s OK to ask for advice and consider different viewpoints. The more various options you consider, the better! I’ve learned a lot just by listening to those investors.

But in the end there’s no single best investment strategy and there’s no “right” domain model. You can stop looking now.

The truth is that there are countless strategies and models available. Each has their advantages and disadvantages. Some might be completely wrong, but most would be quite good or good enough for the time being or maybe just satisfactory given the constraints we have. In the end it all depends on your context. And the very important (and mostly ignored) part of that context is… you.

You and everything you know about the business, company and people in there. Your context.

Somebody said that investments are not risky. Investors are risky. ¬†It matters how much you know, what are your past experiences, how well do you get along with your team and stakeholders, how well you deal with pressure, how much risk and overtime are you willing to accept before you talk about it with your PM…

Even if some DDD uber-expert comes to your team for a project and literally tells you what to type for a couple of months, after they leave you’re on your own. Back to square one. Or even worse, because he probably didn’t realize that the “business expert” he talked to is an ignorant know-it-all who has no idea what he’s talking about. He really should’ve talked to that shy, quiet guy in the darkest corner of the open-space. Everybody goes to him when something goes wrong or when they encounter a new edge case.

So don’t fret and start where you are. You already have everything you need at the moment. The rest you can learn by doing and analyzing results. By all means, ask for advice but don’t mistake it with outsourcing thinking.

After doing it 10, 50, 100 times you’d be surprised how much progress you’ve made.

Trust me. Good investors know that there always will be another great opportunity. Good modelers know that there will always be some other good models they could come up with. Don’t get stuck at looking for “perfect solution”. It doesn’t exist.

The better you become, the better will be your results.

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.