+++*

Symbolic Forest

A homage to loading screens.

Blog : Post Category : Geekery : Page 3

Middle earth

Or, a trip on a steam train

A while ago—I can’t find the exact post—I set myself a target of having more posts on here filed under Trains than I do under Political. I think I even said the target I was giving myself was by the end of last year. Well, I’m still clearly a long way off that at the time of writing (58 versus 113) but this is an attempt to make amends. Right at the start of the year, you see, I went out for a trip on the Middleton Railway.

Happy New Year on the Middleton Railway

The Middleton Railway is quite an interesting little line, for its history if nothing else. There are various claimants to the title of “oldest working railway” in various parts of the UK, partly dependent on what counts as a railway and what doesn’t. If you insist steam trains have to be involved, then various branch lines around Darlington usually get the prize, as they opened in 1825 with a mixture of steam trains and horses. If you’re happy with horse-drawn trains, the stretch of the Ebbw Vale line between Rhisga and Pye Corner opened in about 1805. Both of these are lines that carry passengers in main line trains today. If you’re happy with railways that are just for freight, there’s a branch line near Dunfermline that might have had trains on it in the 1760s, although its early history is a little unclear. The Middleton Railway, by contrast, has a definite starting date, as the first railway to be authorised by Parliament, in 1758, during the reign of George II. Moreover, and something that is unusual for a volunteer-run heritage railway, it has operated continuously ever since, switching from commercial to volunteer operations in 1960.*

Of course,** none of the railways I’ve listed above really resemble their original form and the Middleton is no exception to this. In the 19th century it ran from Great Wilson St—roughly where the Crown Point branch of Pets At Home is now—and ran down to, naturally, Middleton. The furthest-south point I’ve found on a map was “Bleachground Engines”, on the 1854 six-inch map, nowadays at the very south end of Middleton where Middleton Park Avenue meets the A654. As the crow flies, it’s a distance of about 3.5 miles. The current Middleton Railway runs for about a mile, from Moor Road to the northern edge of Middleton Park. Moreover, the landscape it runs through has changed entirely, the coal mines it was built for all turned into post-industrial green spaces.

Park Halt

Being built purely as an industrial railway, the Middleton didn’t carry passengers at all until its heritage days. The first passenger trains were run using a hired diesel pulling a second-hand Swansea and Mumbles tramcar.*** Later, they needed proper carriages. Those in the picture are the underframes of old 4-wheeled parcels vans, which the Middleton has rebuilt with completely new bodies to give themselves a passenger rake.

The sheds

Behind the scenes, the Middleton has an awful lot crammed onto a very small site, with their workshops packed full of stuff under restoration. I can imagine shunting things to the right place in the workshop is a bit of a pain. If they didn’t specialise in small ex-industrial locos, they’d hardly have room for any. As it is, everything is jammed in rather tightly, with just enough room inside for people to move around them and actually do the work. I have an old friend who works at the Middleton; he managed to arrange for the both of us to have a little tour behind the scenes, and see the locos under repair, those undergoing major restoration, and the next carriage the railway has started to build.

Inside the workshop

Spare loco in the shed

Running round

We had a few round trips, too, shuttling back and forth along the mile of track. The Middleton Railway might be very different to its original intention, and might run now for a slightly different purpose. It’s still a fascinating place to come and visit, and was an excellent way to start the new year.

Inside the museum building

No public access

Wreathed in steam

* The only other heritage railway that can really claim this is the Talyllyn, which opened in the 1860s. The Ffestiniog has never quite closed, having leased out a short stretch of its track for former customers to use, but their claim is a wee bit of a stretch.

** And unlike the railways in the first footnote.

*** Another early railway: the Swansea and Mumbles, also known as the Oystermouth Railway, was carrying horse-drawn passengers from the first decade of the 19th century. It later essentially became a tram line, and closed just before the Middleton became volunteer-run. If you’ve ever visited the Gower, you have likely travelled by car along part of its route. The tramcar which moved to Leeds was sadly destroyed by arson.

Too tired for meteors

On not seeing the Quadrantids

If you’re into astronomy—or if you were reading this blog this time last year—you might remember that the first week in January is home to one of the big annual meteor showers, the Quadrantids. I still keep meaning to write a blog post about Quadrans Muralis and other forgotten constellations, and I’m sure I will do at some point. Anyway, as I was saying, last night was the Quadrantids’ peak night.

I went outside at 7 or so for an evening walk, and the sky was beautifully clear, with what felt like it would be excellent seeing. Unfortunately, it was also bloody freezing, with a strong wind blowing, and I was exhausted from my first day back at my desk after the long Christmas break. So, an early night, and no Quadrantids for me.

About half two I woke from bad dreams, and considered getting dressed, dragging a garden chair out and going outside. I could hear the wind blowing gustily, though, and howling around the gutters. Moreover, I’d already worked out that the radiant, here, would be in the direction of the worst street-lights in any case. “Maybe not tonight,” I thought, and turned over and tried to get back to sleep.

There will still potentially be meteors to see tonight, of course, and if the seeing is good again I’ll at least consider taking myself outside. I might have to dig out my warmest clothes and put them to one side first, though.

Teaching an image to think

Computers work in unexpected ways

Following on from yesterday’s post about log4j: another security article fascinated me in the last week, too. You might have already seen it, because it was widely shared on Twitter and computer people everywhere were amazed and aghast at its engineering and its possibilities. The log4j vulnerability is a relatively pedestrian one by comparison, using something that is an entirely documented and public feature of the library. This, on the other hand, is a completely different animal.

It’s a hack which lets you run code on a stranger’s iPhone just by sending them a message. They don’t have to click on anything, they don’t even have to open it, all their phone has to do is receive it and the hacker can take their phone over. At least, could: the fix for this security hole was fixed three months ago in iOS 14.8 and later. If you are running an older version of iOS on your phone or tablet, then, er, maybe don’t. The analysis of how this hack works, by Google Project Zero, has started to be published; and if you’re a programming nerd, it is beautiful and amazing and horrific in just the same way that a biological virus is.

In short, this hack relied on the fact that an iOS device, when it receives an animated GIF, tries to hack the GIF a little so it will always loop forever whatever the GIF itself actually says to do. It does this in an unhealthy way, though. When it opens the file to change it, it doesn’t matter if it’s not actually a GIF. The software will try to be clever and say “ah, looks like your file’s got the wrong name there, don’t worry, I still know how to open one of these” and do it. Even if it’s not a GIF and therefore doesn’t really need to.

Secondly, the hack relies on a bug in an open source PDF-reading library, in the part of the code used to open embedded images that are in an obscure and rather out-of-date format mostly used by fax machines. PDF is a big, complex and rambly format (believe me I know, I’ve been on-off trying to write a .NET PDF writing library for some years now) so it’s not surprising there are bugs and holes in PDF-reading software. What this hack does, though, is frankly brilliant. It uses the capabilities of the compression algorithm of this particular graphics format to implement an entire virtual CPU in the memory of the target device. It’s a small CPU but it is a Turing-complete one, which in technical terms mean that if you ignore practical limits of time and memory, it’s just as powerful as any other computer. An entire virtual CPU…created by feeding a carefully-designed image into a buggy image decompression routine.*

Frankly, if you’re a software developer, this is genius. Evil genius, to be sure, but genius nonetheless. I’m somewhat in awe of it, in a dirty way. It’s a wonderful level of lateral thinking, to know that the bug is there to exploit and work out a way to reach it and trip it up to begin with; and then to build an entire virtual machine from the basic Boolean logic operations available inside a particular image format. As I said above, it’s beautiful, it’s amazing, and it’s horrific in the original sense of the word. It’s awe-inspiring. I might be good at my job, but I can only look upon this with amazement and envy.

* I assume the image itself looks like just so much white noise if you could actually view it, but you can’t have everything. It reminds me a little of Neal Stephenson’s early-90s novel Snow Crash, in which a carefully-designed image that looks like white noise can hack the viewer’s brain.

Some logical relief

In which we discuss a topical flaw

In many ways I lead a charmed life and hold a wide range of privileges in my hand. Not least, this week just gone, the fact that I’m a software developer who generally works with the .NET software stack. More specifically, I am not a software developer who works with Java. Java developers have not, generally speaking, been having a good week.

This is all because of a software vulnerability discovered just over a week ago in a Java library called “log4j”. To summarise, for non-experts: “log4j” is a logging library. No, not the let’s-clear-the-rainforests sort. “Logging” means your software writing diagnostic information as it goes along: records such as “user etoainshrdlu asked to see their bank balance at 9.10am from this address with that web browser”. You can see why…

Regular reader E Shrdlu (from Clacton) writes: Oi! You can’t go around giving my bank balance to people!

Hush now, I was just using you as an example! You can see why it’s useful to have this information stored away somewhere, and log4j is a software library that makes it really easy to do. Virtually all Java server-side code out there uses log4j somewhere inside it, to handle this sort of thing.

Unfortunately, log4j has a few handy features that were originally intended to be useful features, but aren’t necessarily a good idea to have running on an internet-facing server that does important work such as process your banking requests. Particularly, in this case, if you put a certain specialist type of URL into a log record, log4j will see it, try to download another program from it, and will then run that program in a certain well-defined way. Of course, you might say, there’s nothing wrong with that because all of the log record messages are just written by the bank’s own software developers, so everything’s perfectly safe. However, as I said above, one thing they may very well be logging is which browser you happen to be using, because that’s very useful diagnostic data if people start having problems. “Which browser you happen to be using”, though, is just a field that you send them, and if you know what you’re doing, you can change it to whatever you want to. Including a special type of URL which will…well, hopefully you get the picture. And now you’re running whatever programs you like on one of your bank’s internal servers. Ah. You can see now why Java developers have not been having a good week.

The fix for this is straightforward, but rolling the fix out will have involved a huge proportion of the Java code running in the world being checked, double-checked, and redeployed when it’s known to be safe. Moreover, all of the developers doing this will have had several queries a day from their managers asking just how much they are exposed to this issue. I know: I’ve had several myself, even though my response is straightforwardly “we don’t run any Java code at all, so don’t worry.” I do tell them to tell the clients we have thoroughly and conscientiously audited our systems because from a client-relations point of view it does sound a bit more professional than “no, and our tech lead is very glad of her career choices”. But it still means plenty of messages for me to answer.

Incidentally, I don’t feel any sort of schadenfreude about this, in case you were wondering. I genuinely feel sorry for a lot of people I know, who will not have had a good week fixing this stuff. I’ve worked in big banks and other similar organisations, and I know a lot of former colleagues and current friends who will have spent the last week focusing on this above all else. It’s not nice when you are suddenly bowled by a risk like this; and moreover, it’s not as if Java is uniquely likely to suffer from this type of problem. There are nuances to this that I may come back to in a later post; but next time something like this happens, the person fixing it might well be me.

The old gods (redux)

Or, looking at the sky again

Back in August I talked about how Jupiter and Saturn were nicely visible in the sky, but not until well after The Children were in bed. Last night, though, we had a rare family conjunction of myself and The Children being in the same place, on a night when it was dark well before their bedtime, with a largely clear sky. So, the telescope came out.

This was the first time The Children had been able to use the telescope this autumn, the first time since a few abortive attempts just after moving house in February. I was impressed, to be honest, how over nine months they have grown that bit more mature to be able to use the telescope a bit better. Last winter, it was difficult to get them to stand still long enough to look through a telescope properly, difficult to get them to look through the eyepiece without grabbing onto it and swinging it out of position, and difficult to get them to wait patiently whilst I aimed and focused it. Now, though, they managed to do that with a few different things. FIrst we looked at Saturn, its rings angled and nicely visible; then at Jupiter and the four Galilean Moons. I couldn’t really see any cloud bands on Jupiter this time, unlike in August, but nevertheless the children were pretty excited.

There was a fair amount of patchy cloud; some constellations were visible but nothing exciting enough to hold The Children’s interest. In any case, it was almost bedtime. I left the telescope set up, though, and after a few hours the clouds had largely cleared and we went outside again. Orion was just rising; we looked at the nebula, and at Betelguese, and the Pleiades. The night sky, still just as it was last winter.

Code archaeology

When things become relevant again

One thing I have been doing over the past few weeks is: finally, finally, taking the hard drive out of my last desktop computer—last used about 8 years ago at a guess—and actually copying all the documents off it. It also had stuff preserved from pretty much every desktop machine I’d had before that, so there was a whole treasure-chest of photographs I hadn’t seen in years, things I’d written, and various incomplete coding projects.

Some of the photos will no doubt get posted on here over the coming weeks, but this post isn’t about those. Because, by pure coincidence, I was browsing my Twitter feed this morning and saw this tweet from @ireneista:

we were trying to help a friend get up to speed on how to make a Unix process into a daemon, which is something we found plenty of guides on in the 90s but it’s largely forgotten knowledge

Hang on a minute, I think. Haven’t I just been pulling old incomplete coding projects off my old hard disk and saving them into Github repositories instead? And don’t some of those have exactly that code in? A daemon, on Unix, is roughly the equivalent of a “Service” on Windows. It’s a program that runs all the time in the background on a computer, doing important work.* Many servers don’t even run anything else to speak of. On both Unix and Windows systems, there are special steps you have to take to properly “detach” your code and let it run in the background as part of the system, and if you don’t do all those steps properly you will either produce something that is liable to break and stop running that it’s not supposed to, or write something that fills up your system’s process table with so-called “zombie” entries for processes that have stopped running but still need some bookkeeping information kept about them.

Is this forgotten knowledge? Well, it’s certainly not something I would be able to do, off the top of my head, without a lot of recourse to documentation. For a start all the past projects I’m talking about were written in C, for Linux systems, and I haven’t touched the language nor the operating system much for a number of years now.

None of the projects I’m talking about ever approached completion or were properly tested, so there’s not that much point releasing their full source code to the world. However, clearly, the information about how to set up a daemon has disappeared out of circulation a bit. Moreover, that code was generally stuff that I pulled wholesale from Usenet FAQs myself, tidying it up and adding extra logging as I needed, so compared to the rest of the projects, it’s probably much more reliable. The tweet thread above links to some CIA documentation released by Wikileaks which is nice and explanatory, but doesn’t actually include some of the things I always did when starting up a daemon. You could, of course, argue they’re not always needed. So, here is some daemonisation code I have cobbled together by taking an average across the code I was writing about twenty-ish years ago and adding a bit of explanation. Hopefully this will be useful to somebody.

Bear in mind this isn’t real code: it depends on functions and variables that you can assume we’ve declared in headers, or in the parts of the code that have been omitted. As the old saying goes, I accept no responsibility if this code causes loss, damage, or demons flying out of your nose.**

/* You can look up yourself which headers you'll need to include */

int main(int argc, char **argv)
{
    /* 
     * First you'll want to read config and process command line args,
     * because it might be nice to include an argument to say "dont'
     * run as a daemon!" if you fancy that.
     *
     * This code is also written to use GNU intltools, and the setup for that
     * goes here too.
     */

    /* Assume the daemonise variable was set by processing the config */
    if (daemonise)
    {
        /* First we fork to a new process and exit the original process */
        switch (fork ())
        {
        case -1:
            syslog (LOG_ERR, _("Forking hell, aborting."));
            exit (EXIT_FAILURE);
        default:
            exit (0);
        case 0:
            break;
        }

        /* Then we call setsid() to become a process group leader, making sure we are detached
         * from any terminals */
        if (setsid () == -1)
        {
            syslog (LOG_ERR, _("setsid() failed, aborting."));
            exit (EXIT_FAILURE);
        }

        /* Then we fork again */
        switch (fork ())
        {
        case -1:
            syslog (LOG_ERR, _("Forking hell x2, aborting."));
            exit (EXIT_FAILURE);
        default:
            exit (0);
        case 0:
            break;
        }

        /* Next, a bit of cleanup.  Change our CWD to / so we don't block any umounts, and 
         * redirect our standard streams to taste */
        umask (0022);
        if (chdir ("/"))
            syslog (LOG_WARNING, _("Cannot chdir to root directory"));
        freopen ("/dev/null", "w", stdout);
        freopen ("/dev/null", "r", stdin);
        freopen ("/dev/console", "w", stderr); /* This one in particular might not be what you want */

        /*
         * Listen to some signals.  The second parameters are function pointers which 
         * you'll have to imagine are defined elsewhere.  Reloading config on SIGHUP
         * is a common daemon behaviour you might want.  I can't remember why I thought
         * it important to ignore SIGPIPE
         */
        signal (SIGPIPE, SIG_IGN);
        signal (SIGHUP, warm_restart);
        signal (SIGQUIT, graceful_shutdown);
        signal (SIGTERM, graceful_shutdown);

        /* And now we're done!  Let's go and run the rest of our code */
        run_the_daemon ();
    }
}

The above probably includes some horrible mistake somewhere along the way, but hopefully it’s not too inaccurate, and hopefully would work in the real world. If you try it—or have opinions about it—please do get in touch and let me know.

* NB: this is a simplification for the benefit of the non-technical. Yes, I know I’m generalising and lots of daemons and services don’t run all the time. Please don’t write in with examples.

** “demons flying out of your nose” was a running joke in the comp.lang.c Usenet group, for something it would be considered entirely legitimate for a C compiler to do if you wrote code that was described in the C language standard as having “undefined behaviour”.

Look to the skies

But, specifically, at the moon

An upcoming astronomy event: in a couple of weeks time, on October 16th, it’s International Observe The Moon Night. The idea being, everyone gets together around the world and, well, looks at the moon.

You might expect an event like this to happen on the full moon. It’s not, however: the moon will be waxing gibbous, a couple of days after passing First Quarter. In many ways this makes it a more interesting sight, as there will be a day/night terminator visible. That is: the line between the bright sunlit part and the dark night-time part. If you get a telescope or binoculars and look at the terminator, you can see the low-angled sunlight picking up ridges and hills, and casting deep shadows into the craters. Because the moon has essentially no atmosphere, the picture you see will be wonderfully crisp and sharp, the ridge of every crater picked out perfectly.

The Moon might be the nearest heavenly body, most of the time, but there’s still an awful lot we don’t know about it. Moreover, it’s fascinating just to go outside and look at. On International Observe The Moon Night you can go and join an established event, or you can put your hand up to host one yourself. Or, if you don’t like either of those options, just go outside and look at it yourself. It will—clouds permitting—be beautiful.

The old gods

The astronomy season is starting again

We’re getting to the time of year now when it’s properly dark before a reasonable bedtime; as opposed to a couple of months ago, when it is still twilight in the deepest part of the night, which around here happens at about quarter past one in summer. August, by comparison, is the time of year when I can go outside at 10pm and see if the sky is clear enough to do a small bit of stargazing before bed. It’s too late to wake up The Child Who Likes Space, who nominally owns the telescope, but nevertheless, I rationalise, I can always tell him about it in the morning.

A while ago, I noticed that according to timeanddate.com’s planet apparent size calculator, Jupiter would have a relatively large disc right now. Right now, in fact, it’s receding from us, but it’s still a relatively chunky 49 arcseconds wide. Still a dot to the naked eye—the Moon is about 36 times bigger in apparent diameter if my rough mental calculations are correct—but big for a sky object, and with the best chance we would have of seeing features on it. Over the past few weeks I’ve noticed that Jupiter and Saturn together, although relatively low in the sky, are very definitely the brightest things in the south-eastern sky when I go to bed. So last night, as the sky was almost clear, I decided to get the telescope out.

Last spring I found it rather hard to get the telescope set up in the new garden, due to the street light that shines directly into it over the garden wall. Back then, though, the garden was a rocky, rubble-strewn wasteland, which didn’t help. Now it’s grassed, and at the moment I can tuck the camping table and the telescope into a relatively shady distant corner; from which both planets were shining bright in the sky. It was as easy as any astronomy I could think of: set up the telescope, point the finder on Jupiter, and as soon as I had focused, I had the planet and the four Galilean moons right in the centre of the eyepiece. All four of the moons were on the same side of the planet last night, Io just visible almost touching the planetary disc, the other three clear and sharp and separate spread out to the east of the planet. Jupiter itself was a fairly uniform cream colour, with a thin, darker, more reddish band visible near its equator. It seemed so sharp and clear, much more clear and bright than a photograph.

After Jupiter, I trained the spotter on Saturn, much smaller in the sky. At first it just seemed to be an oval blob, but I’d knocked the focus off slightly. Tweaking it showed the planet, orange in colour, and its rings. We don’t have anywhere near enough magnification to show the ring divisions, and the rings and the planet seemed to have a fully uniform colour. It’s strange to think that when Stegosaurs were alive and tramping the planet, Saturn probably didn’t have any rings at all. I couldn’t make out any of the planet’s moons, but I know they are much fainter than those of Jupiter, my eyes probably hadn’t had time to fully adapt to the dark, and I didn’t know where to be looking in any case. I wonder how different the history of science would have been, if Jupiter didn’t have four clear bright moons for Galileo to spot easily with his early telescopes.

Incidentally, due to geometry, it’s impossible for the planets orbiting outside Earth to have phases like the Moon does: their discs will always appear from our standpoint to be fully illuminated. This coming winter Venus will be the largest planet in the sky—it peaks at just under 63 arcseconds on January 8th—and it will be interesting to see if around then more than a thin crescent is visible. Assuming the skies are clear, of course.

Summer astronomy news

Time for some more meteors

You might remember, if you’ve read back as far as last March or April, that I’d been trying some astrophotography but hadn’t got very far. I still haven’t got very far, largely because it’s summer, and we are only just out of the part of the year where it never gets properly dark at all here.

The other day, though, regular reader MdeC was grumbling on their social media that their attempt to take a gorgeous photo of the Milky Way—far better than anything I’ve produced—had been ruined by a meteor. And it reminded me: we’re just coming into one of the key meteor-spotting seasons of the year. August is the month of the Perseid meteor shower, one of the busiest and brightest showers in the calendar. The fact there are lots of meteors in the sky in August has been known since ancient times; in the 19th century the astronomer Schiaparelli calculated they were created by the trail of dust left behind by Comet Swift-Tuttle in its orbit. Their peak will be next week, on Thursday night and Friday morning, but they are spread quite broadly, and any clear night over the next couple of weeks gives you a good chance of seeing some.

So, if there’s a clear night, I’ll be taking a deckchair outside, lying back and looking up at the sky. There’s no point really setting up the telescope or getting binoculars out: they move too fast and can be anywhere in the sky. Just relax, find a dark place if you can, let your eyes adapt, and watch them flash across the sky.

Milestones

Or, how and how not to learn languages

I passed a very minor milestone yesterday. Duolingo, the language-learning app, informed me that I had a “streak” of 1,000 days. In other words, for the past not-quite-three-years, most days, I have fired up the Duolingo app or website and done some sort of language lesson. I say “most days”: in theory the “streak” is supposed to mean I did it every single day, but in practice you can skip days here and there if you know what you’re doing. I’ve mostly been learning Welsh, with a smattering of Dutch, and occasionally revising my tourist-level German.

My Welsh isn’t, I have to admit, at any sort of level where I can actually hold a conversation. I barely dare say “Ga i psygod a sglodion bach, plîs,” in the chip shop when visiting I’m Welsh-speaking Wales, because although I can say that I am wary I wouldn’t be any use at comprehending the response, if they need to ask, for example, exactly what type of fish I want. To be honest, I see this as a big drawback to the whole Duolingo-style learning experience, which seems essentially focused around rote learning of a small number of set phrases in the hope that a broader understanding of grammar and vocabulary will follow. I’ve been using Duolingo much longer than three years—I first used it to start revising my knowledge of German back in 2015. When I last visited Germany, though, I was slightly confused to find that after over a year of Duolingo, if anything, I felt less secure in my command of German, less confident in my ability to use it day-to-day. Exactly why I don’t now, but it helped me realise that I can’t just delegate that sort of learning to a question-and-answer app. If I want to progress with my Welsh, I know I’m going to have to find some sort of conversational class.

Passing the 1,000 days milestone made me start wondering if anyone has produced something along the same lines as Duolingo but for computer languages. In some ways it should be a less difficult problem than for natural language learning, because, after all, any nuances of meaning are less ambiguous. I lose track of the number of times Duolingo marks me down because I enter an English answer which means the same as the accepted answer but uses some other synonym or has a slightly different word order. With a coding language, if you have your requirements and the output meets them, your answer is definitely right. In theory it shouldn’t be too hard to create a Duolingo-alike thing but with this sort of question:

Given a List<Uri> called uris, return a list of the Uris whose hostnames end in .com in alphabetical order.

  1. uris.Select(u => u.Host).Where(h => h.EndsWith(".com")).OrderBy();
  2. uris.Where(u => u != null && u.Host.EndsWith(".com")).OrderBy(u => u.AbsoluteUri).ToList();
  3. uris.SelectMany(u => u.Where(Host.EndsWith(".com"))).ToList().Sort();

The answer, by the way, is 2. Please do write in if I’ve made any mistakes by being brave enough to write this off the top of my head; writing wrong-but-plausible-looking code is harder than you think. Moreover, I know the other two answers contain a host of errors and wouldn’t even compile, just as the wrong answers in Duolingo often contain major errors in grammar and vocabulary.

Clearly, you could do something like this, and you could memorise a whole set of “cheat sheets” of different coding fragments that fit various different circumstances. Would you, though, be able to write decent, efficient, and most importantly well-understood code this way? Would you understand exactly the difference between the OrderBy() call in the correct answer, and the Sort() call in answer three?* I suspect the answer to these questions is probably no.

Is that necessarily a bad thing, though? It’s possibly the level that junior developers often work at, and we accept that that’s just a necessary phrase of their career. Most developers start their careers knowing a small range of things, and they start out by plugging those things together and then sorting the bugs out. As they learn and grow they learn more, they fit things together better, they start writing more original code and slowly they become fluent in writing efficient, clean and idiomatic code from scratch. It’s a good parallel to the learner of a natural language, learning how to put phrases together, learning the grammar for doing so and the idioms of casual conversation, until finally they are fluent.

I realise Duolingo is only an early low-level step in my language-learning. It’s never going to be the whole thing; I doubt it would even get you to GCSE level on its own. As a foundational step, though, it might be a very helpful one. One day maybe I’ll be fluent in Welsh or German just as it’s taken me a few years to become fully fluent in C#. I know, though, it’s going to take much more than Duolingo to get me there.

* The call in answer 2 is a LINQ method which does not modify its source but instead returns a new enumeration containing the sorted data. The call in answer 3 modifies the list in-place.