Meet Dave
Imagine Dave, software engineer, who is in charge of merchandising software for a big online store. Software allows employees of the store to create promotions and put them on store home or category pages.
"Could you please add a button?"
One day Dave receives a request from users: add a button that checks if there are any conflicts in promotions: only one promotion should be displayed on a page at a time. Well, it at a first glance it doesn't seem that difficult: we have a page id where promotion is intended to be placed so we can make a query and verify that there are no promotions for this page. Should be easy: add a button + method to a service + method to a database layer which runs the query + tests + code review - should take about 1 day, maximum 2. Well, not exactly.
Image source: wikimedia.org
Catch #1
The store is data-driven company so people who run the store loves to run A/B tests. So we're fine with multiple promotions for a single page if they belong to a different A/B tests. Not a big deal - adding one more check will do the trick. One more condition and a few more tests to add (and create a few more sample data sets for these tests) - looks like 2 days is more realistic estimate.
Catch #2
But the store also loves to create specialized promotions for a specific set of users, e.g. if user purchased a ruler it is possible that he might be interested in a "back to school" promotion. So we should check not only for A/B test but also for targeting. But wait, what if promotion has both A/B test and targeting? Is it even possible? Probably should be - even if there is currently no such use case who knows what users might ask tomorrow - it's better to make software robust and flexible (yeah!). So we should check that there are no other promos with the same A/B test + targeting combination for a given page. Wait, no. We should check that there is no promotion with either same A/B test or targeting. Ok, 15 minutes to add necessary condition and few more hours to create test data and write necessary tests. There are quite a few tests already at this point so it's better not to have any additional use cases - otherwise other people might have trouble maintaining these tests.
Catch #3
Ugh, sometimes promos could be scheduled. So it's one more condition and a few more data samples and test cases. Well, hopefully it now covers everything.
UI
Ok, now when backend is ready it only remains to add a button on a page and PR is ready to be reviewed and submitted. But where should I put this button? Nothing is said about it in issue description - it's probably better to ask there. Good, in 3 hours I get the response - somewhere in "Promo details" section. Let's add the button as a list item to a list of inputs "schedule", "A/B test", "Targeting", "Available on device type"... "Available on device type"?
Oh, yes, this was the way to do targeting before targeting framework was implemented and it's still being used. Let me ask PM if I can just ignore this thing for now since it becomes too complicated. Ok, PM replied that it's ok for now to ignore this thing but I'll put a TODO to get back to it later (or someone else could do it, hopefully). Here it is, our button, last item in the "Promo details" section.
Button is there and its purpose is to call service method. But this service is not yet presented in this component. And component is not managed by DI framework - it's a simple component that is managed by its parent component. So should I inject my service into parent component? Looks odd - injecting service just to pass it to a child component. Maybe make a child component managed by DI framework? But then other "simple" components would be inconsistent so I either should make all of them managed by DI framework or inject service into parent... Who's idea it was to make these components as a simple classes?! What on earth this person was thinking?! Let's see what blame is saying... Hmm, it all of these component were actually created by me. Ok, I should have had reason for that then but I have no idea what it was now. Shoot, I've already spent 2 hours poking around and button is still not there. Let's just inject the service into parent component and move forward.
Almost there
Ok, we now have a backend with all necessary tests, button located in "Promo details" section and connected to backend. Great. When user clicks on the button we check if there is a conflict and show corresponding notification. Hmm, it actually just says "there is a conflict" and gives no insight about what caused it. Not good. Lets add which promo is causing a conflict. Is only one possible or multiple? From business logic point of view it should always be one but technically nothing prevents me from creating a set of invalid promos. Let's make it just one title - user can always rerun the check to verify that there is no more conflicting promos. Luckily backend already returns collection of conflicting promos so it's easy to add them to notification message.
There is another issue though - I have about 5 seconds to select and copy promo title to be able to search for it in system - notification is gone in 5 seconds. It would be great to have a links in a notification bar but I've already spent how much - a bit more that 2 days working on this thing and it definitely is out of scope of this feature. We'll fix it later (hopefully). Not the best UX but better than having 0 information on what caused the conflict.
Review & submit
Ok, good, now everything is in place and working fine so let's send the PR to review.
Hmm, test is failing - checkstyle. Something is not indented properly. Ok, fixed.
Tom is asking why service is injected in a parent component but not directly in component where it's needed... It'll probably be easier to catch Tom offline and discuss what the best way to proceed.
After offline discussion and one more back-and-forth with the comments PR is finally approved to be merged. Yay!
It took 3 days to add a button on a page. But that's not the whole story.
The bug
In 3 weeks when the feature was released the bug was filed that some users actually see 2 promotions on one page sometimes. Of course everything worked great regardless of the different things Dave tried until he sent a link to Tom who actually saw 2 promos. It was great that issue was reproduced but there were no ideas on what might have caused it. Finally the guy from targeting team provided list of target groups which has Tom as a member and Tom was both in "renters" and "frequent buyers" groups and there were 2 such promotions. Well, that is unfortunate. In order to work properly the algorithm should not only check that there are no promos with same target but also that if targets are different they do not intersect. But that makes a little sense since the vast majority of the targeting sets will have some common users. After having the discussion with the PM it was decided to leave feature "as is" and decide what to do with it sometime later.
image licence: xkcd.com
Conclusion
Overall it took Dave 3 days to implement the feature and about 2 days to troubleshoot the bug. Dave also left 1 TODO and a few things where "some cleanup and further thinking" is required, or, in other words, introduced some technical debt.
It's not that Dave is bad software engineer. It might be useful to imagine software product as a pyramid - it's easy to add 1 more block to a pyramid 3 blocks high, but its way more work if the height is 5 block or more. It is also sometimes happens that while building additional layer some of the lower levels collapse and have to be redesigned and rebuilt. On the other hand if pyramid has solid foundation with some space reserved for future layers it'll allow features to be added faster and with higher quality.
I completley sympathize with this. I manage so many processes at work and the number of factors that have had to go into them to create is incredible. So many people don't realize the complexity that can occur when trying to put together a "simple" thing. BTW, I am a curator with @ocd and would love to nominate your post.
This gem of a post was discovered by the OCD Team!
Reply to this comment if you accept, and are willing to let us share your gem of a post! By accepting this, you have a chance to receive extra rewards and one of your photos in this article may be used in our compilation post!
You can follow @ocd – learn more about the project and see other Gems! We strive for transparency.
Let me know if you have any questions regarding the project or nomination. Hope to hear from you soon!
If you would like your posts to be resteemed by @ocd to reach a bigger audience, use the tag #ocd-resteem. You can read about it here.
Hello, mk40. Thanks for the proposal, I would love to see it shared.
Guess I'll hold off on the steemSTEM vote!