Pages

Showing posts with label Philosophy. Show all posts
Showing posts with label Philosophy. Show all posts

28 September 2011

How to Be Productive

Blindingly Obvious Truths

This is how to be productive. Most of these things are absurdly, staggeringly obvious. That’s kinda my style. Anyway, since not very many of us are the kind that get shit done, we apparently need to be reminded every once in a while. Pin this to your wall—pin it to all of your walls—and look at it to give yourself a mental kick in the ass when you know you should be working.

Get out of bed.

If, like me, you have delayed sleep phase syndrome, then fix it. If it’s hard to get up when the sun comes up, then your sleep schedule is probably not healthy, and it is negatively affecting your productivity. We are a diurnal species. Deal with it.

Be healthy.

It ought to go without saying that you need good diet and exercise habits to be healthy. What you may not realise is that health is happiness, and for many of us, happiness is productivity. (I can’t say all, because surely there are some dark tormented programmers out there whose work is fueled by the darkness and torment in their dark tormented souls of tormentful darkfulness. Or something.)

For instance, when my blood sugar is low, I hate the world—then I eat a sandwich and everything’s fine. If you feel like hell all the time, your body is probably trying to tell you something. Sleep right, eat well, exercise occasionally, spend time with friends, find a mate, and mate with them often.

Work on one thing.

Multitasking is doing many things at once—badly. Innumerable studies have shown that multitaskers are just fooling themselves into believing they’re improving their productivity. You can be a true “jack of all trades” if you work on one thing at a time. Don’t distract yourself from what you’re working on with thoughts of what you’re not working on. It’s an endless cycle of self-subversion that can only be broken with focus.

If I want to write a blarticle, I just do it. If I need to do homework, I just—well, okay, first I complain a lot, but then I just do it. I didn’t post a vlog entry for months, and then I said “no, this will not do” and made something. It was shitty. It doesn’t matter. I did it.

Work till you’re done.

Have a project that needs finishing? Don’t waste your valuable time making small changes. Get your hands dirty and implement that feature you want. No one else is going to do it, and you have the time. It probably won’t even be as hard as you think. If it seems guaranteed to be difficult, you might be fixating on a difficult solution when there is a much simpler one. Reflect.

When you’re done, stop.

You must take time to relax and play. If you work hard, you earn the right to relax hard. You will feel the profound satisfaction that comes from creating something through your own focused efforts, and your sleep will be easy and deep.

Now go, and do.

27 September 2011

Simulation is Abstraction is Power

A more abstract programming language is more powerful. This is one of precious few things that most software developers agree on. C is more powerful than assembly, C++ is more powerful than C, and Lisp is more powerful than most developers realise—or will ever take advantage of. And that’s fine.

But whence cometh abstraction? Sure, you can say that all abstractions are generalisations of some category of operations or structures, but that’s shallow and basically useless. There’s more to it.

Abstraction comes from simulation. Computers run simulations of idealised computation; more abstract languages are better at simulating the ideal. Low-level languages deal with real hardware, while high-level languages simulate ideal hardware. A few examples:

  • References simulate unstructured memory.
  • Garbage collection simulates unbounded memory.
  • Dynamic typing simulates lack of typing.
  • Threads simulate parallel execution.
  • Tail recursion simulates unbounded recursion.

(Depending on how far you want to go with the analogy, recursion simulates a whole bunch of things, including self-reference, fractal structure, and induction.)

Simulation is about removing dependency. A program can depend on manual memory management, but it cannot, by definition, depend on garbage collection. With memory management fully abstracted away, memory management ought to be a nonexistent concept from the perspective of the language.

Your program probably pretends it has infinite memory anyway. Provided your program doesn’t crash, the system does have unbounded memory as far as you know. Most programs that are working properly don’t run out of memory unless they’re deliberately designed to, for lack of a better phrase, fuck shit up.

Similarly, as we all know, threads may actually run on separate cores, and thus truly in parallel—that’s sorta the point. But the thing about a language that offers powerful abstractions for parallelism is that you don’t need to care. It’s taken care of. As far as you need to know, the system can perform an infinite number of computations at once.

Abstractions are (imperfect) simulations of limitlessness. As a language designer, you can (and should) offer pragmatic limitations and safeguards for the benefit of the fallible developer. But to make a more powerful language, you must remove limitations. When you do so, you discover the nature of the underlying simulation—and simulation is abstraction is power.

22 September 2011

Tricky Programming Concepts Aren’t

What Teachers do Wrong

Teachers use subversive language. They say things like “this is a bit tricky” before introducing a concept. It’s intended to remind you to pay attention, but mostly it turns students off—it says “this is hard; I don’t expect you to understand it”.

Frankly, that’s bullshit, and it has appeared—and caused problems—in nearly every class I’ve ever taken. It’s especially visible in mathematics and the sciences, but foreign language, social studies, literature, and even drafting are not immune.

The fine arts, notably, do avoid it: it’s not conceptually difficult to improve your process and observational skills—and no art teacher I’ve ever encountered pretends it will be anything other than hard work and dedication. (Paul Graham got this one right: hacking and painting are very similar.)

I may have an irresponsibly intertwingled worldview, but it seems to me that most things are not conceptually difficult. At all. Even the most high-level concept, explained correctly, can be absorbed and applied by any person of average intelligence. The important thing is the explanation.

Learning should not be about overcoming difficult ideas: it should be about realising how simple those ideas actually are.

I think the main reason that fine art instruction is effective is that, when a student says “I can’t draw/paint/compose/&c.”, the teacher’s natural response is to say “you can—you must; just practice”.

And they do, and they get better. Most people are not going to become master painters or composers, of course, for the same reason that most people won’t become masters of anything. But perhaps more of the people who are capable of mastery would strive for it if we used encouraging, practical teaching methods like we know we ought to.

♦ ♦ ♦

What Programming is About

Programming is fundamentally about doing three things with a problem:

  • Discovery
    First, know what problem you need to solve. Finding interesting problems is half the fun of research. If you don’t mind solving uninteresting problems, you probably aren’t a very interesting programmer, or even very interested in programming.
  • Understanding
    Once you know the problem, you need to understand it deeply. You need to understand its subproblems, and their subproblems, all the way down to the units that make up your problem domain. (This is recursion.)
  • Expression
    When you understand the problem, you can express it. This is not just writing the code you designed earlier, as some “software engineering” evangelists will have you believe. Expression itself contains discovery and understanding, which leads to further expression. (This is tail-recursion. It’s also why the “waterfall” method is flawed.)

This is exactly like the process of essay writing: you discover your thesis, engage in research to understand your topic, then begin the process of expressing yourself in a logically connected essay. While figuring out your expression, you discover and understand further details and incorporate them into further expression.

An essay is ideally just a proof of a thesis; similarly, a program is ideally a solution to an intellectual problem. Both have practical effects in the real world, and at the heart of it, they really are the same thing.


♦ ♦ ♦

“Tricky” Programming Concepts

Two things are consistently taught in such a way that beginning programmers fail to properly understand them. Things that are so stunningly simple and pervasive that it’s baffling that anyone could fail to understand them.

I’m talking of course about pointers and recursion.

What baffles me is how people seem to be so inclined to analogy when the vast majority of programming concepts are stupendously literal.

A pointer points. A reference refers. These are the same thing.

(Don’t the C++ folks in the audience give me any crap about C++ references. They’re not magic, they’re non-nullable immutable pointers—just another reference type.)

The address of a thing is not the thing itself, but it is good enough (and often, in fact, better). I can steal anything in your house, break your windows, burn it down, and all I need to know is where your house is. I can use the words “burn your house down”, and even though I have not actually burnt your house down, you know exactly what I’m referring to.

Reference is a fucking pillar of language. I say “fucking” because it’s fucking important. We use finite-sized symbols to refer to concrete objects and abstract concepts alike, and it takes no more cognitive effort to say the word “apple” than it does to say the word “universe”. (Referring to something is a constant-time operation.)

Most people have no trouble understanding the concept of reference, of course—but then they fail to see why it’s important, least of all in programming. But again, you don’t even need analogies here—the explanations are comically, tautologically simple:

  • A linked list is a list of things that are linked.
  • A tree is a hierarchy of things that are linked.
  • A queue is a queue of things.
  • A stack is a stack of things.

If someone doesn’t understand these things, they’re probably trying too hard. To implement a linked list, just open your eyes and think about what the term means: it is a list, and at each place there must be a thing, and the address of the next thing if there is one.

That’s all.

Recursion is even more important to programming, even less understood by beginners, and yet even more visible in daily life. If you remember one thing, remember this:

References are for referencing, and recursion is for self-referencing.

A mind-squishingly huge number of natural things have fractal structure, from clouds to mountains to plants to coastlines to trees. A branch of a tree looks just like a whole tree, only smaller. Because of this, doing stuff to part of a tree is basically like doing stuff to a whole tree.

You can thus write instructions for doing stuff to entire trees very concisely: to snuggle a whole tree, first snuggle the base of the tree, then snuggle each branch as though it were a whole tree.

This works in less silly examples as well: to sort people by height, pick one, move all the shorter people to his left, and all the taller people to his right, then sort each side. Bam. You’ve just invented quicksort.

♦ ♦ ♦

Don’t Be Fooled

So I think Joel Spolsky got it severely, totally, irresponsibly wrong in his article The Perils of JavaSchools, wherein he basically claims that understanding pointers and recursion is an aptitude, not a skill.

Not only is it the same kind of subversive language that teachers mistakenly use, it betrays a deeply mistaken belief that the concepts of pointers and recursion are somehow inherently difficult.

They are not.

If you think all I’m saying is “programming is not as hard as people make it out to be”, then you’ve missed the point. Programming is hard, like writing and design, because it is intimately related to both. It’s just that the basics of programming are no harder than the basics of any other kind of design.

Pointers and recursion are among the most basic things in the world. The real world, the one in which we live—and that’s why they show up in computing in the first place.

♦ ♦ ♦

My sincerest thanks to all of the kind folks at Hacker News (and now /r/programming!) for reading, upvoting, commenting, and +1ing. Your many praises and criticisms are deeply appreciated, for giving me the motivation and humility to write even better content in the future.

05 September 2011

Turing Completeness is not Practical Completeness


As a discussion comparing the relative merits of different programming languages grows longer, the probability of an appeal to Turing completeness as a measure of linguistic equivalence approaches 1. It's practically Godwin's law of programming languages.

Appealing as it is, the notion that whatever is possible in one language is possible in all is simply untrue. Turing completeness refers merely to the ability to implement any computable function. There are plenty of esoteric languages that have no or very limited I/O, and plenty of non-esoteric languages that have little to no ability to interface with libraries and other languages.

The fact that languages do differ in their strengths and weaknesses is precisely the main reason we use different languages at all. Different tools are best suited to different situations. The next time someone commits this fallacy, point them to the concept of the Turing tarpit, and if further investigation doesn't prove to them that theoretical equivalence is not the same as practical equivalence, invite them to implement a simple algorithm such as CRC32 in Brainfuck.

29 July 2011

Oxymoronic: Computer Science & Software Engineering

I think I'll kill two birds with this stone. At RIT, there are two main computing majors: Computer Science and Software Engineering. Both of these are misnomers.

See, Computer Science is concerned primarily with programming as it relates to computing theory. Programming, while certainly related to the design of (reasonably) precise things, is by no means scientific. Science is systematic, rigorous, testable, and predictable. Computer hardware and software alike operate under the illusion of determinism and reliability for the sake of pragmatism alone.

Further, computing theory is only related to computing insofar as programmers actually implement the mathematical ideas of the theorists. Research is valueless without eventual application.

Software Engineering, on the other hand, is concerned with programming in the context of project management. It asks what the process is (or ought to be) for creating software in teams of people according to business requirements. Software engineers also operate under an illusion of determinism and reliability, but their misplaced faith is not in computers—instead their money is on programmers. The fool and his money have parted.

So computers are fallible, and programmers are fallible, and it's a wonder any of us ever gets anything done at all. The best programmers know the secret of how things are really done in the software world: communication.

I don't mean meetings, or agile (or worse, Agile), or documentation, or any of dozens of other borderline buzzwords that a manager might throw around. No, I mean the plain and simple fact that programming is writing, and programmers have the unique task among authors of writing in such a way that both computers and humans can readily parse and evaluate their work.

Of course, any fool can write for one or the other. If I write an informal description of an algorithm on paper, it's perfectly human-readable; if I write a formal implementation of an algorithm in heavily optimised machine code, then it's perfectly computer-readable.

And this is why I hate the word code. If you call it “coding” for a computer, then the quality of your writing from a human perspective is probably utter trash. Don't get me wrong, of course: for a first draft, utter trash is perfectly acceptable provided it can still convey the intended meaning.

But for a final draft, a certain amount of editing is necessary. Programmers differs from writing in another key aspect: though neither a program nor a work of prose is ever truly complete (final draft is an oxymoron as well), you must release both sometime; the difference is that a program, like a work of nonfiction, can be updated in editions to maintain freshness and currency.

Programming is like creating a diamond from scratch. When you code, you make the stone. You may then polish what's there and cut what shouldn't be, but both the colour and the clarity of that stone are immutable. No amount of refactoring will fix an idea that was poorly styled or unclear from the outset.

In conclusion, I might add that I insist that programming is not art. I believe this simply because I'm not good at art, but I am good at programming. I'm also good at design and craft, and that's what I believe programming is.

Programming is writing for one audience who seemingly doesn't understand you but is also endlessly critical, and simultaneously for another who seemingly understands you but is also painfully literal. It is writing manuals and dictionaries and phrasebooks to help these two disparate audiences communicate. It's logical, illogical, philological, analogical, anthropological, and frequently epistemological.

I fucking love it.

On Brilliance

You are brilliant, but you don't know that the following things are true:

  • Your work is meaningless until proven meaningful; don't complain, work.
  • You do not have to be an insufferable asshole; you probably will anyway.
  • You are not better because you are smarter; you are worse for believing you are.
  • The world is not a meritocracy; your sense of entitlement is undeserved.
  • Intelligence is not a skill; you have to be able to do something.
  • The truth is not self-evident; you do have to explain.
  • You can't stop people from sticking beans up their nose; it won't stop you from trying.
  • You are a fool; wisdom comes only from knowing the depth of your own folly.

03 October 2010

A Walk in the Woods

When I need to get some really good thinking done, I've learned that there's nothing better for me than to relax and avoid thinking at all for a while. My brain is so glad for the brief holiday that it returns to work with renewed vigour, and accomplishes things as though it was working diligently the whole time I wasn't communicating with it.

There are few places where I can really get into this state—the shower is one that I have in common with many others, but a shower can reasonably be only so long for a number of reasons. Another good place is graveyards: the dead tend to be pretty accommodating hosts when it comes to quiet thinkers.

But I think the best place for me is the woods. Going for a long walk in the woods, trying in vain to confound my irritatingly accurate sense of direction, and getting some exercise are all great things, but they're even better when I get to go for a walk with the deer.

Yes, you read that right. The area around RIT is swarming with deer. On a recent late-night walk, I saw no fewer than a dozen by the side of the road, and that's no exaggeration. So it came as little surprise to me this evening when I ran into a couple of does in the forest.

Now, RIT deer are fairly docile. You'll never get them to eat out of your hand, but they won't spook if you're reasonably nice to them. Usually announcing your presence in a soothing voice and talking to them occasionally is enough to dispel their fears and let you get as close as five feet from them. One was still young and the other fully grown, and the fawn was noticeably more skittish than the adult, so kept her distance more.

I was able to walk with them for quite some time before they decided it'd be a good idea to cross a stream, and, clad in sneakers as I was, I wasn't prepared to slog through ankle-deep mud and knee-deep water. So I made my way through the dry part of the swamp to a hillock where I read Dracula and watched the sunset.

Why am I telling you all of this? What does this have to do with programming or linguistics? Not much, really, but it is kinda nice, and people like stuff like that. And anyway, it got me thinking about the universality of expression, which is something we humans seem to not just take for granted, but often entirely ignore. An animal can understand your intent and your emotions even if it can't grasp the meaning behind what you're saying. Hell, a human can, too; we're not immune. Tone of voice and body language are enormously important, and yet we seem to always get lost in the intricacies of verbalisation.

We should probably just relax and eat some acorns.