ID:105683
 
Keywords: design, motivation
Over the last few days, I've discovered I retained just about all my knowledge of how to program in DM... remarkable for a fellow who has taken a vacation from coding for weeks and months. Not only that, I seem to have become better at it.

I guess the incubation has been good for me, as by separating myself from my code for awhile, it provided the necessary mental distance to critically assess what I've been doing and make improvements to it.

Here's a few things I picked up just recently:
  1. Never stop trying to make your code more self-contained/modular.

    This largely entails thinking very much in object oriented terms and separating code into files named not for something like their path (as I did before recently) but rather files related to a specific feature being added. Even though I might have a mob, client, and special datum definitions all in the same file, if this block of code has no references outside if it, that's self-contained code.

    In a best case scenario, if the code is well-modularized enough, I can just yank one file and have the whole functionality I need with little-to-no modification needed. This would be particularly useful for using test beds that tweak the desired performance of the related code.

    Remember: it's much easier to modularize your code while it's still fresh on your mind because what's obvious to you today will some day need to be almost completely relearned. So don't wait until it's time to create a library, start thinking about how you might be able to do it now, while you're coding it.

    You probably won't be able to do it right away, while the code is still being conceptualized, but a solution is likely to occur as long as you keep in mind your intention to make the code self-contained.

  2. Don't be afraid to code things that are completely disconnected to your existing code.

    I often describe building an epic project as building a skyscraper one board at a time. However, there's a problem with this analogy: it assumes that your structure has to deal with gravity. As a programmer, you can ignore gravity while constructing and reap the benefits of not having to worry about holding anything up until it's done.

    I've found it's better to just code an independent entity as though it has nothing to do with anything else, and worry about connecting it to the rest of your code later. If I've got a pretty good idea about how to build a penthouse suite, but I don't know how build the building underneath it, no problem. Just code that penthouse suite and the rest will come in time.

    Perhaps the number way I stumped myself while coding is by asking myself a simple question, "now, where was I?" That's a really hard question to answer yourself when you're staring at several dozen files of code. Turns out that question was a fool's errand: it's not about where I was, but where I'm going. When it longer matters how I'm going to add it, when I'm adding it now and worrying about how it's going to fit later, being stumped does not exist as long as there's one thing I'd like to add to my game.

    You'd think this would burn down your code by creating a bunch of garbage that you can't connect to the rest of your code. On the contrary, if you've been working with your code recently at all, you'll probably recall what you need to know about connecting the code while you're writing it. You may even need to code some new interfaces, or set about improving your existing code (as this is a great opportunity opportunity to reassess if that code is self-contained enough - see #1, above).

  3. It's better to overload an existing proc to exhibit more intelligent behavior than it is to create a brand new proc to handle a special case.

    For many game concepts, for the overwhelming majority of what your game does BYOND already has procs related to it. Enter() determines if you can enter something. Entered() determines what happens when you have. Move() determines how you move somewhere. And so on.

    You don't have to abandon those procs, you just need to re-educate them with the special behavior that applies to your game. For example, step_towards currently can't take into account multiple maps in your project because there's no unified method of joining maps. A simple override, and suddenly your step_towards knows how to step between your maps. You could even include true AStar pathing functionality.

    Why is this better? Many reasons. Because Dantom had a pretty good idea about the flow of an online environment when he built those procs, and keeping your game in line with that will help its form. Because adding more procs that do the same thing just makes that many more procs to remember later. Because, when all your code operates under the same parameters, you'll encounter less conflict later.

    In a little more complex of an example, I have planets that use Lummox JR's swapmap to generate plots of turfs that the players can visit. I initially created some special procs that created the swapmap, located the swapmap, found a place to enter that swapmap, then moved the player to the swapmap. Very awkward to remember later. The revised code simply overrides the plot object's Enter() and Entered() code to run all the necessary procs automatically. Now, all I have to do is tell movable atom to Move() into a plot object, and the rest is handled automatically.

    One caveat, though: if you're going to override core procs, code with efficiency in mind. If you have to run several thousand lines of code every time a mob moves, your game will probably slow to a crawl after the first 20 mobs. Code in mind of the program flow going through as few lines as possible in the greater majority of cases.
If I could summarize all the above in one sentence, it would be this: Do not work for your code, make your code work for you. When you start coding a new language, you will be doing the former. However, as you continue to practice coding, you can perpetually invent new ways to turn the tables. The only catch: progress will be slower unless you're actively trying to do this.

Of course, these suggestions may not be the best for everyone. Every programmer has their style and experience. Perhaps this advice is too hard to follow. Perhaps this advice is trivial and you've moved on to better things. In the end, the best thing to do is to practice and, if you're working with other programmers, make sure your code is well commented and you're all following the same standards of format.
This is very good advice. I'd add to the first point that it's never too late to change your code. People might realize that their code could be improved but are afraid to make the necessary changes. This is another way that writing code is not like making a building. When you're building something it's a hassle to take things apart to redo something. Redoing things means you're wasting materials and time.

Code just isn't the same. You have an infinite supply of for loops and you don't need cranes and trucks to move them around. People still have a sense of permanence about code though. Once they put an idea into code they feel obligated to stick with that code or only make slight modifications. Part of this is because people tend to stick with their initial ideas, part is that their code isn't modular and they're afraid that drastic changes might break other things. If your code is set up decently it shouldn't be a problem to rewrite something.

If you find yourself working on a project and think "I should just start over" then you probably did something wrong early on and were afraid to change it. Try to figure out what that mistake was otherwise you'll just do it again.
It's true the modular approach to programming is usually the best choice, but if you're focused too much on splitting and separating everything you could probably just end up with a big bowl of spaghetti code.
SuperAntx wrote:
It's true the modular approach to programming is usually the best choice, but if you're focused too much on splitting and separating everything you could probably just end up with a big bowl of spaghetti code.

I get what you're saying - that if you spend all your time separating your code and forget what it's intended to do, it will lose its practical use - but spaghetti code isn't the right word for it.

Spaghetti code literally refers to heavily interdependent code. All these threads of code mingling together with other threads of code. If you start the flow of your program on one of those noodles, where will it end up? Who knows? Into a mysterious bowl containing all the noodles in the entire program.

DM is an object oriented language that discourages spaghetti code (though one can still do it if they deign to use the goto command). Striving to make your code modular on top of that reinforces this by trying to make the individual objects interact as little as possible, and be self-contained.

So, it's a bit like the opposite of spaghetti code. You're constantly keeping an eye out for when the strands of noodles start and end, laying them down next to each other identify this, with an end goal of engineering them to exist in several sealed and clearly labeled packets.
And yet, the most important thing for most BYOND devs is, "get something done".
Vermolius wrote:
And yet, the most important thing for most BYOND devs is, "get something done".

See, the trouble with that is just getting something done is too easy to be interesting. ;)
Geldonyetich wrote:
See, the trouble with that is just getting something done is too easy to be interesting. ;)

While this -is- true, the idea of pushing on holds a lot of value.

1. Never stop trying to make your code more self-contained/modular.

I have a couple of fairly large projects on my hands. Both of them were born in my early days of BYOND (one of them, DBTC, is literally my first BYOND project, and the other, Murder Mansion, came a couple of years later, which now happens to be 6 or 7 years ago), and their initial programming was definitely very amateur; code originally all in one file, lines of code repeated in multiple places, rather than pulled out into a single proc, etc.

Over the years, I've tended to switch back and forth between working on the two... I'll abandon one, grind out an update on the other, then switch... Sometimes, this cycle takes a year or more, but it's happened a handful of times...

And each time I jump back into one of them, my first order of business is to further modularize and universalize the code... And every time I come back to one, I find even more ways to do this... Even if I thought that on the previous cycle, I had made them as streamlined as possible, the next time I see them, I've always found ways for further improvement...

In fact, once I get to the next switch, to DBTC, I'm expecting to take quite a lot of time doing just this...
Vermolius wrote:
Geldonyetich wrote:
See, the trouble with that is just getting something done is too easy to be interesting. ;)

While this -is- true, the idea of pushing on holds a lot of value.

The day Geldonyetich qualifies to talk about getting something done is the day marshmallows will grow wings made of pudding and take over the milky way.
In other words around 2012.
Toadfish wrote:
In other words around 2012.

It's all so obvious now - the fiery apocalypse the Mayans predicted was probably because all the firemen were having so much fun playing my game to do their job.

Alternate theory: upon my game's release, Hell froze over, and all that heat had to go somewhere.