ID:95390
 
Keywords: design
You're Wrong.


There's a certain mentality that I've noticed a lot of users within our ranks have. This is mostly common to inexperienced programmers who have managed to throw out what can be considered barely passable games and who now suddenly think they're top dog because they've done so.

The mentality I'm referring too is pretty much summed up in the title of this post, if at any time recently you've said: "it works, so I'm doing it right", "you do it differently than I do, that doesn't make you right" or any variation there of, then chances are you fall into this category. And this post is aimed directly between your eyes.

You see, there are many ways to do lots of things. And anyone with any life experience can tell you, even though they work, it doesn't make them safe, advisable and least of all, correct.

For a quick analogy: I can drive the wrong way down a motorway. By the logic of those targeted at this post, I'm doing it right, because I'm still getting to my desired destination. By the logic of all other experienced motorists not on any form of narcotic, I'm being an absolute tool by driving recklessly and putting the lives of other people in my obviously foolish hands.

In a real life scenario, I'd probably get my license revoked for dangerous driving and there might also be some jail time depending on my reaction towards the judge. If programming required a license, everyone this post is targeted at would by theory, also get their licenses revoked and no longer be allowed to make games. And I dare say a few of you would also be looking at jail time for your reactions towards those who attempt to help you by telling you you're doing it wrong.

Now lets move onto a code example. One Garthor corrected me on recently; just to show that even I am not infallible when it comes to programming. You can view the thread here. Please note my reaction, or lack there of, as that is pretty much what this entire post is about. Instead of arguing that I'm correct because it works, I conferred with my colleagues and then accepted the words of a superior programmer silently, and am now no longer making that mistake.

Wrong:
#define SECOND 10
#define MINUTE (SECOND * 60)
#define HOUR (MINUTE * 60)
#define DAY (HOUR * 24)

client
proc
SaveProc()
//Some random save proc for clients.

proc
recursive_save_or_something()
for(var/client/C) C.SaveProc()
sleep(HOUR)
.()


Better:
#define SECOND 10
#define MINUTE (SECOND * 60)
#define HOUR (MINUTE * 60)
#define DAY (HOUR * 24)

client
proc
SaveProc()
//Some random save proc for clients.

proc
recursive_save_or_something()
while(TRUE)
for(var/client/C) C.SaveProc()
sleep(HOUR)


(Come to think of it, that proc should probably have a set background = TRUE in it.)

As you can see, my original example still worked, but that didn't mean I was right, at the end of the line, a place you can't reach in two minute testing sessions of new features, I'd have eventually crashed my game entirely. And we all know what that means.

I'd have gone running to the developer forums crying: "why oh why sweet merciful gods of programming does my game fail so?" They would have eventually given me an answer if anyone cared enough to stick around long enough to debug it, and I'd have been left with a lot of reworking to do, simply because I never learned my lesson and undoubtedly made lots more of these mistakes.

Now let's take a trip down memory lane, way back in 2005 when I was a way more inexperienced programmer than I am now and dared to ask the question a lot of you refuse to ask and stick to your "I'm right" mentality: Why does which way matter?. This thread should explain to you why we go out of our way to tell you why your examples are incorrect. Don't let the attitude a lot of us have fool you, our goal is to help you. But we're not certified teachers and a lot of us don't have the patience to hold your hand through everything. Which is why we often link to reference material that we hope you will read and understand.

I hope this article has been enlightening for you. And I also hope that it's also opened a few peoples eyes. You don't learn by getting it right first time every time, but if you're doing it wrong, you will learn by simply asking the right questions and learning from what better programmers have to say. If I had not listened to Lummox JR, Wizkidd0123, Xooxer, Crispy, YMIHere or Garthor, I'd still be making horrendous mistakes that would ultimately cost me the stability of my game.

That's not to say I'm still not making mistakes, as humans, we are doomed to forever make mistakes. Hell, the previous example I used in this post probably has a better way to go about it (ten points for someone who comes up with a working theory as to why). Which is precisely what Design Philosophy is for: Asking people if how you're doing something is right, and whether or not there's a better method to go about it.

If this post reminds you of yourself, I also recommend reading How to Fail at Game Programming by Deadron. Well worth it, if only for the entertainment value.
So true. Last week, I was talking to a fairly new developer who thought this was working code:

turf/space/spacestation
Enter(var/atom/enteringThing)

enteringThing.loc = locate(/area/spacestation)

Seemed to work just fine for making a turf in which the player who entered it would be teleported to the space station. However, when he tried to use Enter() in a similar manner to to coordinate various functions on the space station, he was boggled that he suddenly wasn't able to move.

The problem, of course, was that he needed to be using Entered(), not Enter(). Enter() was run at about the same time as Entered(), but the job of Enter() is to return true if you're allowed to enter the proc. When he override Enter() without returning true, all of a sudden he wasn't allowed to move anymore. The reason why he got away with it before was because the function of the Enter() actually moved the user.

He went on to make a similar mistake by trying to use typesof() instead of istype() to perform verification that something was of a certain type. Of course, typesof() returns a list of derived types (as long as at least one of the args existed otherwise it would return null) so because his arg would include a known type, his if statement was always being evaluated as true. Seemed to work, sure, right up until something came along that wasn't supposed to be true.

The bottom line is basically this: you need to know what your code actually does, in other words, exactly what you're telling the computer to do. Computers may be fast at computing, but they're dumb as a sack of rocks (pounded into silicon and veined with circuitry). They'll do exactly whatever stupid thing you've told them to do, Sorceror's Apprentice style, no more, no less. Whenever I see a fantasy scenario where the computer takes over mankind (e.g. Terminator, The Matrix) I can only smugly acknowledge that it would mean some dumb coder failed to pay attention to what they were coding.

Understanding exactly what every little line of code you've written does is not implicit knowledge, and we should forgive the newbies for not knowing this. A lot of this comes with experience. However, it'll come a lot faster if you regularly consult the BYOND DM help, resources, and forums to get a better understanding.

Put another way, when you begin programming, it's all you can do to simply focus on how to hammer the individual nails into place. When you're better at programming, the hammering of nails can can be done subconciously, and your attention should instead be on how to assemble entire rooms. When you've mastered programming, you'll be able to visualize the entire palace and its scheme in the greater universe.
Yeah this is why I tend to stay away from recursion in DM.

Small call stack ftl.
Definitely liked, my computer science teacher stressed this point throughout the semester. It might help "those type of people" to understand a bit better if you emphasized how following your advice would help with the overall maintainability of the code despite hinting at it. :)
Tiberath wrote:
Better:

Ugh... no matter how much I prepare myself for the inevitable, I'm always smacked in the face with the illogical insistence of many BYOND gurus on replacing recursion with an infinite loop.

Your first example was 'wrong' in that it would have resulted in a stack overflow eventually. This could have been fixed by spawning the recursive call (For anyone who isn't familiar with spawn, the code that is spawned takes place in a new call stack). It wasn't wrong from a design standpoint, it was wrong because the recursive design wasn't executed properly.

To provide a different design (loop instead of recursion) as a correction seems misleading to me. I've talked to several developers who's programs could have benefited from recursion, yet who decided to use a different, often convoluted, design because they were led to believe that recursion is an anti-pattern.

If there's a valid reason why recursion shouldn't be used in the above example, then please let me know, because I see no reason. On the contrary, there is at least one (minor) reason to prefer recursion over an infinite loop: the loop will eventually trigger a warning from DS.
Iain hit the nail on the head. This post only serves to show how very few on BYOND have any formal programming training or experience. Recursion is Comp Sci 101 but is rarely used where it should be and often used where it shouldn't. I've oft thought about holding a "Real Programming" challenge on BYOND, but what would be the point?
The person who I mentioned was making such obvious mistakes was taking formal programming courses. I'd say it has more to do with experience than training.

Besides, I'd argue that utilization of spawn() in that manner is technically not recursion. You're basically just throwing a list of things to do on the process manager. In assembling a list, what you have there is a loop in disguise whose iterations are being created via a fairly extravagant method.

What Tiberath was doing here was a deliberately broken example to point out how something that seems to work can bite you in the butt later. He wasn't trying to make a point about recursion vrs loops.
There wouldn't be one.
Honestly, I use the while(1) example, but I only saw the difference between it and the .() example whilst reading the comments (and because of DM I tend to gravitate away from .(), because of how long it took me to realize it existed, the while(1) was just more natural).
And yet, what you described, Geldonyetich, is completely irrelevant because the problem is the concept and logic behind programming itself, not the unfamiliarity with a language. If you take a veteran programmer and drop them into DM, guess what? They're going to make silly mistakes like using Enter() instead of Entered() because it's a nuance of the language. What they won't do is make novice logic and flow control mistakes.
Just because you're unable to find the relevance of something does not make it completely irrelevant, Airjoe.

Again, you're missing the context in which this original article was intended: code which seems to be working but, in reality, is not.

If you're here to pick a battle of intellectual wills, I promise you, a burned out forum veteran veteran such as myself will only disappoint.
I'm pretty sure the definition of irrelevant is the lack of relevance. You are completely missing both Iain's and my points, but I can't say I'm surprised.
If you paid better attention, Airjoe, you'd see Iain's point has nothing to do with your own.

His point was only that there are times and places where recursion makes sense.

You agreed and went on to make a completely seperate point that many programmers on BYOND are untrained or inexperienced.

You're both right, but for the wrong reasons.

Tiberath was not intending to argue that there are not times and places that recursion makes sense. He merely used an example of how a bad implementation of recursion could appear to work but later be problematic.

Yes, there are many inexperienced programmers on BYOND, and a good thing too: that's why articles such as this exist.

You see, the trouble with arguing with me is I actually read your posts and point out how they're largely based off of things nobody said. You're in the majority - I'm under the educated belief that the greater majority of Internet disagreements are similar failures to communicate. It makes me a real bore to invite to flame wars, especially if I decide to abstain upon recognition that the pervading problem makes further investment of my words futile.

Now look what I did? I derailed myself from my development. Hrmph.
Guys, don't you think your argument is a bit meaningless in the comments of said blog post? Could it be taken to the pager, because I'm sure (most of) it doesn't relate to the blog post itself.
@Iain: "Hell, the previous example I used in this post probably has a better way to go about it (ten points for someone who comes up with a working theory as to why)."
Wizkidd0123 is a good friend of mine IRL... shameless plug :D <3 him. He's doing well for anyone that cared, at school
I see a little problem here.
One of the main unique selling proposition of authoring tools, such as BYOND is their fast and easy visual success and thus one could argue that the delusion of being correct when not applying proper object-oriented programming paradigm in ones creation is somewhat encouraged.
Please do not misunderstand me, as I do not try to argue against modular programming, abstraction, encapsulation, polymorphism and whatever else you might find of help in BYOND, but rather that the target audience of the product is prone to come with the mindset you blame.
The concept of a call stack is something I only recently wrapped my mind around, so only about a year ago I would have had no idea why the first example ultimately leads to implosion. Are there articles I've missed on the subject, or is this issue largely undocumented?
Mobius: Again, this is basic computer science, but it's simply not taught on BYOND. Good programming in general isn't really taught on BYOND. We have "How to make an enemy mob" tutorials, but not general instruction on data structures or algorithms, concepts that are very important in any programming setting. If the only programming you know comes from tutorials like the ones BYOND offers, you're going to have a difficult time. The DM Guide is a great resource, but it's exactly that, the DM Guide, not a programming guide.

Unfortunately, though, new content on BYOND is a catch-22. The people who have time to write it generally don't have the ability to, and the more knowledgeable members have way too much on their plate to get an article or game out.
Not to try to pick another tiff with you here, Airjoe, but I think you're being a bit overly general. "Basic computer science." "Good programming." I don't think these are things you can expect a tutorial to cover. If you write up a tutorial on data structures or algorithms, have you truly bridged the gap to reach these goals?
Mobius Evalon wrote:
Are there articles I've missed on the subject, or is this issue largely undocumented?

It seems the subject is undocumented. While writing my last comment I tried to link to the reference or guide to back up my statements about the call stack and spawn. The problem is that I couldn't find that information anywhere! Thinking back, I don't know how I learned that fact. I plan to write a comment on the reference, but I want to find it written somewhere else, first, so I don't write something false or misleading.
Page: 1 2