Don’t use global state to manage a local problem

by Rob Galanakis on 25/09/2011

Just put this up on altdevblogaday: http://altdevblogaday.com/2011/09/25/dont-use-global-state-to-manage-a-local-problem/


I’ve ripped off this title from a common trend on Raymond Chen of MSFT’s blog.  Here are a bunch of posts about it.

I can scream it to the heavens but it doesn’t mean people understand.  Globals are bad.  Well, no shit Sherlock.  I don’t need to write another blog post to say that.  What I want to talk about is, what is a global.

It’s very easy to see this code and face-palm:

global spam = list()
global eggs = dict()
global lastIndex = -1

But I’m going to talk about much more sinister types of globals, ones that mingle with the rest of your code possibly unnoticed. Globals living amongst us. No longer! Read on to find out how to spot these nefarious criminals of the software industry.

Environment Variables

There are two classes of environment variable mutation: acceptable and condemning.  There is no ‘slightly wrong’, there’s only ‘meh, I guess that’s OK’, and ‘you are a terrible human being for doing this.’

  1. Acceptable use would be at the application level, where environment variables can be get or set with care, as something needs to configure global environment.  Acceptable would also be setting persistent environment variables in cases where that is very clearly the intent and it is documented.  Don’t go setting environment variables willy-nilly, most especially persistent ones!
  2. Condemning would be the access of custom environment variables at the library level.  Never, ever access environment variables within a module of library code (except, perhaps, to provide defaults).  Always allow those values to be passed in.  Accessing system environment variables in a library is, sometimes, an Acceptable Use.  No library code should set an environment variable, ever.

Commandline Args

See everything about Environment Variables and multiply by 2.  Then apply the following:
  1. Commandline use is only acceptable at the entry point of an application.  Nothing anywhere else should access the commandline args (except, perhaps to provide defaults).
  2. Nothing should ever mutate the commandline arguments.  Ever!

Singletons

I get slightly (or more than slightly) offended when people call the Singleton a ‘pattern.’  Patterns are generally useful for discussing and analyzing code, and have a positive connotation.  Singletons are awful and should be avoided at all costs.  They’re just a global by another name- if you wouldn’t use a global, don’t use a singleton!  Singletons should only exist:
  1. at the application level (as a global), and only when absolutely necessary, such as an expensive-to-create object that does not have state.  Or:
  2. in extremely performance-critical areas where there is absolutely no other way.  Oh, there’s also:
  3. where you want to write code that is unrefactorable and untestable.
So, if you decide you do need to use a global, remember, treat it as if it weren’t a global and pass it around instead (ie, through dependency injection).  But don’t forget: singletons are globals too!

Module-level/static state

Module-level to you pythonistas, static to your C++/.NET’ers.  It’s true- if you’re modifying state on a static class or module, you’re using globals.  The only place this ever belongs is generally for caching (and even then, I’d urge you to reconsider).  If you’re modifying a module’s state- and then you’re acknowledging what you’re doing by, like, having to call ‘reload’ to ‘fix’ the state, you’re committing a sin against your fellow man.  Remember, this includes stuff like ‘monkeypatching’ class or module-level methods in python.

The Golden Rule

The golden rule that I’ve come up with with globals is, if I can’t predict the implications of modifying state, find a way not to modify state.  If something else you don’t definitely know about is potentially relying on a certain state or value, don’t change it.  Even better, get rid of the situation.  This means, you keep all globals and anything that could be considered a global (access to env vars, singletons, static state, commandline args) out of your libraries, entirely.  The only place you want globals is at the highest level application logic.  This is the only way you can design something where you know all the implications of the globals, and rigorously sticking to this design will improve the portability of your code greatly.

Agree?  Disagree?  Did I miss any pseudonymous globals that you’ve had to wrangle?

No Comments

The skinny on virtual static methods

by Rob Galanakis on 22/09/2011

Today at work, I saw the following pattern in python:

class Base(object):
    @classmethod
    def Spam(cls):
        raise NotImplementedError()
class Derived(Base):
    @classmethod
    def Spam(cls):
        return 'Eggs'

After thinking it over and looking at the alternatives, I didn’t have an objection. I asked for some verbose documentation explaining the decision and contract, as this is really not good OOP and, some (me) would say, polymorphism through convention- which in dynamically typed languages like python, is how polymorphism works. But it is unfamiliar and generally considered bad practice, especially in statically typed languages.

Of course this sparked some disagreement, but fortunately, this is a topic I’ve read deeply into a number of times- first, when I was thinking about how to implement the pattern and realized the error of my ways.  Second, when I was working in another codebase that was a case study in antipatterns where this was used quite heavily.  I read into it yet again today so I could write this blog post and send it to the persons who disagreed with my judgement of the pattern in statically typed compiled languages.  So read on.

Let me reiterate- I’m not opposed to this pattern per-se in python or other dynamically typed languages.  I think it is a sure sign of code smell, but there are legitimate reasons, especially if you’re working on, say, a Maya plugin and have some restricted design choices, and this can smell better than the alternative, which is a bunch of other shitty code to deal with it.  In fact, it @abc.abstractstaticmethod was added to the abstract base class module in python 3.2, with Guido’s consent.  Which doesn’t mean it is right, and I’d still avoid it, but it’s not terrible.

My problem is with the pattern in statically typed languages.  When you make a method abstract or virtual on an interface of class, you are saying, ‘you can pass around instances of me or derived from me and they will have a method named Foo.’  Instance methods are bound to the instance.  When you define a method as static, you are binding it to the class.  So there are two reasons this doesn’t work- one technical/semantic, the other conceptual.

The technical/semantic cause is that virtual and static are opposite!  Virtual tells the compiler, ‘look up what method to call from the vtable of the object at runtime.’  Static tells it, ‘use this method at this address.’  Virtual can only be known at runtime, while static must be known at compile time.  I mean, you need a class to invoke the static method on!  The only way around this is through either dynamic typing, or some sort of reflection/introspection/codegen- in which case, you aren’t working with static typing, you’re emulating a dynamically typed environment in a statically typed one!

So, clearly the concept of ‘virtual static’ is impossible in static languages like C#, C++, and Java.  It doesn’t stop people from trying!  However, does the fact that the languages don’t support the feature make it a bad idea (the same way that just because python 3 supports it doesn’t necessarily make it a good idea)?

Yes, yes, a thousand times yes.  Let me restate the above: in order for ‘static virtual’ to be supported in a statically typed language, you need to use its dynamic typing faculties.  Look, I’m all for ‘multi-paradigm’ languages (even though some artard on Reddit berated an article I wrote because that phrase doesn’t actually make sense), but we need to be very careful when we start using patterns that go against the foundation of our languages.  Like I said- I’m not fundamentally opposed to the pattern, I am just opposed to using it in statically typed languages.

But that’s like saying, I prefer tomato juice to evolution.  I don’t even know what that means.  You cannot have virtual static methods in a statically typed language.  They are incompatible.

So much for the technical (vtable)/semantic (dynamic) reason (were those 2 reasons, or one reason?).  What about the conceptual one?

Well like I said earlier, virtual or abstract methods are part of a contract that says, I or a subclass will provide an implementation of this method.  Classes and interfaces define contracts, and at their core, nothing else (especially not how they’re laid out in memory!).  So if you’re passing around a type, and you’re saying, this type will have these methods- well, what does that look like?  I can hardly fathom what the class declaration would look like:

class Base {
    public virtual static Base Spam() { return Base(); }
    public virtual string Ham() { return "Base Ham"; }
}
class Derived : staticimplements Base {
    public override static Base Spam() { return Derived(); }
}

Well, shit. We’re saying here that Derived’s type implements the contract of Base’s type- well, Base has a ‘regular’ instance contract, the Ham method.  What happens to this on Derived?  Is Ham part of Base’s contract?  It must be, because otherwise I have no idea what the Spam() method is going to return for Derived.  Alright, so if you ‘staticimplements’ something, you get get all static and instance methods as part of your contract (and this is how python works, too).

So how do we use this?

void Frob(Base obj) { ... }

Wait. Shit. This says we’re passing in an instance of Base, whereas we want to pass in the Type of an object that staticimplements Base. So:

void Frob(BaseType obj) { ... }

So now let’s jump back to our class definitions:

class BaseType : Type { public virtual static Base Spam() { return Base(); }
class Base : staticimplements BaseType { public virtual string Ham() { return "Base Ham"; } }
class Derived : staticimplements Base { public override static Base Spam() { return Derived(); } }

Now we’re getting somewhere. We can define types that inherit from the Type object (that is some class like .NET’s Type class), and we can staticimplements those (and if you staticimplements, that implies you also get all instance methods).

Well shit, wait. If Base inherits from Type, then instances of Base will also get all instance methods from the Type object? Well ok, I can deal with that, we don’t have to use Type- what if Type inherits from RootType, and BaseType inherits from RootType, and RootType is just an empty definition so instances of objects that inherit from BaseType don’t have all of Type’s instance methods?

void Frob(BaseType baseType) {
    Base obj = baseType.Spam();
    //Well, how do we get an instance of BaseType from an instance of Base?  We can't.
    //RootType rt = obj.GetType(); //What good is RootType here?
    //BaseType bt = obj.GetBaseType(); //Wait, so we put a method on the instance that needs 
                                //to be overridden on the subclass to return an instance of the actual type?
}

I’m not going to go any further because I doubt anyone has even read this far. The question of virtual static functions in statically typed languages is pointless- much easier, then, to just throw up your hands and hack together whatever using reflection, dynamic, templating, or any other form of introspection. You can, for sure, come up with workarounds that are often quite specific and span hundreds of lines. I’ve read and gagged at a hundred of them.  But given that it is currently not just technically impossible, but conceptually brain-melting, why would you?

The problem at its core is, I think, that people learn a golden hammer in one language (in this case, python, Delphi, etc.) and try to apply it to another (C#, Java, C++), as well as people coming up with a design and then figuring out how to shoehorn the idea into the language.  Well guess what- not every language can execute any arbitrary patterns or designs well.  Learning python made this patently clear.  The language is so concise, each line (and character!) so meaningful, it is patently clear when I am doing something unpythonic- the meaningless lines of code, the extra characters, the redundant patterns in the code, the roundabout way to achieve something.  Static languages don’t have this concision, they don’t have the same economy, or flexibility.  There is too often a legitimate workaround or over-engineering, so when illegitimate workarounds are devised- well, who even considers it?  I certainly didn’t (hello, class Blah<T> where T : Blah<T>!).

So what are your choices here?  If you really think that this is your only option, your design stinks.  Stinks in that it has a foul code smell.  You have a few options:

  1. Singletons, which is a pretty big copout because you’re really just creating a static class by another name (but to be clear, are still a potential solution),
  2. Just create a new instance and call an instance method.  Suck it up, it really isn’t a big deal, though you basically require generics and a new() constraint for it, or the conceptual opposite:
  3. Dependency injection.  My guess is, if you’ve made it this far (congrats and thanks!), and you disagree, you’re not familiar with the idea of Dependency Injection or Inversion of Control.  I’d encourage you to read up on it, and realize it isn’t nearly as complicated as you may think it is, but far too interesting to get into here.

Good luck!


I’d encourage you to do your own googling and reading about this problem. It’s quite interesting and really highlights conceptual differences between languages, and understanding the problems or benefits to the approach will make you a better programmer and designer in your preferred language.

No Comments

Automation must be a last resort

by Rob Galanakis on 18/09/2011

A repost from altdevblogaday.  Original post here: http://altdevblogaday.com/2011/09/10/automation-must-be-a-last-resort/  As is usual, the title is more inflammatory than the contents, the contents muddle the issue, and things are far more clear after reading the comments.


As tools programmers and tech artists, we are responsible for the efficiency of our designers and artists.  And most tools programmers and TA’s I’ve worked with take this very seriously, and are generally very clever, so very few things can stand in their way when they are determined to speed up a developer’s workflow.  Most commonly, such speedups are achieved by the automation of repetitive tasks.

But we are also responsible for the quality of our codebase.  “Simplicity” of code and systems is commonly accepted as an ideal all coders should strive for.

Everything should be made as simple as possible, but not simpler.

And here is my problem.  Automation increases complexity and reduces simplicity.

An Example

Consider the following diagram, which could represent a single workflow with many steps.  Each Step represents some unique concept or block of code or logic that exists in a pipeline- for example, exporting the content, format conversion, writing a metadata file, assigning a material, and importing into game.  Right now, the user performs each one manually.

Obviously we can do better- we can half the number of steps if we write some code to automatically, say, launch an exe to process the just-exported content, and we can automatically write the metadata file on import.

 

Once this is in the wild, we realize we can automate the whole thing!  So on export, we do everything, and it even imports the content into game.  Great!  But of course we still need to support some manual intervention for things that don’t ‘fit in.’

There’s a problem here, though.  A big one.  The code has essentially remained the same- so even though the user’s experience is simpler (which is always the goal!), the way we got there was to add more complexity into the codebase.  Because here’s the thing about automation:  Automation relies on inference.  And inferring things in code is notoriously difficult and brittle.  We have basically all the same code we had when we started (though I’m sure we fixed and introduced some new bugs), except we have now effectively doubled the connections between the components, and each connection is brittle.  How much of your automation relies on naming, folder structures, globals (environment variables and singletons are globals too), or any number of circumstances that are now built into your codebase?  Likewise, if you merely added buttons to create automation, the additional complexity there is obvious.  All the old stuff is still in place, you’ve just created another UI and code path on top of it that is either using it or also accessing the same internals.

That is not what we should strive for.

This, instead, is what we should strive for:

 

This isn’t always possible- but I’ve seen enough pipelines to know that it is probably possible on most pipelines at your studio, and definitely possible on some.  It should always be our goal- that every time we want to ‘automate’ what the user does, we instead say “how can I reduce the complexity of the code so nothing needs to worry about this.”  This is how you identify automation that increases complexity versus refactorings that reduce complexity: when your change simplifies the codebase (this is open to interpretation but I’d imagine you can judge this pretty easily), and ‘automates’ previously manual parts of the pipeline, that is no longer automation- you have done an excellent refactoring that has reduced complexity and it is not automation (at least not actually- the users are free to call it what they want).

It isn’t always possible.  More commonly it would be possible but not without a substantial refactoring somewhere (maybe not even your code).  Sometimes, it is just moving the complexity around rather than removing it.

These things are fine! The important thing is that you are now really thinking about your codebase.  The goal isn’t to reduce the complexity of your codebase in a day, it is to ensure you are only adding valuable complexity and that you have identified opportunities to reduce complexity.

Identifying Trends

It’s not very difficult to identify when we are adding excess complexity when automating, or when we are simplifying.

If you have simple configuration needs, such as choosing two options or files, see if you can infer that setup instead from what the user chooses to do (such as providing him two choices, rather than one configurable one).

In contrast to that, prefer upfront configuration to inference if the configuration adds significant power and simplifies the code.

If common use cases no longer fit into the scope of the tool’s effective workflow, refactor the tool.  Do not start adding ‘mini-UI’s that support these additional use cases, or you will end up with a complex and confusing mess.

Always present the minimum possible set of options to the user that allows her to get her job done effectively.

As a corollary, if the code behind your simpler UI becomes significantly more complex when simplifying the actual UI, it is likely your system can be streamlined overall.  The lower the ratio of UI options to code behind, the better.

Conclusions

All too often I see tools programmers and technical artists automating processes by building new layers of code on existing systems.  Coders should always look for ways of simplifying the overall system in code (or moving the complexity out and abstracting it into another system) as a way to achieve a streamlined workflow for the user, rather than building automated workflows and adding complexity and coupling to the existing code.

I intentionally didn’t provide precise examples or anecdotes, but I will gladly provide personal examples and observations in the comments.  Thanks.

Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius – and a lot of courage – to move in the opposite direction.

No Comments

Python software metrics- my first useful OS project?

by Rob Galanakis on 5/09/2011

I’ve tried to open-source code quite a few times, but the projects have been niche enough that they haven’t been very useful.  Well, I finally have something universally useful.

I’ve take an interest in code metrics recently (as documented on this blog) and I have been quite upset to learn that there are few good tools for measuring them in Python code.  PyLint and PyChecker and the like are not what I’m talking about- I want dependency graphs, measure of cyclomatic complexity, automatic coverage analysis, etc.

So basically what I’m doing is creating a framework that wraps a bunch of existing functionality into an easy-to-use system, and expands or refactors it where necessary.  My goal is to make it a ‘drop in’ system to it will be trivial to get thorough code metrics for your codebase (similar to how simple it is to do in Visual Studio).

Right now I’ve created a SLOC (Source Lines of Code) generater, a wrapper for nose and coverage, and hooked it up to pygenie to measure Cyclomatic Complexity- which is unfortunately going to need a significant refactoring, so I won’t be able to fork it directly.  I’ll be hooking it up into our automated test framework at work this week as well for some battle testing.  I’m 100% sure there’s a good deal of extensibility and configuration adjustments I’ll need to make to support alternative setups.  Next up will be automatic generation of dependency graphs (which doesn’t look easy at all, unfortunately).  And writing tests (this is the first project that I didn’t sort-of-TDD in a while).  Oh, and getting it into Google Code.

Is this something you guys can see hooking into your codebases?  Do you see the value of and want to find out metrics of your codebases?

Oh and it’s tentatively called ‘pynocle’, if you have a better name I’d love to hear it.

4 Comments

The Tech Artist’s Creed

by Rob Galanakis on 26/08/2011

Repost of my most recent from altdevblogaday: http://altdevblogaday.com/2011/08/26/the-tech-artists-creed


Last month we started a thread on tech-artists.org about creating a tech artist’s creed.  After several weeks of back and forth, we finally came up with something we could all agree upon.  Here it is:

I am a Tech Artist,
Every day I will teach, learn, and assist,
And build bridges between teams, people, and ideas.
I will observe without interrupting and mediate without judging.
I may not give exactly what you ask for,
But I will provide what you need.

I am a Tech Artist,
I will approach every problem with mind and ears open
To my colleagues and peers across the industry.
I will solve the problems of today,
Improve the solutions of yesterday,
And design the answers of tomorrow.

I am a Tech Artist,
I am a leader for my team,
And a standard-bearer for my community.
I will do what needs to be done,
I will advocate for what should be done,
And my decisions will be in the best interest of the production.

My goal for the creed was to have the community come up with a code of ethics and standards for tech art in general.  We are a diverse group and there are as many specialties as there are TA’s.  So it was necessary to create something widely applicable, but still meaningful.

My hope is that we can hold ourselves to, and judge our actions against, this creed.  I think it says everything vital about what a tech artist should strive for.  I know I have not always lived up to it, and I want my fellow TA’s to call me out when I do not.  I expect that other tech artists will share that sentiment.  I want to keep pushing our craft forward, bettering ourselves and our community, and I think this creed embodies that.

So, a short post today because so much brain power and effort went into those words above.  They are not mine alone (or even primarily), they are those of the tech-artists.org community which represents and advocates for the tech art community at large.  I am just fortunate enough to have the honor and privilege of posting the creed here, on behalf of an amazing and incredibly creative group of people.

So read it over, tell me what you think, and if you have something to suggest, suggest away- the creed should continually grow and evolve just as our role does.

No Comments

What’s Eating OOP?

by Rob Galanakis on 15/08/2011

Repost from altdevblogaday. Also of note that this was my first blog post that I know of that was reposted on reddit/hackernews, and on reddit especially the comments were sort of brutal… oh, internets. Anyway, I’d suggest heading over the altdevblogaday to read the comments when you’re done with the article.


It has been commonplace over the past few years to bash Object Oriented Programming.  Functional programming going mainstream.  Data oriented design becoming commonplace for performance.  The resurgence of dynamic languages.  OO bastions going multi-paradigm.  Why is everything going wrong for traditional OOP?

Because it took a while but we realized that canonical OOP sucks.  Let’s look at .NET’s humble System.Diagnostics.Process class.

  1. The sin of statefulness.  ProcessStartInfo, the mutable type that represents the filename, args, std io, and other state of the Process, has 20 mutable (get/set) properties.  The Process type itself has over 50 properties (mostly immutable).  The problem here is that the Process itself transitions between three states- not started, running, and finished- and only a subset of properties are valid at any given time.  This whole situation is impossible to reason about- you either need to look at the extensive tests that would need to be written to test all the combinations of state, or you’d need to look at it under the debugger to know what’s going on.
  2. Inheritance.  This situation is bad enough.  But have you ever seen someone subclass Process?  I have, a few times, and it makes things even more impossible to reason about.  You presumably subclass it to ensure certain state is set up by default, such as Filename.  What if someone mutates that default, though?  You either allow it, which makes your class sort of pointless and breaks its invariant (Filename won’t change), or you don’t allow it by raising an Exception, or even worse, just silently returning, which would break the fundamental contract of your base class and the Liskov Substitution Principle (you are quite clearly changing the behavior if you are raising an exception or not fulfilling the contracts the base class makes).  There’s no point to inherit stateful objects like this, but that is canonical OOP.
  3. Code reuse through inheritance/polymorphism.  Obviously code reuse is a good thing.  The problem is the way OOP encourages it, through polymorphism via inheritance.  Process does not implement any interfaces.  You could not pass Process to a method or class that, say, is responsible for managing IO and std streams in general, not just for Process.  Actually, this isn’t a big problem- just either wrap the Process in something (don’t subclass it!), or pass in only the actual data/methods needed.  The ease of getting around this quite clearly demonstrates that, if you were to take away inheritance, it really wouldn’t be such a big deal- would it?
  4. Messy contracts and abstractions.  What are the contracts on Process?  Good luck trying to figure them out by reading the documentation (which is extensive).  I think everyone has put an asynchronous process into a deadlock, even when following MSFT’s directions.  Understanding how to use Process still requires a pretty thorough understanding of the underlying system, and it ends up in a no-man’s land between simplicity and power.  These messy (not just leaky) abstractions are the major problem when consuming other people’s code- I can’t count how many 3rd party modules I’ve seen crashes or problems in, if they have a reasonable enough API to figure out in the first place.

I’m aware I’m picking on Process here.  It is a .NET 1.0 type, and the .NET framework (and programming in general) has matured immeasurably.  I’m sure if the team were to do it again, they would do it quite differently.  Process is a simple thing but obviously technically not easy- look at the dozens of ways Python had to launch a process, until subprocess.POpen simplified things into a wonderfully simple yet powerful way.  But that’s another good point, isn’t it- even Microsoft, who are supposed to be the leaders in these things (they are the ones training people and publishing the guides), ‘get it wrong,’ if it’s even possible to get right (it isn’t).  How is Sammy the Scripter supposed to learn these lessons easily?  He won’t.  It will take him years, and he’s not going to learn it from OOP, he’s going to learn it (like the C# team did) from other languages and concepts.  But this whole time, we’re telling him these fallacies about the wonders of OOP, with inheritance, polymorphism, code reuse, abstraction, patterns, and every other buzzword.

So what are we gonna do?  Well, the first thing is to throw out ideological purity when it comes to OOP.  The language designers are way ahead of us.  Dynamic languages like python and Ruby have long been multi-paradigm.  C# has been making big strides in the area, with anonymous methods/lambdas in 3.5, and even adding dynamic typing support in 4.0.  Java and even C++ are following suit.  On the opposite end of the spectrum, people are also taking hints from Eiffel, the most thorough and pure OO language around, with things like .NET’s Code Contracts.

We’re still lagging behind with education (the education we give at work, not just universities).  We need to expand our toolbox by looking at other languages and other concepts.  We need to throw out much of the traditional OOP approach we’ve taken that hasn’t worked.  (As a commenter pointed out- ideological purity is an aid for new people, but we too often label it as best practices.)  But I also don’t want to throw the baby out with the bathwater and start declaring that OOP is dead, or all around  inferior.  The practical applications of OOP languages (and not necessarily their ideological underpinnings) make them natural for multi-paradigm implementations, and this is something I think it’d be hard to say of procedural, or even functional, languages.

I’d love to see us start to branch out in how we educate and teach to include these non-OO concepts, so we can better use the generally excellent OO languages available.  Let’s take the lack of state from functional programming.  That’s easy enough to do.  Let’s take the modularity and specificity of data oriented design solutions.  Not everything has to fit into some grande, reusable abstraction.  Let’s be honest about the fact that most of our code does a particular thing and isn’t reused.  Let’s take design by contract from Eiffel, and stress how important contracts are for a clear and well abstracted API.  Let’s take duck typing from dynamic languages, so we don’t have to write a new interface to use our code somewhere (interfaces are great, except when you want some small overlap or subset of functionality- look at how even though .Add isn’t part of .NET’s IEnumerable, it gets special treatment by the compiler).  On the other hand, let’s not forget that formal interfaces are important, and make sure we have those (like ABC’s in python).

We have most of these things already, because the language designers are really quite smart people and are way ahead of where the mainstream usage and understanding of these concepts are.  We just need to start using and teaching them more intelligently.  Maybe it is a PR thing?  Stop calling our languages ‘object oriented’ and take the focus off of the ‘4 principles’, and start teaching people how to program effectively using a variety of paradigms.

Likewise, I’d like to see caution when talking about the style-a-la-mode, whether that’s AOP, DOD, FP, whatever, so we don’t start treating it as a golden hammer.  As modern programmers, we live in a complex world, and it is our duty to continually educate ourselves and others using all the information we can find.

 

4 Comments

Optional parameters can be harmful

by Rob Galanakis on 7/08/2011

I’ve come around on optional parameters after being an opponent of adding them to .NET.  They can be very helpful, clean up the code by not needing overloads, and inform the caller what the defaults are.  They are an integral part of python and why it is easy to use.  This is great.

Except when you abuse them.
And you may be abusing them without knowing it.

Parameters should only be optional if a valid default value can be determined by looking only at the contents of the method.

What do I mean?  Well, if your default value is ‘None’, and you call another module to create the actual default value, this is not good practice.  It negatively impacts two important software metrics: it increases coupling by adding a dependency on your module, and it increases cyclomatic complexity by creating an ‘if’ statement.

It is better, in these cases, to just force the user to pass in a valid value.  If you’re jumping through hoops to determine a default value, odds are it is too specific and also breaks the reusability and dependability of the method.  The caller has a higher chance of already having a dependency to what you would be depending on for your default value (any chance is higher than the 0% chance your method has of needing it).  To demonstrate:

def exportFile(filename, branch=None, depotRoot=None):
    if branch is None:
        branch = os.environ['EXPORT_BRANCH']
    if depotRoot is None:
        depotRoot = someScmModule.singleton.depotRoot
    ...

This code is not unusual but it is really difficult to understand and maintain.  The default values determined for branch and depotRoot are entirely outside the logic and goal of the method.

Don’t do stuff like this and you (and especially others!) will have a much easier time maintaining and supporting code.

No Comments

Bored People Quit (I did!)

by Rob Galanakis on 4/08/2011

If you read one long blog article this year, make it this one: Rands in Repose’s Bored People Quit.  It is one of the most important blog posts I’ve read in a long time, and right on the money.

If you’ve ever worked a shitty professional job (especially programming), and you know you have, you’ll resonate with what’s written there.  I told my last job for well over a year that I was bored and actually tried to quit a number of times, and gave exact action items for how to fix my boredom and what my grievances were.  Not that any were ever addressed.  And in a place like that, they couldn’t realistically be addressed, with so much riding on such an expensive project- they couldn’t give a shit about almost any individual worker or what I perceive as the long term health of the studio.

Anyway, go read it, and pass it on to your managers!

No Comments

The Open Source community can be mean

by Rob Galanakis on 2/08/2011

I’ve talked a bit about my problems with OSS as an outsider.  Martijn Faassen wrote a great post about his problems with it from the inside: How to Handle Ideas.  It’s an informative, lucid post about improving the ways the open source community receives ideas and criticisms, written by an insider.

Even outside of the open source community, it is useful to read and remember his advice and ideas, as they’re useful ways to handle incoming suggestions and criticisms for any internal project you work on.

No Comments

You will create a brave new world

by Rob Galanakis on 1/08/2011

Ian Cooper, one of the contributing authors at CodeBetter.com, recently wrote an article called ‘Why CRUD might be what they want, but may not be what they need‘.  While this applies mostly to the world of applications, I’ve been saying the same things about tools and pipeline for a while now.  The basic argument goes, the people designing/requesting our apps have a history and understanding of the process, and when we build new systems, they ask for optimized versions of that same process.  But there are very likely ways we can rethink that legacy process in the context of much better technology and software, and change the experience profoundly for the better.  It is our job, as the people who sit between technology and content development, to do that.

And the good news, as always, is that if we fuck up, no one dies.

Go ahead and read the article and see what I mean.

No Comments