Sometimes we find ourselves so preoccupied with finding a solution to a problem, that once we’ve reached it we fail to realize we have wasted time on the wrong route.
The right solution to the wrong problem (TRSTTWP for short 🙂 ) is a phenomenon which happens many times in software development, but not only. It leads to some really elegant solutions to problems that should have never occurred in the first place if spotted on time.
Here’s an actual challenge I have encountered working on a large scale Angular project.
The URL possessed two types of attributes: a product ID as part of the URL and a query param as a data filter.
For example:
app/product-type/199/details?minPrice=20&maxPrice=25
The route may change due to one of the following:
- We’re looking a different product, but the same price range.
- We’re looking for the same product, but with a different price range.
- We’re looking for a different product and a different price range.
In practice you’d want to catch both events and decide what to do next.
But here’s the catch: these events are prioritized. In practice this means that Angular will detect one of them first and then the second. This all sounds fine and dandy until you realize that if the app detects one event there’s no way of knowing if the other is going to follow or not!
“Wait a minute”, you might say, “surely there’s a UI trigger for all three options. Like a product dropdown and a range filter”. True, if that was the case then sure. But when routing is involved it’s not just the router which reflects the state, it should work the other way around allowing the URL to trigger a behavior from the app.
It got me thinking about what would be the best strategy to solve this problem.
Possible solutions:
- Request the data from the server for every change. On the one hand it means the 2 out of 3 cases will be single calls, one third would trigger a “premature” call followed by a second one. It’s an ugly and inefficient solution.
- Turn on a flag for each subscription and decide what to do after a timeout. This will probably work, beside the fact that we’ll never be 100% certain there will be no side effects due to an intermittent event. Besides, ugly.
- Inject the router and listen to router events instead like so:
We’ll get an output for every URL change.
So the last one seems like a legit solution. Just parse the URL and decide what to do.
Only it’s a shame we had to dump the entire feature set the route provided us. We’re left with a simple, but dumb solution. Did we choose Angular just to dump a core feature?
And then I had a revelation! I have found a great answer to the wrong problem! “Wrong” in the sense of “shouldn’t have existed in the first place”.
So what gives? What got me into this mess in the first place? The answer is simple.
The URL structure is just wrong.
Both the product and its filters are part of the same query. So why use the one structure (product/:id) to query one half of the query and another (?from=a&to=b) to query the other half?
Simply use a unified structure, e.g.:
app/product?type=99&from=1&to=8
and that’s it. Problem that should have never existed in the first place is now resolved.