Hacker News new | ask | show | jobs
by ndarilek 2783 days ago
Hey, kudos to you for thinking about this! Background: I'm totally blind, have programmed for nearly 3 decades, kind of do the in and out of half a dozen languages thing these days. Today's favorites are Rust anywhere I can get away with it, Python because it runs in places where I need it (Home Assistant, Mycroft, etc.) and JavaScript because if I hold my nose and don't think too much about the atrocities I'm committing, I can run the same or similar code in various form factors. I'll try to give a few pointers. Note that these are specific to blindness, and specific to me. I don't claim to speak for the disabled population as a whole, as we're kind of a grab bag.

1. Indentation: Pretty much a solved problem at this point. If I were reading Python code line-by-line, my editor might speak something like (not sure if my newlines will make it, but imagine them where they should be): def hello(world): 4 spaces print("Hello, world.") 4 spaces 1 tab 4 spaces print("What was I thinking when I indented this line?")

So I wouldn't worry too much about that. I've never had issues with an indentation-based language, and anyone blind who does likely just needs to change their tooling a bit. This is usually just a checkbox in the screen reader settings, so doesn't even usually require an editor/IDE change.

2. Avoid crazy symbols. Scala gave me some grief with this, with every library author having method names like %^&@^$# because I assume that set of symbols looks like performHttpRequest(...) in some visual way. I exaggerate a bit. Only a bit. Note that operator overloading is fine, at least from an accessibility perspective. It's when people decide that a series of connected punctuation symbols evokes the idea of making an HTTP request or opening an Option that I start to get annoyed.

3. Create good command line tooling. Rust has this nailed. I like how Rust's own installer just uses rustup under the hood, or at least I think it does, and every blog post advertising a new component also includes the rustup incantations to grab it. I assume the editor interfaces are as nice or nearly so. I guess the takeaway is, package your language installation tooling in a library so you can invoke it from the CLI, editor plugins, etc.

4. Put error messages at the bottom of stacktraces rather than the top. Python does this right, and everyone else gets it wrong[1]. Say you're running a compiler from your command line. You get an error, and your cursor lands on the input area, ready for a new command. As a screen reader user, you discover that error by entering your window's review mode and moving up. With JavaScript, Rust, and just about everything else, I have to arrow through the callstack in reverse as I move up the screen to the line containing the error. Python puts this error last, near the input cursor, so all you're doing is arrowing up a couple lines. It's a few seconds per error, but can add up immensely over the course of a day. NPM, infuriatingly, shows the error, followed by disclaimer text that the error isn't in NPM, then barfs up an NPM error just to confuse things. So any JS package I use that uses NPM for its scripting requires arrowing back through 2 stacktraces to find the original error. It's enough to drive me to drink.

I can probably come up with more, but I haven't finished my coffee yet. Perhaps that's a good thing...

1. Right and wrong are of course subjective. This is just one blind dude's opinion, take it for what it's worth.

3 comments

Are Unicode characters a problem for the tools you use?

For example, some languages will let you use λ instead of lambda. Or when trying to define the logistic function, I sometimes find myself writing

  σ(x) = 1.0 / (1.0 * exp(-x))
Or the Julia language has ≈, which tests if two floating point numbers are approximately equal. Visually, this is a reasonable symbol, it's not like one of the weird functional programming spaceship operators. But I have no idea what a screen reader would read.

Sometimes this sort of thing lets code correspond almost exactly to the notation in papers. It is a minor aesthetic improvement, but if it breaks screen readers and other tools I'd rather just write out "sigma" or "lambda".

My screen reader, Orca under Linux, read those as "sigma" and "almost equal to." So I suppose those work, though I'd have to hit Google to find out how to type them. :)
The NVDA screen reader for Windows also reads these symbols. So it looks like they're not a problem.
In Julia editors these are written by e.g. typing `\sigma` with a backslash and using tab completion.
Thanks for the response, that is pleasantly surprising default behavior.
Thanks so much for your response! #4 in particular is something I hadn’t considered, except in the context of how to display error messages in an editor, but now it seems obvious that the most relevant information should be closest to your focus.

As for #3, my compiler is intended to be all-in-one: there’s a single executable that acts as a front-end for an internal library, which handles everything: compilation, syntax highlighting, dependency management, documentation generation, you name it. So all the language tooling should just work in a consistent way.

Do you use a Python auto-formatter called black, or if not, do you think consistency helps (e.g. shorter lines, same constructs/indentation) or hinders (e.g. shoter lines means more lines means more noise)?
Haven't thought much about line length. I tend to write longer lines just because I don't see the point on the screen where they'd logically break, and when I'm arrowing through code, I generally prefer to hear as much of a construct as possible without having to arrow 4-5 times through a single statement. If I'm calling something on a long list or string then I might break the list out over several lines, but if I'm dealing with a single long function call then I just let it go long. Formatters are certainly fine, it's just annoying to find and configure them for each language I use.