I see this often with both new and old developers, they have one way of doing a thing and when presented with a new problem they will fall back to what they are used to even if it’s not the optimal solution. It will probably work if you bruteforce it into your usual patterns but sometimes, a different approach is much easier to implement and maintain as long as you are willing to learn it, and more importantly - know it exists in the first place.
On a less abstract level, I guess my question is - how would I go around learning about different design patterns and approaches to problem solving if I don’t know about their existence in the first place? Is it just a matter of proactive learning and I should know all of them in advance, as well as their uses?
Let’s for example say I need to create a system for inserting a large amount of data from files into the db, or you need to create some service with many scheduled tasks, or an user authentication system. Before you sit down and start developing those the way you usually do, what kind of steps could you take to learn a potentially better way of doing it?
I loved my course on patterns. It was tough, but I now regularly feel like I can apply mastery of this tricky subject to my software projects. The course used a variety of techniques:
- Read the seminal Design Patterns book by Gamma et al., for an overview of the concepts.
- Every week, we’d incorporate three patterns into a preexisting XML processor project. My final one had like 25 patterns, which was challenging to keep working amidst refactoring. (You don’t have to do them cumulatively, but I enjoyed it.)
- We’d have to ask pattern-specific questions of our classmates in forum threads; and occasionally we’d be assigned to answer some.
- We each wrote up our own pattern. (I designed one based on my experiences handling data exchange between web apps and clients.)
Together, this taught us
- How the patterns could concretely look in practice.
- Pros, cons, and other considerations for each.
- Similaraties, differences, and nuances. (We’d joke that everything was the Template pattern if you squinted.)
- The impact of modifications to the patterns.
- How to recognize, create, hone, collaborate on, and share patterns.
I appreciate this approach because patterns are an inherently fuzzy subject.
Thanks for the book recommendation, I’ll definitely check it out! The course sounds really helpful as well, I imagine there are many remote classes like that nowdays or as part of learning sites like pluralsight so that might be worth checking out. If there’s one conclusion I got out of this thread so far is that it is pretty much something you have to learn and practice in advance and then hope to use appropriately, there’s no sure-way or easy way of finding a pattern once you’re already faced with a problem.
Design patterns are typically just workarounds for the limitations of the chosen programming language. What you might consider a pattern in C might just be a simple language feature in C++, and the patterns in C++ (as popularized by GoF) might just be language features in Lisp/Rust/whatever.
So rather than thinking about patterns, you should first choose the right language for the task. If you’re working on a parser, you might prefer Haskell. If you need formal verification, there’s C and Idris and little inbetween. If you need to hire lots of developers, something widely-known like JS might be the choice.
After you’ve chosen a language, you can identify the things that the language is bad at and apply the appropriate design patterns. Sometimes the patterns can be found in books (C++, Java) and sometimes it’s just tribal knowledge (D).
Maybe I’m using the word pattern wrong but I meant like builder, factory or visitor pattern, but on a more wide scale also stuff like dependency injection / IoC - basically “techniques” that are not bound to a specific language but rather provide a design by which some things can be accomplished better. Afaik those are not related to specific languages
I would call those language-specific. While they are useful in more than one language, they are also replaced by language features in many languages.
- Builder pattern can be simplified with kwargs (Python, C#) or argument objects (JS, C++).
- Factory pattern can be simplified with first-class types (Lisp, Haskell).
- Visitor pattern is similarly simplified by first-class functions (supported by most languages nowadays).
- Dependency injection of concept X is generally simplified by first-class X. I think the least widely supported is dependency injection of effects (Koka).
It’s more like languages evolved to incorporate the most common idioms and patterns of their ancestors. ASM abstracted common binary sequences. C abstracted common ASM control structures and call stacks. Java leaned hard on object orientation to enable compositional and inheritence-based patterns widely used in C and early OO languages. Python baselines a lot of those patterns, and makes things like the Null Object pattern unnecessary.
how would I go around learning about different design patterns and approaches to problem solving if I don’t know about their existence in the first place?
Read, and try things. A lot. Read books, read articles, read forums, go to conferences or watch videos from conferences. And try things - do small projects at home, do large projects at home, work in multiple projects at work, if you can. In all these projects, try various things. See how good or bad they are.
There really isn’t any shortcut for this. This is why experience is so valuable and sought after. There is no replacement for it.
for example say I need to create a system for inserting a large amount of data from files into the db
Read about how others have done it, and how it worked for them. Ask colleagues, if you have some which did this before. Remeber how you did it (if you ever did it before), and how it worked out for you. Try some prototypes, and see how they work. These are the strategies most people use.
Seems like on one hand, programmers (online at least) are really against being questioned during interviews about whether they “live the code” and spend their free time on contributing to other projects or developing their own, but if this is really the only way to learn stuff like that then maybe they have a point. I was hoping there’s a better way but I guess it’s the same as always - work enough and hope the stuff you learn ends up being useful one day…
I guess the most important advice about learning that I always try to pass on is: Do NOT go passive. Reading books, watching videos, etc. is all fine, as long as you question everything about what you have read or seen. This is something I see especially with juniors but also quite often with seniors. They get recommended a book, and because the author has a name in the industry or simply because its written in a book, it must be Gods holy truth and everything must be done exactly as decreed. In out industry, knowledge has little value without application, so unless you can put the things you consume into a context that makes sense for you foremost, for your team and for your project. If you struggle with this (not everything can be time boxed into a lazy Saturday afternoons) try to discuss with your peers and form some context that way. Do not just consume, you will not improve that way.
what kind of steps could you take to learn a potentially better way of doing it?
Research what other people have done, to be honest.
Most of the time, I find a library that does it for me so I use that.
Then I might run into limitations of that library… so I either extend/wrap it, reimplement it myself following a similar pattern (but how I want it), find a similar library that doesn’t have the limitations, or learn that the way the library implements it doesn’t work for me and try something else.
And all of this contributes towards my experience. Recognising the shape of a problem when starting to work on something, and having experiences using patterns that fit that shape.It really is a time to be standing in shoulders of giants for a lot of the work. Either find a library, or figure out what other people have done.
I would bet that only really low-level stuff and cryptography are implementing any “new” code.
Everything else is just glue.For example, right now I’m doing some embedded systems work. I found a project that does something similar, so I learnt from it and implemented something similar.
I’ve worked out the main parts of the system, and I now realise it’s a bunch of state machines where the logic for transitioning between states is more important than what happens in a state (in the states is fairly straightforward, but the transitions are confusing and where the bugs are going to happen).
So now I’m looking at some libraries for how a FSM can be nicely implemented in CPP, and I’ll probably draw from a few examples to get my own working.But something that I had originally built as a stitch-together of functions, turned into many complex switch statements, and will now hopefully turn into some elegant, descriptive and abstracted-away state machine.
Yeh, I could probably have predicted it would be an FSM from the start. But I didn’t know that, I didn’t even know if the project was viable, and I don’t do much embedded systems programming.
The similar projects I drew reference from were hobbyist and a mess.
So, now I have a little more experience to think “is this an FSM” when it comes to embedded systems, and whether I want to go with switch statements, or if I go for some fancy system to make the transition logic easier.Is it just a matter of proactive learning and I should know all of them in advance, as well as their uses?
Yes
There is of course the excellent book by Polya: How to solve it which I highly recommend to any programmer.