An issue with not focusing on on the problem is that your work will likely join the ~90% of near-useless products. There is a lot of joy to be found in the development process itself, I'm not dissing making obscure things that you think are fun; I do that all the time. It's just sometimes sad to see people pouring their sole into products no one ever actually wanted.
And yes, that app helped fix their boredom.
Look into jobs theory if you're interested in this stuff
I think programmers need to start taking a lot more responsibility for what we release into the world.
If you don't think your software solves a real problem, or will improve people's quality of life, then why release it?
There are already too many distractions in the modern world. I don't want to create more. Any software you release that doesn't solve a real problem is just another distraction that takes time away from people's lives.
You're not noticing that you're inadvertently referring to "solutions" in multiple meanings which leads to false equivalence: https://en.wikipedia.org/wiki/Equivocation
E.g. "solution" in "they are solutions, and you shouldn’t learn to use solutions" in your 1st paragraph is referring software tools -- but 2nd paragraph of "solutions" in "bring me solutions, not problems" is about answers or actions to take irrespective of tools.
Because of the above confusion, I think a more accurate title and angle for your essay is "Learn about problems, not specific software tools" ... because people do care about solutions in the generalized non-software-tool sense. E.g. the recent mRNA vaccine is a "solution" to slowing down COVID that's crippling the world.
Also, the following is hard to parse and could use some wordsmithing:
>"(AI is kind of hot, but there are a a ton of wannabe data scientists and few open roles, while the opposite is true for DevOps, study linear algebra and probability theory, either, React, it’s hype),"
That's fair - I wasn't really implying they were equivalent and that sentence is really just to lead into "I find problems more interesting than solutions", but you're right that I'm probably 'cheating' a bit.
DI frameworks solve problems caused by OOP (having to assemble a service object graph). So really, they're solving a problem that programmers created for themselves.
Concatenating all the functions flat into one file can work for quick prototypes, but when you reach 1-2k LOC, you need to start abstracting things to keep it maintainable.
It all depends how much state you need to manage, and how persistent it needs to be. What works in an image processing pipeline doesn't work in a web server, and what works there doesn't work in an autopilot.
I'm usually not one to talk in absolutes, but I'm near certain that procedural or functional programming beat OOP every time. The idea of hidden/encapsulated state just hurts flexibility - where OOP shines is when you have an army of junior developers and you want to encapsulate state and provide rigid interfaces so that mistakes are harder to make.
Some amount of hiding state makes APIs easier to use though. Keeping data structures coherent, for example, means you need to only interact with them through the provided interfaces. This also means that you could internally change the data structures (eg. from deque to ring buffer) and not expose the implementation details to the outside world, causing downstream breakages.
What you describe makes sense for small components built by a small, tightly knit and highly skilled team. The issue is that at some point the software grows enough that you can't hold the whole thing in your head at once, or you need to make it reusable to external developers.
Dependency injection is a good pattern from a testability POV. Trying to test something that instantiates its own dependencies is frigging hard.
But with DI, a service needs to talk to the database? I can either spin up an embedded DB, or, I can pass it a mock DAO to verify it is using the data layer as expected.
(And of course, if there's a real DAO, I'm most likely going to write an integration test that does involve an embedded DB, just to be sure that our Postgres flavoured SQL works. And surprisingly, spinning up an embedded PG isn't that slow. And certainly better than trying to convince HSQL that it's Postgres.)
That said, something I've spent years trying to beat into my fellow Java developers is that the best form of dependency injection is... constructor args.
Make your dependencies constructor args, then you can "inject" whatever the hell you like that conforms to the expected type. You can stick @Autowired on the constructor if you like, go nuts. But even without, well hell, you might not actually need that DI framework, and it's still in a testable space.
As soon as someone starts sticking @Autowired on class fields though, you're fucked. You're annotating JUnit tests with Spring crap, or using Mockito combined with some reflection libraries... ...it's all downhill from there.
But! None of that cruft means that the DI pattern is bad. It's just that people have done very bad things in it's name.
> Make your dependencies constructor args, then you can "inject" whatever the hell you like that conforms to the expected type. You can stick @Autowired on the constructor if you like, go nuts. But even without, well hell, you might not actually need that DI framework, and it's still in a testable space.
Yes, this is exactly what I mean, the amount of wrong stuff that is in the constructor makes me believe DI is a solution for something else.
Infinite amount of times have I encountered stuff in the constructor that shouldn't be there.
Object A has a constructor with a bunch of dependencies, one of them is Object B.
The proper way is for Object B to use object A instead.
Blindly injecting everywhere is my problem with DI. Without these frameworks one would see that dependencies flow in a different direction if proper interfaces are defined.
For example, React Context and useEffect hook is implicit DI yet people have no idea it's DI and I see codebases using React + DI framework instead.
The only DI magic is the topological sort of dependencies and automatic construction. That stuff is 20 lines of additional code so that React.Context and useEffect work the same way.
> But! None of that cruft means that the DI pattern is bad. It's just that people have done very bad things in it's name.
DI adds complexity to the code just by itself. The best ways to implement it are the ones that add as little complexity as possible, but they are still adding complexity.
So, I wouldn't call it a "bad pattern", but it's not something that should be carelessly decided. The best DI is still no DI, you go for the second best only when you can't use the best.
A different way to think about this is to focus on domains. While software is a general purpose skill, like accounting, you can still reap the benefits of specialization. If you know a domain (like real estate or financial services) well, you will be able to build better software quicker because you don't have to come up to speed on the concepts in an area.
If you've worked in real estate, you know, for instance, what the following concepts are:
* MLS
* Brokerage
* Referral fee
* sqft vs total sqft vs aboveground sqft
* pending vs backup status
None of these are rocket science, but knowing the domain deeply will make you a better developer for that problem space.
I also liked the author's turn of phrase at the end. I think as a technologist I sometimes am enamored of the solution, when I really should be focusing on the problem. And sometimes technology isn't the answer to the problem.
The real value comes from learning about both, so that you can maximise the "surface area" of where solutions meet problems.
When you don't understand the problem, you tend to over-engineer with a lot of technology not actually delivering any value. But if you don't understand the solutions, you under-engineer - this is how organisations end up running an ERP through WordPress.
Instead of learning lots about problems, learn about how to listen so you can quickly understand problems.
Read/listen/watch long form content about something you don't understand very well, and attempt to summarise it. Share your notes with someone else, and see if they understand.
Problem discovery and formulation definitely needs to be taught and practiced relative to solutions. Who'd you think has more expertise on a topic - a fellow student who can crack tough exams or one who can set challenging exam papers?
The greatest of scientists were problem finders. Once you truly grasp and formulate a problem, seeking the expertise to solve it becomes a lot easier .. even trivial in cases.
Startups are about problem finding too. Solutioning is important, but not as important as addressing the right problem.
Reading your comment made me want to read the article.
Lets see..
Edit: it was a quick and useful read. I’m actually struggling with getting motivated, maybe reminding myself from time to time what my main issue I’m focusing on I could recalibrate my priorities, and keep my momentum.
Reading this reminds me a lot of a web comic about holding onto and treasuring questions instead of answers [0]. This seems a little more specific to software though. I do enjoy the brevity of it!
This article reminds me of an essay by Neal Stephenson about how the internet stifles the innovation process. The gist of it is that the availability of pre-existing solutions provided by the internet leads to much faster solutions, but stifles innovation and experimentation in the process.
If a group of engineers in a room have to dream up solutions to a problem, then go research and experiment to learn if they'll work, they will be innovating and learning the problem space in the process. If they dream up these solutions, then search the internet to see if they've been tried and work, they'll just be hill climbing.
I once read an article about "problem based learning" where there was a problem presented first and then the solution was shown. The article implied that this was a better way of learning. I am trying to find this article for years now. Anyone knows what I am talking about and maybe has a link for me?
I know what you’re talking about, but I don’t have links.
I took part in a “training session” at a med school. Basically undergrads were brought in to go through a “PBL” session so the facilitators could get training for the upcoming school year.
Looking for literature in the medical field might help to narrow your search. I think it’s a “flipped classroom”, “Socratic method”, “case studies” approach, or probably goes by a different name in different fields.
You do a bunch of pre-reading and preparation ahead of time. You come into the room and are given a problem statement. Then everyone tries to solve the problem and discussion ensues.
Kind of off topic, but I've had a colleague once that defined his role on LinkedIn as "Problem Expert". I'd be worried if I had such a role in my company :P
35 comments
[ 2.1 ms ] story [ 82.3 ms ] threadSay you create a fun little app that a hundred people download, that you just had a good time making.
What problem did it solve for them? Boredom? Did it solve the same problem for everyone?
That being said, I like the article, and I like the idea of focusing on problems more than solutions, to define a career.
And yes, that app helped fix their boredom.
Look into jobs theory if you're interested in this stuff
If you don't think your software solves a real problem, or will improve people's quality of life, then why release it?
There are already too many distractions in the modern world. I don't want to create more. Any software you release that doesn't solve a real problem is just another distraction that takes time away from people's lives.
You're not noticing that you're inadvertently referring to "solutions" in multiple meanings which leads to false equivalence: https://en.wikipedia.org/wiki/Equivocation
E.g. "solution" in "they are solutions, and you shouldn’t learn to use solutions" in your 1st paragraph is referring software tools -- but 2nd paragraph of "solutions" in "bring me solutions, not problems" is about answers or actions to take irrespective of tools.
Because of the above confusion, I think a more accurate title and angle for your essay is "Learn about problems, not specific software tools" ... because people do care about solutions in the generalized non-software-tool sense. E.g. the recent mRNA vaccine is a "solution" to slowing down COVID that's crippling the world.
Also, the following is hard to parse and could use some wordsmithing:
>"(AI is kind of hot, but there are a a ton of wannabe data scientists and few open roles, while the opposite is true for DevOps, study linear algebra and probability theory, either, React, it’s hype),"
Figuring out how to handle ambiguity in writing is difficult. Sometimes a little fuzzing works, I appreciate you supplying an explanation.
It appears everywhere because everyone knows about the solution.
Or have I missed your point?
What you describe makes sense for small components built by a small, tightly knit and highly skilled team. The issue is that at some point the software grows enough that you can't hold the whole thing in your head at once, or you need to make it reusable to external developers.
But with DI, a service needs to talk to the database? I can either spin up an embedded DB, or, I can pass it a mock DAO to verify it is using the data layer as expected.
(And of course, if there's a real DAO, I'm most likely going to write an integration test that does involve an embedded DB, just to be sure that our Postgres flavoured SQL works. And surprisingly, spinning up an embedded PG isn't that slow. And certainly better than trying to convince HSQL that it's Postgres.)
That said, something I've spent years trying to beat into my fellow Java developers is that the best form of dependency injection is... constructor args.
Make your dependencies constructor args, then you can "inject" whatever the hell you like that conforms to the expected type. You can stick @Autowired on the constructor if you like, go nuts. But even without, well hell, you might not actually need that DI framework, and it's still in a testable space.
As soon as someone starts sticking @Autowired on class fields though, you're fucked. You're annotating JUnit tests with Spring crap, or using Mockito combined with some reflection libraries... ...it's all downhill from there.
But! None of that cruft means that the DI pattern is bad. It's just that people have done very bad things in it's name.
Yes, this is exactly what I mean, the amount of wrong stuff that is in the constructor makes me believe DI is a solution for something else.
Infinite amount of times have I encountered stuff in the constructor that shouldn't be there. Object A has a constructor with a bunch of dependencies, one of them is Object B.
The proper way is for Object B to use object A instead.
Blindly injecting everywhere is my problem with DI. Without these frameworks one would see that dependencies flow in a different direction if proper interfaces are defined.
For example, React Context and useEffect hook is implicit DI yet people have no idea it's DI and I see codebases using React + DI framework instead.
The only DI magic is the topological sort of dependencies and automatic construction. That stuff is 20 lines of additional code so that React.Context and useEffect work the same way.
DI adds complexity to the code just by itself. The best ways to implement it are the ones that add as little complexity as possible, but they are still adding complexity.
So, I wouldn't call it a "bad pattern", but it's not something that should be carelessly decided. The best DI is still no DI, you go for the second best only when you can't use the best.
If you've worked in real estate, you know, for instance, what the following concepts are:
None of these are rocket science, but knowing the domain deeply will make you a better developer for that problem space.I also liked the author's turn of phrase at the end. I think as a technologist I sometimes am enamored of the solution, when I really should be focusing on the problem. And sometimes technology isn't the answer to the problem.
When you don't understand the problem, you tend to over-engineer with a lot of technology not actually delivering any value. But if you don't understand the solutions, you under-engineer - this is how organisations end up running an ERP through WordPress.
Instead of learning lots about problems, learn about how to listen so you can quickly understand problems.
Look for "active listening" skills.
The greatest of scientists were problem finders. Once you truly grasp and formulate a problem, seeking the expertise to solve it becomes a lot easier .. even trivial in cases.
Startups are about problem finding too. Solutioning is important, but not as important as addressing the right problem.
Lets see..
Edit: it was a quick and useful read. I’m actually struggling with getting motivated, maybe reminding myself from time to time what my main issue I’m focusing on I could recalibrate my priorities, and keep my momentum.
[0]: http://kiriakakis.net/comics/mused/a-day-at-the-park
If a group of engineers in a room have to dream up solutions to a problem, then go research and experiment to learn if they'll work, they will be innovating and learning the problem space in the process. If they dream up these solutions, then search the internet to see if they've been tried and work, they'll just be hill climbing.
Is that the article in question?
I took part in a “training session” at a med school. Basically undergrads were brought in to go through a “PBL” session so the facilitators could get training for the upcoming school year.
Looking for literature in the medical field might help to narrow your search. I think it’s a “flipped classroom”, “Socratic method”, “case studies” approach, or probably goes by a different name in different fields.
You do a bunch of pre-reading and preparation ahead of time. You come into the room and are given a problem statement. Then everyone tries to solve the problem and discussion ensues.