Dirty Coding Tricks To Make a Deadline 683
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?
Re:Here's one... (Score:2, Interesting)
Balancing act (Score:4, Interesting)
Similar (Score:1, Interesting)
Wolf 360 hack (Score:4, Interesting)
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?
Game Art (Score:5, Interesting)
Technically not a code fix, but still a valid solution.
seen some bad shit. (Score:5, Interesting)
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.
Re:University Assignments. (Score:2, Interesting)
We discovered that trick in O-chem lab too. You start with the percent yield to get an A on the lab and then back calculate your intermediate yields and amount of product you expected from the reagents you weighed. Fond memories.
Train simulation (Score:5, Interesting)
Re:University Assignments. (Score:2, Interesting)
Re:Wow. Talk about old news. (Score:3, Interesting)
Quick, find the dupe and copy-paste all the +5 Insightfuls!
Example (Score:5, Interesting)
#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;
}
Re:University Assignments. (Score:2, Interesting)
Re:Really? Not Slashdot's fault, if so... (Score:3, Interesting)
Re:Study Assignment (Score:2, Interesting)
He was a pretty good prof, otherwise.
Re:One word.. (Score:5, Interesting)
You often cannot develop software with the language you want, but must develop it with the language you have. C has no such features and, therefore, goto is used more often than in languages that have them. Fit the strategy to the tool.
This is reasonable, but it assumes some other function can do the needed cleanup code or other data massaging just as cleanly. If the goto is being used because finding the value is an error condition, you often have to do certain things as soon as possible in the code so you do not lose important debugging information.
And, no, exceptions are not part of C, and setjmp/longjmp is, if anything, even less likely to pass code review. An advantage of goto is that you can keep the cleanup code in the same function, visually close to the rest of the logic and sharing the same locals.
Even worse stuff! (Score:5, Interesting)
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.
Prolog Assignment (Score:5, Interesting)
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.
Re:One word.. (Score:5, Interesting)
But as below says, they make error handling an easier task as well as some oddly structured loops for which try/catch logic doesn't get you all the way
Ugh. Magic invisible gotos FTW! [joelonsoftware.com]
Comment removed (Score:5, Interesting)
Re:PHP signed 32 bit integers (Score:2, Interesting)
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*
Re:University Assignments. (Score:4, Interesting)
You laugh, but that's the basis of 'Test Driven Design'. :D You were only supplied with 1 test, and you passed it. Had their been more tests, your code would have had to be what was really wanted.
I've started to think about how a class could be run like that... Create a series of unit test sets that progressively test more of the program. For each assignment, give the students the next set of tests and have them code to make the tests pass. In the next class session, work to show everyone how to make it happen, then give the next set.
Configurable sleep() (Score:3, Interesting)
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().
DOS to the rescue... (Score:3, Interesting)
> 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.
VB6: Lost source code - Ultimate repack (Score:5, Interesting)
. 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...
Not exactly programming, but... (Score:2, Interesting)
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.
Re:Even worse stuff! (Score:2, Interesting)
I've come across horrible if-statements, too. One developer I worked with liked using the following for code he wasn't using right away: if (1 == 2). There're many other hilarious variations, of course. The thing that got me was nobody else on my team questioned that if-statement for over 4 months! They saw it and assumed it was important. I came across it while fixing a bug and, at first, couldn't see why several hundred lines of code seemed to do nothing at all. In the end, all code surrounded by that if-statement was unneeded, as admitted by the developer in question. Why didn't he remove all of it to make things clearer for the rest of us in the first place? Instead he let it sit there and clutter up pertinent code until another person took the time out of their busy schedule to do some housekeeping. Don't get me wrong; that developer had done the same sort of thing on many files - not only the specific instance mentioned here. Hunting through ~1100 files for rogue if-statements wasn't fun, even with aide of search functionality in SVN, since I 1) had no clue what other conditions the guy decided to use while being lazy and 2) couldn't figure out where to begin since the issue was EVERYWHERE. I made the developer sit down with me in order to make progress. When all was said and done, the code base was noticeably lighter and much more manageable. Oh, the joys of going through everybody else's code while fixing bugs. The biggest change came in the form of new and incredibly strict coding standards for the team. This was my first programming job and I'd only been there for 3 months, so I guess it was a good experience in one way or another.
Easter egg dependency (Score:5, Interesting)
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.
Re:Example (Score:3, Interesting)
I don't think the efficiency is worth having a non-standard construct, considering a simple switch would do the trick.
You could also split the function in multiple function (because having all the code in the same function is not very useful as local variables are trashed between executions), and directly returning pointer to the next function to call (hence you could spare of the cost of actually calling f() before jumping).
Anyway, a nice trick. Didn't thought I would learn another one in C. The worst I ever did with function pointer (not in production code, of course, just to provoke disgust) was in the line of:
#include
int f0()
{
return 10;
}
int f1()
{
return 20;
}
int f2()
{
return 40;
}
main()
{
printf( "%d\n", (*((int (*)())(((int)f0+(int)f2)/2)))() );
}
(yes, this will print 20 on most compilers).
Re:University Assignments. (Score:5, Interesting)
Re:Here's another one... (Score:5, Interesting)
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 [google.com]
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.
Re:University Assignments. (Score:3, Interesting)
On the turn-in day, everyone turned in their huge heaps of paper that covered their design - again, practically impossible for the professor to 100% go through. Included also was a printout of everyone's signals within the chip - intermediate ones, and the final output. And of course, >95% of the things turned in gave the correct output and had everything correct inside.
So the professor starts his lecture, and then stops and says "OK, everyone up!" And we headed to the computer lab, where he made everyone sit down in front of a computer, one by one, load up their chip, and gave a new input string (maybe 300-400 bits), and made each person run it.
Approximately half the class had the output of their chip be the same output for the original "sample" input he had given so people could test - that is, their entire big ASIC (because it had to LOOK complex or it would be too obvious it didn't do anything) was essentially a giant set of fake elements which actually did nothing except give the appropriate output - for the ONE sample input.
I have to admit, mine worked for the original input, but when he gave the new input, my output was correct for the first 399 bits - but the 400th was incorrect. It should have been a 1, I had a 0. It seems that no matter what the input was, my last bit (regardless of the number of input bits) had a stuck-at-0 fault. But since his sole sample input had a 0 as the final output bit, I never detected the fault. However, in this "second sample", the last 30 or so output bits were all 1's, and the difference between 29 '1" bits in a row and 30 "1" bits in a row in terms of looking at a long line quickly (as the professor was) is not noticeable. I saw it, but the professor didn't, and I got credit for the chip.
Comment removed (Score:4, Interesting)
Re:Wow am I the only one in here (Score:3, Interesting)
Here is my strategy for dealing with this situation:
1) Tell the salesmen that you have absolutely no problem with them telling the customer whatever they want. Their function is to make sales to customers. Your function is to write software. You won't try to tell them how to do their job, because quite frankly you aren't qualified to know what's best for sales. Of course the implication is that they shouldn't tell you how to write software, but you probably don't have to tell them this explicitly (well, it happened once that I had to say it...)
2) Show the salesman what you actually *are* going to deliver. Generally a list of use-oriented functionality is the best. You might be doing a lot of refactoring underneath, but they won't understand that. Only list what the user will see.
3) Probably what they are saying to the customer and what you are promising to deliver will not match. No matter how clueless they are, the salesmen will probably notice and tell you, "You had better do something to fix the situation". This is where you reiterate, "I can't tell you what to say to the customers, that's up to you. But this is what I plan to release. However, if you would like to substitute something on this list with something more important, I'd be happy to oblige."
4) Now they will still want it all. They will tell you that the whole company will go under unless you deliver everything. You can now say, "That's a shame. I like working here too. Well, if that's the way it is, I guess I'll go fix up my resume. It was great working with you." You only have to do this once (thank god). At this point the salespeople will say, "Well, maybe we can do something if you at least give us feature X".
5) Negotiate with the salespeople. But use each piece of functionality as a lego block. Its size is immutable, but you can put it in, take it out, put it in a different place etc. At every point make sure to point out that you are quite happy to allow the salesmen to choose what they want you to do. It's just that it doesn't all fit.
6) Sometimes you will run into the situation where the salesman will swear at you and tell you to go do something anatomically impossible. Then they will storm off. At this point it's important to let them go, but to go to your own management (or executive management if you have no manager) and explain, "The salesmen are upset and I understand their point of view. They can't have everything that they want. It's frustrating for me too. But I need them to choose what things are most important. If you could just have a chat with them so I can prioritize things properly I would really appreciate it." After this you will have no problems (unless the salesman in question *is* executive management, in which case you should jump ship as quickly as possible).
7) Probably you will have to go through this charade about 4 or 5 times. But each time it will get easier. There will be one last time where they will pull every dirty trick in the book. Just hang tough, because after that you will have no problems.
Hope this helps.
Re:Here's another one... (Score:2, Interesting)
DMP* VXSC
GAINBRAK,1 # NUMERO MYSTERIOSO
ANGTERM
Re:Here's another one... (Score:2, Interesting)
# Page 731
# BURN, BABY, BURN -- MASTER IGNITION ROUTINE
BANK 36
SETLOC P40S
BANK
EBANK= WHICH
COUNT* $$/P40
Re:Last one was great! (Score:3, Interesting)
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.
note really code (Score:2, Interesting)
Re:Prolog Assignment (Score:2, Interesting)
Interestingly, a LOT of people, let's say almost everyone, get Make wrong because they don't understand how the declarative rule structure works.
I'm not a fan of ANT, actually; I think it exists to solve a problem that Sun should have never created in the first place. (Produce arbitrarily named .class files from a given .java file.) I don't know how declarative it _really_ is under the covers, but everyone I see saying "it's better than make" are doing procedural things with it and using that to justify ANT over make.
(My gripe with ANT--aside from the XML soup--is it affords sloppy build systems: it's a wildcard enabler.)
Hex Editor Fun (Score:1, Interesting)
Working on an application for a now defunct airline. Developers embedded similar to the following Oracle 7.3 SQL in an executable:
select *
from bob A, fred B
where A.key = B.key;
Rule-based optimizer depended on ordering the tables in the from clause correctly for an efficient join (driving table will be last in the list), but the developers got the order wrong. So, I used a hex editor to reverse the aliases A and B in the from clause in the executable. Voila, performance went from dog slow to blisteringly quick without a recompile (no time for that).
Word Conversion (Score:2, Interesting)
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.
Comment removed (Score:3, Interesting)