4 ms·
Technically a huge switch statement isn't a ball of mud. It is mutually exclusive and completely exhaustive. It may have other issues, but is actually better t
by nyrikki 2y ago
Technically a huge switch statement isn't a ball of mud. It is mutually exclusive and completely exhaustive.
It may have other issues, but is actually better than what this article is describing.
- sillysaurusx 2y agoI happen to agree, but only in this special case. Normally a giant switch statement is a pain to work through if there's even a tiny amount of logic involved. One hilarious case was at Scottrade. I was poking around their C++ codebase one day and to my amazed horror saw a file hundreds of lines long, and a big chunk of it was devoted to handling leap years. Like, every leap year, one at a time. There are few enough leap years that it should in theory be difficult to write hundreds of lines of code to handle each of them, but some contractor managed to. And so the ball of mud continued. What can you do but laugh and embrace the horror?
- throwway120385 2y agoAt least you can be sure that it worked, whereas if he'd actually written the succinct version there was a risk of a subtle bug.
- wewtyflakes 2y agoWhy would such a system assure someone that it worked? Conversely, why would only the succinct version lend itself to a subtle bug?
- codetrotter 2y agoMine is as succinct as they come, but a little bit buggy int is_leap_year(int year) { return 0; }
- wewtyflakes 2y agoI don't think that qualifies as a "subtle" bug. :)
- throwway120385 2y agoSuppose that someone tried to naively derive the leap year by dividing the current year by 4. There are some years that are divisible by 4 but that are nonetheless not leap years. If you fail to account for this in your succinct implementation then you might introduce a leap day that doesn't exist at some point. I know the table implementation seems really dumb, and it's not that hard to look up a correct algorithm for this, but it's a good example. If you build a table from some correct source then you can simply use that table instead of running a calculation. There are fewer than 30 leap years in the next 100 years, by which time something cataclysmic will happen that will completely erase the need for your code anyway. At least, you will be dead before you need to revise the code again. So it's reasonable to build a function with a table given the time-limited nature of the code and the desire to be visibly and explicitly correct. Sure you could add a unit test with the table and test the calculation, but that actually adds more code to maintain than just jamming the table directly into the function.
- wewtyflakes 2y agoI don't think they were stating that a simple table based solution was used, if it were, it would probably meet the bar for "succinct" because you could just write that as something like `if X in Y`. Rather, I got the impression that a lookup based approach was intended, but it was enterprise-ified (like https://github.com/Hello-World-EE/Java-Hello-World-Enterprise-Edition/tree/master/src/com/example https://github.com/Hello-World-EE/Java-Hello-World-Enterpris...).
- throwway120385 2y agoOh, gross.
- HideousKojima 2y agoDoing modulo 4, 100, and 400 isn't really that complicated to implement. I know there are even simpler ways to calculate this but come on, this is stupidly easy stuff. Then again we live in a dimension where there are Node packages for IsEven() and IsOdd() with tons of downloads.
- skybrian 2y agoYou can only be sure if you verified every year and didn't miss a typo. Having a test that straightforwardly checks every year individually would be more useful, since then you know if you changed anything, and can double-check just the changes. Although, I suppose it doesn't matter all that much which is which, as long as they're not both written the same way.
- lanstin 2y agoUnless there's something about leap years that you don't understand and miss in both tests and implementation. Not an impossible situation.
- throwway120385 2y agoHow do you ensure that you don't put a typo in the unit test?
- skybrian 2y agoHopefully, it wouldn't match the algorithm. It's implementing it two different ways and comparing the results. It's not a guarantee, since you could have implemented the wrong spec, but there's only so much you can do with internal consistency checks. But it would be better to compare to a known good function. It might be easier to add a dependency to do that in a test than in production code.
- lmm 2y agoIf you used the list of years in the test and the mathematical expression in the impl (or vice versa), then you know you didn't make the same mistake in both.
- worstspotgain 2y agoMaybe the author wanted to squeeze as many hours out of the task as they could? Plenty of non-top-quartile people love this sort of thing as a day at the beach. For the diametrical opposite, here's one time on an embedded system where I really didn't want to bring in a library dependency, so I wrote an inconspicuous-looking good-enough version: y = (d - (d + 366 + (d >= 47847)) / 1461 + (d >= 47847)) / 365; d = d - (d + 365 + (d >= 47848)) / 1461 + (d >= 47848) - y * 365; y += 1970;
- shawndumas 2y ago#include <iostream> int main() { long long d; std::cout << "Enter a Julian Day Number: "; std::cin >> d; if (d < 0) { std::cerr << "Error: Invalid Julian Day Number (must be non-negative)." << std::endl; return 1; // Indicate an error to the system } const int DAYS_PER_YEAR = 365; const int DAYS_PER_LEAP_YEAR = 366; const int DAYS_PER_LEAP_CYCLE = 1461; // 4 years const int JULIAN_TO_GREGORIAN_THRESHOLD = 2299161; // Oct 15, 1582 // Adjust for Julian-to-Gregorian transition if (d >= JULIAN_TO_GREGORIAN_THRESHOLD) { d += 10; // Account for dropped days } int a = d + 32044; int b = (4 * a + 3) / DAYS_PER_LEAP_CYCLE; int c = (4 * a + 3) % DAYS_PER_LEAP_CYCLE; int y = (b / 1460) + 1970; d = (c / 4) - 365; if (d < 0) { y--; d += DAYS_PER_YEAR + (y % 4 == 0); } std::cout << "Gregorian Year: " << y << std::endl; std::cout << "Day of Year: " << d + 1 << std::endl; // Add 1 as days are typically 1-indexed return 0; }
- trealira 2y agoThat reminds me of this program, which calculates the month and day given the year and the day of the year [0]. There's a version that abuses goto, and one that stores state in variables and only uses structured statements. You probably won't see people similarly abuse goto today, though. I think it was translated from Fortran. [0]: https://craftofcoding.wordpress.com/2020/02/12/the-world-of-unstructured-programming-i-e-spaghetti-code/ https://craftofcoding.wordpress.com/2020/02/12/the-world-of-...
- worstspotgain 2y ago
- nyrikki 2y agoI am not talking about ease of programming, and c being imperative, and the explicit break are edge cases. But for case value value can only be char or int, and must be unique Really it is just sugar for if-else-if, but if you enforce explicit break in your code it is as close to a provable total function as you get in C. Total functions are the ideal in any code. As determining whether or not a function F is total is undecidable, switch is more reliable than if-else-if ladders.
- tuveson 2y agoI think any time you're dealing with data in the form of an enum, a switch usually the natural way to handle cases. Many compilers will warn you when you've missed a case, which is a nice check to have. Similarly, in languages that support ADTs, pattern matching tends to be the sensible thing to do. But I agree that in the case you described, that the programmer was being stupid. However they could have written it as a giant if-elseif block and that would also have been stupid, or a loop over a giant list of years, and that also would have been stupid. I think the problem was the programmer not thinking about the problem carefully, not with the control-flow construct they used to write the bad code.
- daemin 2y agoWas it then case that there was special logic attached to special leap years like all of the exceptions we hear about in other software products like Excel etc? Or was it just "return true" and "return false" ?
- Piraty 2y ago> What can you do but laugh and embrace the horror? laugh. embrace and share the fun with others: submit to https://thedailywtf.com https://thedailywtf.com
- pixl97 2y agoOoof, I have dealt with some fun balls of mud. Had a customers app break when they used zips that contained over 65k separate files. Sent it to dev and they said "Oh use this other API we have". And yes, the file 'worked' but the api didn't do what the customer needed. Got back with the developer and saw We had two api's that did almost but not quite the same thing. Ok, it happens, maybe there was a reason for it. We also had two different zip libraries built in. At some point a dev ran into issues with legacy zip support not working on large files and added a new library. They converted about 10% of the API, enough to cover what they were working on and stopped.
- osigurdson 2y ago>> "Oh use this other API we have" This is an interesting problem. If you insist on maximizing consistency on a large code base, then nothing can ever change. If you allow too many small deviations / good ideas that are only ever partially completed, it results in chaos. I think it is a little like entropy: some (not too much) is needed for things to progress.
- pixl97 2y agoSo this was a few years back and they've wrangled a lot of the mess in. They've went with API versioning where you can set a flag in the request of something like ver=5 and you get a static version of the api that doesn't change. If you don't set an api version you get the latest version, which may break on updates. I think for most users it's made feature observability much better.
- daemin 2y agoThe part with having multiple libraries that do the same thing is always an interesting engineering case. Usually it's the case that different libraries support different features, so trying to settle on only one library is folly. Same thing when converting all of the existing zip code to handle a new library, who knows what will break, and even though it may be required production/management rarely want to take the time to make the switch. Case in point I've been at multiple places that have had multiple JSON and XML libraries in the same product at the same time.
- Quekid5 2y agoTuring Machines have that property. There the Tarpit lies.