Introduction
Problem solving is a critical skill all developers must learn as they progress through their careers. One of the big things I focus on as a mentor is arming them with tools and techniques that aid them in becoming higher level thinkers. These techniques should help them see things from a different perspective and begin to unravel the unknown unknowns that sometimes come with old legacy code. These tools will help junior developers start coming out of that junior task focused mindset and begin thinking more like senior developers.
Depending on the developer they will be further along or earlier in their journey so introducing these and the best approach will vary. I've had developers who were all borderline seniors that this was just a single team training, but you can also break it down and slowly introduce these ideas.
80/20 Rule
This says that 80% of your result or effect comes from 20% of your work. This suggests that sometimes the smaller changes or improvements will have the biggest impact and those should be focused on. This is one of those tools that can help prioritize and triage defects and the approach to fixing them. It also can help rationalize that stop the bleeding hot fix you put in compared to the perfect solution.
Example
You give your kid 10 toys they will probably focus on 20% of them and ignore the other 80%. The 2 toys they decide to play with have the biggest impact or the same impact as the other 80%.
Code
- Optimization: if your code is having performance issues you may find that 20% of the critical code is causing 80% of the performance issues. By focusing on that 20% and optimizing that pain point you can drastically improve the overall performance of your code base.
- Defects: The idea here is that 20% of your code will likely cause 80% of your defects. Focus on finding and fixing this 20% and you will increase the reliability of your code.
- Features: To users 20% of the feature set provides 80% of the value, figure out what those features are and focus on them.
The 80/20 split is really just a guideline, it might not always be that clear cut but it is used to visualize the idea. The most important thing is to find the the smallest changes/improvements you can make that create the biggest impact/value. These are some ways to look at how to discover where the value is and prioritize time. Oftentimes, fixing or improving one of those 20% features can buy you enough social credit with users to spend more time fixing other issues, it shows progress and a commitment towards improving. Understanding this principal is a big part of that shift in thinking that marks a developer becoming more senior.
Inverted Thinking
Look at things from the opposite perspective. In development it means that the solution to a problem is often the opposite of the problem. Essentially, to solve a problem you think about how to create the problem instead of how to solve it. For a defect this means don't think about fixing the defect but think about how you would create it and work from there. This generally leads developers to think more of about what they know could cause the problem compared to the never ending mountain of what ifs. It's a more focused and narrow approach but can lead to faster resolution by started narrow and going more broad if needed.
Example
Your sandwich tastes terrible, don't think about how to make it better instead think about how you created this terrible sandwich and go from there. Instead of thinking about what to add to make it not so terrible you think about how you would create such a terrible sandwich and solve the problem that way.
Another way to think about it is to think about the things you do not want on your sandwich and create a sandwich from the remaining items.
Code
- Debugging: instead of thinking about the what the correct code is or why the code didn't work right think about how you would create the same defect. Often times this leads to exploring different possibilities which can determine the root cause more efficiently.
- Optimization: Instead of focusing on what to add or change to optimize code think about how you would slow it down or think about what you could remove from the code to achieve the same effect. For example, this SQL query is slow what could I do to intentionally create a slow query.
- UX: Instead of thinking what you need to add to make your UX better think about what you can remove or simplify
Second Order Thinking
Second order thinking is about thinking about the "and then..." situation. It forces you to think about long term or short term side effects of your decision and use that additional context to make your choice. Be careful to not get into the never ending what if minefield on this one. Long term should be within the next year or two what can we reasonably anticipate based on business needs, direction, and what we know. Getting caught in what ifs is paralyzing and usually fruitless. You protect your code from the 5 year unknowns by ensuring it is adaptable, maintained, and documented.
Example
There is a gigantic bowl of ice cream in front of you. You know that eating all of it will make you happy right now so you decide to eat all of it. Then you think about the "and then" scenarios and wonder if this will make you sick, make you miss your dinner, etc and decide not to eat all the ice cream.
Code
- Refactoring: forces you to think how your changes will play out long term. Are your changes maintainable, will they be easy for other devs to work with and understand, does it introduce complexity etc.
- Software Architecture: forces you to think beyond the initial requirements of the project and take into consideration scalability, how flexible the system is to changes or updates, how well the system will grow.
- Performance: will making a change to one area for a small performance boost ad complexity or hinder other parts of the code?
This is really about thinking through the consequences of your changes or beyond the immediate bug fix, improvement etc.
First Principle Thinking
First principle thinking is about understanding something from its most basic building blocks or core functionality. This involves questioning assumptions about the system, breaking down problems into smaller pieces, and finding solutions by getting to the bottom of a problem. This is critical for sprint planning and backlog refinement. Asking these questions to get to the core of the problem helps define features an get questions out of the way earlier clearing the path for success during development.
Example
You have a cookie and you eat it. Instead of asking for more cookies so you are no longer cookie-less you ask questions about how to make cookies like asking for ingredients, how those ingredients are combined, why they are combined that way, until you get to the basic blocks of making a cookie. In practice this is often done with "Why" questions.
Identify the problem, break it down into pieces, ask questions or "Why...", and create solutions that start from the building blocks up.
Code
- Problem Solving: this encourages you to break problems down into smaller pieces and ask questions about those parts instead of looking at the problem as a whole you focus on the core principles and requirements
- Algorithm Design: forces you to analyze the problem before deciding on an algorithm or deciding on how to optimize an algorithm
- Design Patterns: forces you to think about what problems the pattern solves, how they solve them, can it be adapted to fit your problem. This gets you thinking about the principles behind design patterns instead of just applying them everywhere.
Overall this helps you dig deeper, question your assumptions, and understand the fundamentals or core parts of your project.
Occam's Razor
Basically, when there are multiple explanations or solutions the simplest one is usually the best. This looks to solve problems with easy and uncomplicated solutions that avoid unnecessary complexity. If nothing else this one should be the standard. Unneccesary complexity is toxic in a codebase and does nothing but increase cognitive load, decrease maintainability, and decrease DevEx. You should strive to keep your code as simple and as you can, and this is the perfect reminder for that. The simple solution is usually the best.
Example
Your computer won't turn on. You could think the PSU is dead, the surge strip is bad, the motherboard is fried, but it could be as simple as the power is unplugged.
Code
- Debugging: when it comes to defects look for the simple explanation first, instead of thinking it is a huge complex issue check the simple basics first. Think typos, incorrect variables, missing data, etc. Most of the time it is something simple.
- Writing Code: this encourages you to write simple and clean code. Keeping this in mind can help you avoid complexity and help you to design simple solutions that are easier to understand and maintain.
- System Design: helps keep systems free of unneeded complexity making them easier to maintain and keeps points of failure low.
Type 1 and Type 2 Decisions
This is more about understanding that choices you make generally fall into one of two categories, understanding this helps you classify what decisions might need more time to make or need extra care in making.
Type 1 decisions are decisions that cannot be reversed or cannot be reversed without a huge amount of effort. These are the decisions to take your time on and gather as much context about as possible. An example of this is NoSQL vs SQL databases or building your application in PHP vs Node. Fundamental architecture choices are Type 1 decisions.
Type 2 decisions are ones that can be easily changed. Some examples of this are libraries or using Fetch vs Axios etc.
Things to try and avoid
Man with the hammer
The man with a hammer sees everything as a nail. This says don't let your decisions be biased by the tools you have or by the tools you favor. Research and look for the best solution even if you are not comfortable with it.
First Conclusion Bias
Don't settle for your first conclusion, normally when we find a solution our brain gets stuck on it and ignores other possible answers. When you come to a conclusion write it down and walk away to do something else and clear your head. Then come back and reevaluate, try to force yourself to think of alternate solutions or answers.
Conclusion
These tools can help your junior developers start thinking more like seniors and more on the project level. They give them options for better troubleshooting and design and strategies to increase their performance and skill set. Focusing on soft skills is just as important as code and technology, if not more so. The fundamentals of programming translate between languages, but soft skills can be tricky and not developing those skills can slow their career progression significantly.
Top comments (0)