Sunday, November 30, 2014

Mathematical Properties and Programming

In school part of the maths education involved memorizing the definitions for words like “commutative” or “transitive”.  I always did terrible with those memorizations [1], however I’m pretty sure the cause behind my performance was a lack of context.  Trying to investigate maths on my own, I reencountered these words.  My first thought was something along the lines of, “hey these are those words I always missed points on with exams.”  However, I wanted to understand certain maths [2], so I trudged on.  I’m rather glad I did because an important realization struck me once I had finally memorized enough of these definitions:  If you create a programming construct [3] that does not obey a property that it should intuitively have, then when you (or someone else) uses the construct in the intuitive fashion it may malfunction in surprising or hidden ways.

The example that first comes to mind is floating point numbers in most programming languages.  Typically we imagine addition to be associative.  That is to say that a + (b + c) is equal to (a + b) + c.  However, this is not necessarily true for the floating point representation of a number [4].  The effect is that apparently valid looking code that uses floating point numbers may be incorrect, and apparently innocent looking code changes to code that uses floating point numbers may result in correct code becoming invalid.

Of course this doesn’t just apply to programming constructs that are baked into your programming language as a base feature.  It also applies to pretty much any class, object, inheritance chain, function definition, etc that you might end up creating in order to accomplish your goal. 

So far I’ve compiled a list of properties that look like that are important to keep in mind when you’re implementing solutions:

Equality Relation (reflexive + symmetric + transitive)
Partial Order (reflexive + antisymmetric + transitive)
Unary / Binary Idempotence 
Continuous (in the topological sense)
Monotonic (in the domain theory sense)
Continuous (in the domain theory sense)
Sound (in the type theory sense)
Referential Transparency

Not all of these properties are going to be required (or even a good idea) for every construct you come up with.  But when you’re using a construct like it has one of these properties it better have that property.

[1] - Actually I tend to *do* terrible with all memorizations, but that’s a different story.
[2] - Type theory and category theory (mostly because of Haskell).
[3] - It’s so much worse than just programming constructs though.  It also applies to reasoned arguments, personal philosophies, business procedures, school policies, and the list goes on.

Saturday, November 1, 2014

Competency categories

In my previous post [1] I mentioned wanting to have a better idea of how people think different.  I initially started down this road because neither of the descriptions for extrovert or introvert really seemed to describe me very well.  Different people seem to explain the way these personality types are different in different ways, but none of them really stuck when I tried to apply them to myself.  Well, that's okay because no one is really 100% introvert or 100% extrovert, except for *weird* people, most fit someplace in the middle.  But that's just the thing.  I don't feel  like I'm in the middle of extrovert and introvert.  And I don't seem to be on one extreme or the other.  I feel that I tend towards the extremes of both.  Instead of the introvert/extrovert scale being a line with two opposite ends, it feels more like maybe it's a circle where being "in the middle" might also mean being diametrically opposed to yourself.

My secondary foray into people being different occurred because I noticed some anomalies with my software development career, and the way I approach playing certain games is a bit peculiar.  

Concerning software development, I've noticed that there are certain people who I work shockingly well with, but terribly bad for.  There's a significant distinction here.  Working with someone suggests a collaborative process where each person covers the shortcomings of the other and working for indicates someone proclaiming and verifying goals with someone else doing the actual work.  Okay quick digression into games.

I've noticed that I really like to build decks in the card game Magic the Gathering [2].  Additionally, my actual strategies during play are entirely decided ahead of time during deck construction.  The actual play time strategy could be considered greedy.  Play all land, summon as many creatures as you can, attack as much as you can.  Maybe some finer points if some additional information is present or if there's a social element at play in a >2 player game, but basically a python script could do about the same thing.

Additionally, my ability to make any progress with RTS games like Supreme Commander [3] just isn't that up to scratch.  My ability to deal with keeping resources sane while also adapting to a dynamically changing battle field really isn't that good.  Although on the other hand analysis ahead of time concerning what units have good strategic value is something I can actually do.

So what's the deal?  My thought was that maybe there's two ways people can think.  Or deal with situations might be a better way of saying it.  There's observation and there's actualization.  Additionally, with these two modes there's a spectrum for each ranging from analysis to action.  In this system I would be a heavily leaning action person in the actualization mode and someplace in the middle for the observation mode (but closer to analysis).  The theory is that when actually playing the game my actions are primitive, but ahead or after observation allows more strategy.  To be better at an RTS, you would expect someone's actualization to be more balanced.

Back to software development.  If I'm working with someone who has a balanced actualization mode of thinking and an observation mode that is skewed towards action, then I can give up any actualization on my own and focus completely on observation.  The only actions I have to perform are simple social prods that keep development going in a direction that I've already worked out is viable.  They don't have to worry about category theory and I don't have to worry about implementing certain things I find frustrating. 

This would also explain why I don't work "for" these sorts of people very well.  My actions aren't nearly as graceful as they would prefer and meanwhile I don't like it that they can't actually explain what they want done and instead focus on how I didn't do what they imagined.

Now my most recent approach to this problem is what I indicated in my previous post combined with the actualization vs observation thing.  Instead of having a spectrum for actualization and observation you substitute in cognitive complexity classes [4].  So maybe the best actualization you can handle is a certain level of complexity and the best observation you can handle is on a different level of complexity.  This sort of thing seems to explain how there are very clever people who don't appreciate how clever they are (they tend to have a hard time understanding how people aren't as clever as they are) and get into trouble when their reach exceeds their grasp.  In other words if you can handle very high complexity for actualization you can accomplish very cool things (like writing operating systems or graphic renderers effortlessly).  Although if you can't handle very high complexity for observation maybe you don't have an appreciation of how hard the thing you're doing is or maybe your theoretical grasp on the whole thing is suspect (the cowboy coder whose codebase is a horrifying collection of hacks, but it somehow works nearly all of the time).

Unfortunately, I'm pretty sure right now that cognitive complexity classes don't yield a convincing or coherent picture when merged with observation vs actualization.  Too many things aren't falling into place when it looks like they should and there's also a bunch of things it doesn't explain.

It seems kind of like being competent at something means you can handle high complexity.  And then the categories of things you can be competent in is this huge set of things that's interrelated in weird ways.  So for example, macros, very higher order functions [5], and type theory are all things that don't bother me.  However, for loops and if statements not so much.  Judo, walking on uneven terrain, and public speaking:  yes.  Parties, interactive self expression, and relationships:  no.

A lot of this stuff sounds kind of good, but it seems sort of like the situation is a lot more complicated than being able to divide the world into halves again and again.  So instead of nice points on a coordinate plane or vectors or whatever, we end up with a messy graph that describes each person, each weight being another messy graph.  At the very least handling complexity and competence look vaguely related, so maybe I'll think in that direction for a while.

[1] -
[2] -
[3] -
[4] -
[5] - Functions taking functions that take functions that return functions that return functions.