Dirty Coding Tricks To Make a Deadline
Gamasutra is running an article with a collection of anecdotes from game developers who had to employ some quick and dirty fixes to get their products to ship on time. Here's a brief excerpt:
"Back at [company X] — I think it was near the end of [the project] — we had an object in one of the levels that needed to be hidden. We didn't want to re-export the level and we did not use checksum names. So right smack in the middle of the engine code we had something like the following. The game shipped with this in: if( level == 10 && object == 56 ) {HideObject();} Maybe a year later, an artist using our engine came to us very frustrated about why an object in their level was not showing up after exporting to what resolved to level 10. I wonder why?"
Have you ever needed to insert terrible code to make something work at the last minute?
Right before I left from Microsoft: int security = *NULL; // eat it!
Most people don't get why the integral of "e to the x" is so funny. Most math majors don't have a sense of humor.
GOTO :-) (or is that two..?)
[Slashdot Comments We Liked]
VBA
A Good Troll is better than a Bad Human.
If you have short deadlines, you end up with issues similar to the bugs Ubuntu needs to smooth out every release. If you go with "It'll be finished when it is finished", Your stable releases can become ridiculously out of date between versions. Debian did a good thing by abandoning the open-ended release cycle in favor of the extremely long but predictable two-year deadlines.
Once I had an assignment due and at the last minute before being evaluated, realized I had made a huge mistake, even though the code looked OK...
Too much time playing games in class and I was about to fail the course unit if I didn't pass that one test (right at the end of a semester)
So I ran the program, adjusted the output in a word processor, saved it as a file and threw some code hidden in the comments that read the file, outputted it and exited.
Three minutes later my code was evaluated... I was the only one who passed.
Fortunately, no one investigated too carefully at the time why I was the only one who passed, because after trying to fix the code later in my own time, I realized the source data we were all supplied was corrupted.
Inevitably, Later the same lecturer came to the same conclusion when his program didn't work either and cornered me to ask why mine worked (of course he was suspicious). Thinking quickly, I told him my source data was corrupted and that I fixed that first so my program would work. I don't know if he believed me, but he accepted the story.
Fortunately, I got away with it and I got to keep the pass.
The Gamasutra article is dated August 20, 2009. I doubt any Slashdot contributor submitted a link to a 2009 story back in 2000.
The editor might have approved this submission just to meet some kind of deadline or a minimum requirement.
The deadline is looming, I can't spend much more time on this. So, I did the unthinkable -- I packed the controller id into the pointer parameter. I marked it as a horrible hack in a 4-line all-caps comment, and checked it in.
Does not sound so horrible, just make sure the 1,2,3,4 pointers never point at anything "free()"able and it'll work fine.
BTW, is that Wolf 360 game out?
Have you ever needed to insert terrible code to make something work at the last minute?
Wouldn't "have you ever shipped a product without needing to insert terrible code to make something work at the last minute?" be a more sensible question?
My boss however *only* does coding tricks. And he puts them in one big 1k line function.
And is proud of it.
This is one of those stories where the story isn't the point, it's the comments that are worth reading, so it's only a problem if we have the same comments :-P
I mod down anyone who says "I will be modded down for this", regardless of the rest of their comment
In the real world there are deadlines, and it's entirely the developer's responsibility to be able to meet those deadlines without using such "dirty coding tricks". Good developers should have tested their code so as to not have serious problems to fix at the last minute, and designed it so as to be able to extend it easily.
And putting such "if" statements is not solving the problem - not even temporarily - but hiding the bug.
Right, nobody said it was easy. That's probably why software development is not for everybody.
When my deadline comes up and I haven't produced I wait for my boss to ask me for the code then I sucker punch him and run away. The trick is to hold down short term contracts and give false references and hire someone to back them up (another dirty trick). That also makes it easier to dodge the cops when your boss presses charges. It's getting harder though with all this talk of test driven development and short incremental releases. Then the trick becomes to write the most meaningless trivial unimportant tests first - but crucially tests that you can make pass quickly so you don't have to do any real work.
(For anyone insane enough not to realise it, this is a joke. Don't try this at home...or at work).
A 3d model export would break regularly screwing up the texture map orientation on certain polygons. The godawful export couldn't be fixed on the deadline, and risk management said best not to touch it cuz EVERYTHING might bust, let alone all the coders being nailed to the wall by the ship date. So I fixed the model files in an ascii editor. All the art builds that had tweaks needed this "touch" Since it was a hockey game, you can imagine how many goalie pads that was. Oh yeah, you couldn't see if the fixes were correct except in the game engine after more pipeline.
Technically not a code fix, but still a valid solution.
I once worked at a Fortune 25 company in Chicago. They had this ENORMOUS mainframe program written in COBOL that ran their order inventory system which accounted for 20% of the companies revenue. All the guys who wrote this grunting pig of a system had either retired or had passed away. In the middle of the code was the following;
*
* We don't know what this does.
* Please leave it alone !
*
SET INSIDE-INDEX TO 1.
*
* We don't know what this does.
* Please leave it alone !
*
If this statement was commented out or removed the system stopped working. No one could find the problem. People had spent years looking for it but the code was such a mess and the documentation was so useless that they just left it alone and made a note that when the order inventory was re-done to make sure they left this "feature" out. I have been told that many old system have similar problems.
Another day closer to redwood heaven
Have you ever wrote a function / procedure with more then one return statement? Or used break or continue in a loop? Then you can use goto as well. From a structure point of view goto, break, continue and return are all unconditional jumps. They are one of a kind. And looking back in retrospect: Since goto need to be paired with a label it's the least evil of the group.
Note that Pascal the archetype of structured programming had goto but it did not have break, continue or return.
Way back we had a project where we had to simulate entire train traffic entering Helsinki train terminal. Someone else had made the simulator and it ran pretty neatly, but unfortunately crashed mysteriously after about four - six hours of simulation time. Our customers were coming the on monday and I spent my sunday trying to figure out how this simulation worked and what crashed it. Finally I caught the problem, which was as simple as some null pointer to a train schedule or something similar which needed to be referenced. I couldn't figure out why it was null in time, so I just added test for null pointer, which skipped said code. Program ran fine and we got our money. Never figured out what was wrong with it. Luckily it was only a simulation.
This was a pretty important assignment back when I was studying computer science. It added to the final mark mark for that particular class. The task was to write a reasonably complex application in Prolog or some functional programming language, I can't remember which it was. I think the goal was to pair males and females based on their preferences, and find the optimal solution. Of course, I screwed up royally, and nothing worked five minutes before I had to demonstrate my solution.
So in the final five minutes, I changed my code so it would avoid the parts which put it into an infinite loop, and instead simply output a random result. My goal was to tell the prof that it had worked a few minutes earlier, and that I didn't know what had gone wrong, and could I please have another week?
So I demonstrated my app, it gave its random output, and I was about to start with my "damn, it used to work properly" spiel when he said (and this is actually true, even though it sounds unbelievable):
"That's great! The result is correct, and your app is also quite a bit quicker than my own implementation of the problem. Congratulations, I think you're the only one so far who managed to get the correct result so far."
I was so taken aback that I probably just stared at him for a few seconds. Then, I stupidly said "So... You want to see my code?" but he was like "No, the result is correct, and your implementation is very fast, so I don't need to see the code. Good job. Send in the next guy."
And so I did.
Quick, find the dupe and copy-paste all the +5 Insightfuls!
Example? Right here:
#include <stdio.h>
void *f(void)
{
a:
printf("Here!\n");
return &&a;
}
int main(int ac, char **av)
{
goto *f();
printf("There\n");
return 0;
}
I worked with some finance guy who was convinced that the square root of a negative number -x was -sqrt(x), and wouldn't hear otherwise. I hacked sqrt(x) to return sgn(x)*sqrt(fabs(x)), but he complained that when he squared the answer, he didn't get back a negative number. Luckily our code was C99 so I changed his dollar type to be "double complex", made him use the complex sqrt, and changed his print function to display creal(x) - cimag(x). The guy said things worked great. I was glad to hear that, but it still feels wrong that part of our finance system is handling complex number of dollars, whatever that means.
After years of programming, I guess everyone had to cut some corners sometimes. It's also not (always) a problem of goofing off, a module you depend on not shipping in time but you being required to keep your deadline can already force you into doing just that: Delivering a hack that 'kinda-sorta' works, or at least the customer won't notice 'til we can ship the patch.
Yes, that happens often. It's dubbed "Bananaware". Delivered green and ripens with the customer.
We used to have a Bill of Rights. Now, with the rights gone, all we have left is the bill.
> it's the comments that are worth reading
More specifically the comments in the article. I loved this one:
"Back on Wing Commander 1 we were getting an exception from our EMM386 memory manager when we exited the game. We'd clear the screen and a single line would print out, something like "EMM386 Memory manager error. Blah blah blah." We had to ship ASAP. So I hex edited the error in the memory manager itself to read "Thank you for playing Wing Commander.""
That's awesome.
Basically ALL the software you use works like this.
Welcome to the real world, no need to feel bad.
Some of the worst I have seen:
In critical C code:
if (some condition)
i *= 0;
else
i *= 1;
And I was the actual variable name.
Even worse, on a different project, an Easter egg that told the user their hard drive was about to be erased, and another that popped up about 30 dialog boxes full of banter between Spock and Kirk. Worst of all this code written in VB and was licensed for megabux then we got hold of it for orders of magnitude more megabux (Most of the original coders were hired fresh out of highschool). It ended up being rewritten (thankfully NOT by me) but we had to get the source to work out how it worked in the first place.
I wish I was making this up.
These posts express my own personal views, not those of my employer
That's completely understandable in this case of programming in Prolog.
Prolog is a declarative language.
You declare the rules, and the system figures out a result that matches those rules.
The problem is that this basically doesn't work. So a Prolog programmer has to write the "declarative" rules in a procedural order so that the run-time system doesn't have to try every possible combination to find (or fail to find) a matching result.
The proper ordering of declarations can be quite subtle. With a modestly complex program you can make a seemingly unimportant change in the order of the declarations and have the runtime go from a second to a week.
In this case the professor didn't (couldn't) know how long a Prolog program to solve this problem should take. He just assumed that you had found a more efficient ordering for the declarations. He might even have thought it was luck rather than deep insight that your program was faster than his. But you have to a decent understanding of the limits of Prolog to get a complex program to complete in a reasonable time, so you had to be good before you could get that lucky.
If you couldn't already tell, I have a low opinion of Prolog and declarative languages. They are "parlor tricks". Much like computer 'Life' and neural networks, simple programs can produce unexpected seemingly-sophisticated results. But they don't get better from those initial results. To compute the answers or results you want in a reasonable time, you end up with at least the complexity of writing things in the traditional explicitly procedural method.
The promoters of declarative language typically don't mention that you end up writing rules in an explicitly procedural order if you want the program to work. If you press them on the issue, they then say "well, OK, it's not actually any easier to write, but it's easier to verify that you've correctly specified the desired result." But if you have to carefully shuffle declarations around, and even then some results unpredictably take centuries to compute, pretty much no one cares.
it made a total hash out of what I was trying to do. But he lost the source code, so I couldn't prove that he did it. Of course we couldn't fix it either. It was in code that calculated people's paychecks. He got fired. I quit.
who just aims to get what is functionally absolutely needed finished & tested by the deadline? Bear in mind that most of my deadlines get set by clueless salesmen who even if they consult me generally tend to ignore what I say and tell the client what the client wants to hear.
I haven't implemented a fully finished system by the deadline in years simply because I can't squeeze 3 months work into 1 month.
Build a Man a Fire, and He'll Be Warm for a Day. Set a Man on Fire, and He'll Be Warm for the Rest of His Life.
Axually, we wrote the code long before 4.4.0 or 5.anything, so... new manual entry is unhelpful. :) (I cited "MAXINT" given my C heritage .. PHP's nomenclature fails anyway, as they lack an analogue to "MININT" ;3)
When you've got code failing at unpredictable places for unpredictable reasons, the first place you look is not the "integer" subsection of the manual, anyhow. Besides, by that time the damage were already done. We noodled out the cause and thereafter found your cited manual points to corroborate our theory.
We were still stuck using PHP which apparently cannot understand anything but signed 32 bit reliably, interfacing with MySQL which isn't capable of interim calculations in that space.
we refuse to write anything but simple two's compliment logic into all of our applicable SQL statements, so for things like sort we just aren't going there.
Allow me to forstall suggestions of using GMP given that gmp_strval(gmp_add(gmp_init("2"), gmp_init("2"))) is fail compared to "2+2" in every conceivable way, and there do not appear to be any OO bindings for GMP in PHP 5.x to rectify.
Put simply, we could obviate this problem easily if ANY of the following were possible:
* Sane integer support in PHP
* Sane OO support in PHP (for example, OO GMP bindings .. though there would still be crippling performance hits for major parts of our app!)
* sane functional support in the database to handle the two's compliment logic imposed by PHP
If we had the resources to remake the project in Ruby or Python against a postgres database, then all of those possible solutions would be at our fingertips, so much so that only the first solution would need to apply. The other solutions/capabilities would simply stand around looking cool. :P
So... meantime, can't afford the Ferrari and have to duct tape the pinto's engine together. *sob*
People willing to trade their freedom of expression for temporary entertainment deserve neither and will lose both.
Yes. But mostly it's not to "make it work"; it's because the customer wants something that is entirely against the original design they asked for.
My worst shortcut is to use fixed-sized strings with non size limiting functions, as in:
char Str[255];
sprintf(Str, "%s, %s", Lastname, FirstName);
I really wish snprintf was available on my C implementation.
Non-Linux Penguins ?
First year at university, as part of the end of year project, we coded a shortest path algorithm to work out the distance between two stations in the London Underground system. However at 4am a couple of hours before the class presentation we discovered a bug! This was that if you chose the station 'Bank' it could for example take you to 'Embankment' (since it contains 'bank'). Our 'fix'?? We renamed Embankment to... Embonkment! Nobody realised in the presentation! :)
So we had a race condition on database transactions using two-phase commit, your usual mind-fucking WTF situation, drove us up the walls for days, you all know what I mean. We knew it was a race condition because if we put a sleep() statement at the end of one of the transactions, everything ran fine. sleep(10) was always long enough, and since all of this ran asynchronously in the back end, an end user would never notice the difference.
So we went to the customer. We told them that we could continue to bust our brains trying to find a "real" fix, and didn't know how long that would take, or we could just leave the sleep() in. And we could even make the length of the sleep interval configurable, so they could try to make it shorter than 10 seconds, if they really felt like fiddling around with it.
The customer went for the configurable sleep().
Always keep a sapphire in your mind
> Once I had an assignment due and at the last minute before being evaluated, realized I had made a huge mistake, even though the code looked OK...
I once did almost the same thing, except that I wrote the entire assignment the first day we got it, during class. But I couldn't turn it in yet. And nearly forgot about it. So I turned it in at the last minute...
Except that I had misread the specification! Oh, the program worked just fine, but it printed everything to the screen. It was *supposed* to go to output.txt. That would've been trivial to change, if I actually had any time. But now I was out of time and couldn't change the code I had submitted...
With a bit of quick thinking, I actually managed to convince the TA that the problem was that you were supposed to execute the program as:
java MyProg > output.txt
So instead of getting a zero, I got 98%, because I had failed to document this.
syntactic sugar is just fine, but what I would really like is syntactic caffeine.
As of Postgres v6.2, time travel is no longer supported.
So it was 1999 and I was working for a mom and pop software shop, we had been acquired by a dot com. All our money and toilet paper stock options were held until we delivered the re-branded product with source. Part of the "rules" said we had to have only C/C++ and VB6 source, NO OTHER LANGUAGE.
....(you get the idea)
. We finished converting a few rogue scripting modules and things like that, which creep in over time. But we COULD NOT find the source code to one of our VB6 DLLs (an old one that had not been changed since it was first compiled in VB6). We searched and searched and eventually the fastest coder(not me) started rewriting it. We were 1 day from delivery date and there was no way he could finish it, so I ran it through a disassembler.
the C++ code we delivered looked like this:
int functionName(int parm) {
_asm {
push esi
mov esi, dword ptr ds:[esp+8]
mov dword ptr ds:[edi], esi
retn
}
It was unreadable, but it compiled and worked and we got our money. I still wonder what they ever did with that... since the software is still in use...
One of my uni courses our assignments required us to build circuits on breadboards in class - no opportunity to work on it otherwise. My lab partner and I were having problems with one assignment which, despite being wired properly, refused to produce the required output. After checking and rechecking wires, swapping out gates, etc., we were finally down to the last five minutes of class with no idea what to do next. Out of frustration, my partner reach out and scrunched the entire mess of wires in his fists and held them there.
"Try it now"
It worked. He just sat there while I dragged the prof over to evaluate it. As soon as he was done, my partner let go and it stopped working again.
We had an easter egg in our code that was in a routine scheduled to be executed only at 0-dark-30 when our users were long gone. But someone later called the routine as part of the loading process, and the users ended up seeing it anyway as they signed on at start of day. It made people smile, so we left it in.
A few years later, we were telling a client that we couldn't add their new feature X because we don't have the memory. At that point the director said to get rid of the easter egg and then it'd fit. (A few hundred bytes was not going to make a difference, but our director didn't care, it was a perception thing.) What we got instead was a hundred bug reports that the easter egg wasn't displaying, and that they "needed" to see it so they'd know when start of day was complete.
John
That's the good thing about open source! All of the dirty hacks the devs use eventually get weeded out of the code as time goes on! Honest!
I always just hard-code all my levels - it's easier to just go back and recompile (which takes 15 seconds in C or 0 seconds in python) than code all the extra logic in for reading from files. As another plus, this makes it harder for other people to cheat. Speaking of cheating, once I called my player save file "makefile" to discourage people from looking at it or modifying it.
And, I never split my code into multiple files - scroll and Ctrl+F were good enough for my grandfather, and they're good enough for me!
This is the code for the Apollo 11 lunar lander flight computer.
http://code.google.com/p/virtualagc/source/browse/trunk/Luminary099/LUNAR_LANDING_GUIDANCE_EQUATIONS.s?r=258
and yes some of my code is in there along with the equivalent of a few "goto's
Lots of bright people worked on this and in some circumstances a "goto" is required.
*--- Sometimes a majority only means that all the fools are on the same side. ---*
What, you think no hobby programmers have added quick hacks because they've spent two days chasing a bug and still can't find it? No open source projects have ever added quick hacks to make a feature they want to boast about work in time for their code freeze?
I am TheRaven on Soylent News
Back in college, we were at a programming competition and I was the on-the-keyboard coder for one of the problems. We had 10 minutes for the problem and I coded it quickly, having decided on the best algorithm before sitting down. Part of the solution was a sorting routine on a list. We were using Visual C++ although we were all not C++ experts at the time, and so rather than mess with the STL and the possibility of having to read documentation, I did it all from scratch. I knew that sort was already in use by the standard library, so I called my routine mysort.
Apparently, however, Visual C++ includes a mysort in its standard library. So, with the clock ticking down and the solution's only impediment to our victory being an identifier conflict, I renamed the routine the way that any one of us would have: myfuckingsort. We won the competition.
In this particular competition, the judges were not supposed to read our code - they just run the output of your code on the input and check for correct output - so I felt safe when I typed what I did. However, one of them came up to us afterwards and told us that they do in fact usually read the code of the winning team to see if we did anything unique in our solution. Yep. Sure did. And my classmates and professors never did let me live down what was affectionately nicknamed the fucksort algorithm.
But I might have missed some. There is not much difference between "return 0;" and "ret=0; goto exit_function;". Both are unconditional jumps there is no rational reason why one should be "considered harmful" and the other not.
I really love this bit :
DMP* VXSC
GAINBRAK,1 # NUMERO MYSTERIOSO
ANGTERM
sbb
# Page 731
# BURN, BABY, BURN -- MASTER IGNITION ROUTINE
BANK 36
SETLOC P40S
BANK
EBANK= WHICH
COUNT* $$/P40
*--- Sometimes a majority only means that all the fools are on the same side. ---*
10 Print "No"
20 Goto 10
Well, in part, but another important lesson in science labs is learning to report the truth, even if is disappointing and not what you want. This is an important lesson and unfortunately even some well known scientists don't learn it,
We do this at my job. We have a decent production database system, but we develop against a K6-2/400 with 256MB of RAM and a couple flaky SCSI disks. If it performs adequately there, it'll perform adequately anywhere.
Not that I have done this but I have seen plenty of web desigers use a css 'display:none' or before that was happening put comments tags around data that they did not want the site visitor to see.
HELP!
I'm trying to get this code to work. I'm at an altitude of 6,000 ft, hovering over the Sea of Tranquility, and the darn thing keeps crashing! (The code, not the lunar module.)
PLEASE don't connect me to that Bangalor helpdesk again! I am in serious trouble here!
Has this been tested for Y2K compliance?
Did we not pay our last support bill?
- Major Tom
I remember 15 years or so back; I was trying to get an application convert a text file into a Word document. I was using all these nice OLE calls from within Delphi but for some reason it didn't work.
The deadline was looming, so I ended writing a function that copied the files and renamed the extension to DOC. When opening it in Word it didn't show any errors. Unfortunately my client found out and went ballistic. By that time I luckily had the word conversion code working and was able to provide a new executable that worked as requested.
Let others smack you down, but with nearly 30 years of programming experience in numerous languages, I'm with you. Indented branching flow seems clean, stable and maintainable. I got dissed for a job i applied for because my code was designed this way instead of the "enlightened" way of throwing exceptions. Exceptions are ok, I guess, if everything is a C++ objects that self-destructs when it goes out of scope, but reality doesn't always work that way. In retrospect, I'm glad I'm not at that job.
-- There is no truth. There is only Perception. To Percieve is to Exist.