Shortcut to seniority

Home
Go to main page

Section level: Junior
A journey into the programming realm

Section level: Intermediate
The point of no return

Section level: Senior
Leaping into the unknown
Go to main page
A journey into the programming realm
The point of no return
Leaping into the unknown
Problem solving is the most important topic for software developers, this is what we're hired to do, we're not code monkeys, we're there to solve problems.
A software is nothing more than a piece of program that solves a particular problem or set of problems.
It’s true that solving problems comes with practice, but I can point out a few rules that I follow when trying to solve an issue.
This is absolutely the first step. Ask anyone and they will tell you the same thing.
If you don’t understand what’s the problem, you will not be able to solve it.
Ask yourself the following questions:
After we understand what we need to do, we still need to have a plan. Although we could theoretically jump directly into coding, we need to make sure we know what we have to do.
Give your brain some time to analyze the problem and process all the information.
Sketch some ideas on paper. Try to split the problem into smaller sub-problems.
Think about the code, write some simple pseudocode or simply delimit the sub-problems.
Don’t code yet. Let’s first imagine how the code will work with some sample input/output examples.
Take some simple examples and think about the output. Will your logic work on that input?
Take more complex and bigger inputs – will it still work?
What about corner cases / edge cases? What should be the output in such cases?
And what about receiving invalid input?
Try to divide the problem into smaller, manageable problems. Split the functionality in multiple functions or classes. Connect those sub-problems by calling them into a specific order (one function calling another, etc).
This can also be done with pseudocode – by now, you should know the function names, and maybe also the input arguments / return type. Make sure that the function names (and parameter names) are crystal clear to everyone who reads them. Don’t get stuck with the syntax, just focus on the logic and the steps.
TDD is a great way of making sure you understand the problem statement and what’s expected as input/output. Other than that, you’ll also know when your code is correct. Therefore, I strongly suggest to start with the test first, and validate the basic input.
First, you should think about a simplified version of your problem. Add or remove constraints, in order to reach a problem that you’re able to solve. Reducing the problem will also allow you to see exactly where is the remaining difficulty.
Now you can start coding. Solve each sub-problem one by one.
And remember – first, you should only care about making it work. Just implement the initial solution, it doesn’t matter how the code looks like for now. If you have a unit-test – your goal is to make it pass.
Now that the problem is solved – we’re not done yet.
Write more complicated tests, and also validate the edge cases.
Then, you can start polishing the code.Make it better. Make it faster. Refactor it until you’re happy with the result. You'll make the tests fail, but that's why they are there, to tell you when everything's working properly again.
Rebuild and check the test results as much as possible.
To do so, you have to ask yourself the following questions:
After you’re done with the code, add the documentation for classes, methods, and major algorithms – if any. Other developers (you included) will thank yourself for this.
Let’s tackle a short problem. We want to reverse a string, and we cannot use any already-implemented functions, so we need to implement our own string reverse. Let’s go through each steps.
Do you understand the problem?
Yes, we need to reverse a string.
Can you explain the problem im simple terms, to a non-technical person?
We want to create an algorithm that will receive a word and we need to reverse the letters, let’s say for example we receive the word “abcd” and we need to be able to return “dcba”.
What is the required input?
We need to receive a string, nothing else
What would be the output for those inputs?
The output for a given string should be the reverse of the string.
What are your assumptions about the problem?
The input should contain a valid string.
Have you solved similar problems before?
No, so I cannot make use of a similar solution.
Ask yourself a few questions here. What happens if the string has only two letters? But what if it’s just one? Well, if it’s only one letter, we should just return it. But if they are two? We simply swap it. What if we add one more letter? So now we have three letters. We only need to swap first and the third one. So we will need to start from the beginning and end of the string, and go until they intersect.
Pseudocode:
Function reverse(string myString):
set n = length of myString
iterate through the characters, from 0 to n
swap the characters based on some logic
return the reversed string
Ask yourself a few questions here. Will it work if you pass something else than a string? Maybe a number? Maybe a negative number? Or some strange character from a chinese keyboard? Does the string should be in english? Can it work with some character with a french accent ? How will it behave then ? Can I pass it an empty string? Can I pass it a string with a very long length, let’s say 1 million characters?
Simple examples:
Corner / edge cases:
Not needed for this problem.
Now we simply need to use the sample input that we created and move it into a unit-test.
EXPECT_EQUAL(reverse("ab"), "ba");
EXPECT_EQUAL(reverse("abc"), "cba");
EXPECT_EQUAL(reverse("abcd"), "dcba");
EXPECT_EQUAL(reverse(""), "");
EXPECT_EQUAL(reverse("a"), "a");
Let’s say you don’t know how to solve this problem. But we know how to reverse an empty string, it's still empty, right? We also know how to reverse a string with two characters, we simply switch them up. Now, what about three characters and beyond?
Let’s build our solution based on that. How would your brain solve the problem? Now you only need to transpose that into code.
Implement the code and check the unit-tests to make sure that they pass.
Is there an edge-case that you did not think of? Use the unit-tests to tell you that.
Therefore, you may have to add a few more edge-cases in the unit-test and update the code to accommodate those cases.
Now that all your unit tests pass, you have a working code.
Can you make it better? Faster? Easier to be understood by others?
Did you find the best names for those variables? For the function? For the classes?
Are there extra variables that can be removed? Lines that can be moved together, logical conditions that could be stacked up, or moved into a variable to make it more clear what they validate?
Can the code run faster? Does it work for small data sets? For big data sets?
This is the easiest step. Now that you’re done, document the code.
What is the input? What is the output? What does the function do ? Is it clear for everyone, even for someone who never saw that code up until now? If not, write it down.
Create the implementation for an application.
Requirements / Features
Relevant quality attributes: Performance, Availability
Feedback should be provided to the user in all cases, in less than 2 seconds.
We cannot simply start coding. We need a plan. We need to make sure we understand the problem. Then, we need to take into account unsaid tasks. Let’s see how we can tackle this.
Let’s take them step by step.
User can search for some online functionality such as weather at a given location.
Where do we get the account details?
The persistent data should not be stored in clear.
We interact with a 3rd party application
…and so on.
=> We need to have a server that will act as a communication bridge between application and the actual server.
We communicate with a webpage.
We need to persist the server where we log in.
It was said something about messages to the user.
Where do we get the message from?
Are there any other popups that we should display at any other point?
Do we display the popups for a specific time, or do we wait for the user to press on some OK button?
If we force the user to press on that ok button, would it be ok if we hide the popup if the screen changes? Or we don’t execute any screen change while having a popup on screen?
Ok, what about those screens? For sure we need to have some screens up available.
We also need to write the GUI (graphical user interface) for the screen.
Do we have interface specifications? Do we draw things on screen, or connect to a web page from the application?
How can we write an application that has performance in mind?
Should it reply fast to the user? What can we do about that?
We need to make sure that the servers are replying fast.
We need to make sure that graphical elements are loaded fast.
How can we make an application that has availability in mind?
It’s clear that the server should be available at all times.
Feedback should be provided to the user in all cases, in less than 2 seconds.
Ah, yes, about that..Another implementation detail. We need to use some kind of timer to make sure we reply to the user.
What happens if the server hasn’t replied, or we have a slow connection?
What happens if we do a request, we cancel it due to slow response, and then do another request?
We need to make sure we cancel all operations when network is unavailable.
We need to know the login state.
We need classes / libraries / components for:
We need to think about how are we going to deal with all that, architectural wise.
And we have a lot of new questions that need to be answered or taken into account when writing the code.
Create the implementation for an application.
Requirements / Features
Relevant quality attributes: Security, Usability
The files are limited to 100Mb per file and 1GB per user.
Same as before – step by step. What do we know?
User can log in.
Ok, same as before, we need a server to log in, and some credentials.
User can upload files, and update personal profile.
We need some implementation for uploading files.
Personal profile
Logged users can add or remove friends.
Everyone can search for files uploaded by other users.
If we need to keep the user logged in, we will probably need a cookie, a token, or something similar.
After how much time of not using the app should we disconnect the user and request reauthentication?
Speaking of which – we need to implement the server as well.
Do we have a design specification somewhere? How are things supposed to look like?
Now let's talk about the quality attributes and how to handle them.
How can we make an application that has Security in mind?
How can we make an application that has Usability in mind?
We need to know the login state.
We need classes / libraries / components for:
We need to think about how are we going to deal with all that, architectural wise.
And we have a lot of new questions that need to be answered or taken into account when writing the code.
Well, that’s easy and hard at the same time. You already know what you have to do to become better at this – it’s right there in the title. Just practice. With experience, you’ll be able to connect the dots. You’ll know how to take some ideas and to detect similarities from already solved problems in order to solve new ones.
Find the strategy that works for you. How do you solve the problems in real life?
There are so many options to practice. Chess, math problems, Sudoku, Monopoly, video games.. Yes, video games.
Even video games are all about problem-solving.
But I’d recommend you to also work on some coding challenges. You find tons of them online.
Remember, problems share similar patterns. If you still don’t know how to solve a problem – do your research. If you still don’t know how to solve a problem – do your research.
Start checking on google, because for sure someone else already solved it.
You can learn a lot even from other people’s solutions. But think of why that solution works, what is the complexity, whether you can improve it, whether it gives you an idea on how to proceed on your solution..and so on. Learn from it, don’t just read it, have an ‘’aaaah I see it now’’ moment, and then throw it away.
Stakeholders: People involved / interested in the topic, that have influence or power over it.
KISS (Keep it simple, stupid), DRY (don’t repeat yourself), YAGNI (you aren’t gonna need it).
Acceptance criteria – conditions that a software must satisfy to be accepted by the user/customer.
Appendix B contain a list of behavior questions. Click to open it in new tab.
Appendix C contains a list of questions that the candidate may ask regarding the company. Click to open it in new tab.
Will be discussed in detail in Architecture chapter, Quality attributes.
Performance is the ability of the system to execute actions within a certain period of time.
Availability is the ability of the system to be fully or partly operational.
Will be discussed in detail in Architecture chapter, Quality attributes.
Security is the ability of an application to be secure.
Usability refers to how easy it is to use or to learn the application.
Security is the ability of an application to be secure.
Usability refers to how easy it is to use or to learn the application.