30 Jan 2015
On behalf of Twisted Matrix Laboratories, I am honoured to announce that Twisted 15.0.0 is here!
- SSLv3 is disabled by default by endpoints created by twisted.internet.endpoints.serverFromString and twisted.internet.endpoints.clientFromString.
- inlineCallbacks now has introductory documentation, and now supports using the return statement with a value on Python 3.
- twisted.web.client.Agent now supports using UNIX sockets.
- ProcessEndpoint now has flow control, which makes it useful for many more protocols
- A whole bunch of bug fixes and other improvements, with 70+ closed tickets.
You can find the downloads on PyPI (or alternatively the Twisted Matrix website). The full details of what's new in the release is contained in the NEWS file.
As usual, many thanks to everyone who had a part in this release - the supporters of the Twisted Software Foundation, the developers who contributed code and documentation, and all the people building great things with Twisted!
30 Jan 2015 10:13am GMT
25 Jan 2015
On the Internet, it's important to secure all of your communications.
The problem with these applications is that they advertise their presence. Since "insecure chat", "insecure email" and "insecure phone calls" all have a particular, detectable signature, an interested observer may easily detect your supposedly "secure" communication. Not only that, but the places that you go to obtain them are suspicious in their own right. In order to visit Whisper Systems, you have to be looking for "secure" communications.
This allows the adversary to use "security" technologies such as encryption as a sort of stencil, to outline and highlight the communication that they really want to be capturing. In the case of the NSA, this dumps anyone who would like to have a serious private conversation with a friend into the same bucket, from the perspective of the authorities, as a conspiracy of psychopaths trying to commit mass murder.
The Snowden documents already demonstrate that the NSA does exactly this; if you send a normal email, they will probably lose interest and ignore it after a little while, whereas if you send a "secure" email, they will store it forever and keep trying to crack it to see what you're hiding.
If you're running a supposedly innocuous online service or writing a supposedly harmless application, the hassle associated with setting up TLS certificates and encryption keys may seem like a pointless distraction. It isn't.
For one thing, if you have anywhere that user-created content enters your service, you don't know what they are going to be using it to communicate. Maybe you're just writing an online game but users will use your game for something as personal as courtship. Can we agree that the state security services shouldn't be involved in that?. Even if you were specifically writing an app for dating, you might not anticipate that the police will use it to show up and arrest your users so that they will be savagely beaten in jail.
The technology problems that "secure" services are working on are all important. But we can't simply develop a good "secure" technology, consider it a niche product, and leave it at that. Those of us who are software development professionals need to build security into every product, because users expect it. Users expect it because we are, in a million implicit ways, telling them that they have it. If we put a "share with your friend!" button into a user interface, that's a claim: we're claiming that the data the user indicates is being shared only with their friend. Would we want to put in a button that says "share with your friend, and with us, and with the state security apparatus, and with any criminal who can break in and steal our database!"? Obviously not. So let's stop making the "share with your friend!" button actually do that.
Those of us who understand the importance of security and are in the business of creating secure software must, therefore, take on the Sisyphean task of not only creating good security, but of competing with the insecure software on its own turf, so that people actually use it. "Slightly worse to use than your regular email program, but secure" is not good enough. (Not to mention the fact that existing security solutions are more than "slightly" worse to use). Secure stuff has to be as good as or better than its insecure competitors.
I know that this is a monumental undertaking. I have personally tried and failed to do something like this more than once. As the Rabbi Tarfon put it, though:
It is not incumbent upon you to complete the work, but neither are you at liberty to desist from it.
25 Jan 2015 12:16am GMT
12 Jan 2015
As you may have seen me around the Internet, I am typically represented by an obscure symbol.
I have been asked literally hundreds of times about the meaning of that symbol, and I've always been cryptic in response because I felt that a full explanation is too much work. Since the symbol is something I invented, the invention is fairly intricate, and it takes some time to explain, describing it in person requires a degree of sustained narcissism that I'm not really comfortable with.
You all keep asking, though, and I really do appreciate the interest, so thanks to those of you who have asked over and over again: here it is. This is what the glyph means.
I do have one other reason that I'm choosing to publish this particular tidbit now. Over the course of my life I have spent a lot of time imagining things, doing world-building for games that I have yet to make or books that I have yet to write. While I have published fairly voluminously at this point on technical topics (more than once on actual paper), as well as spoken about them at conferences, I haven't made many of my fictional ideas public.
There are a variety of reasons for this (not the least of which that I have been gainfully employed to write about technology and nobody has ever wanted to do that for fiction) but I think the root cause is because I'm afraid that these ideas will be poorly received. I'm afraid that I'll be judged according to the standards for the things that I'm now an expert professional at - software development - for something that I am a rank amateur at - writing fiction. So this problem is only going to get worse as I get better at the former and keep not getting practice at the latter by not publishing.
In other words, I'm trying to break free of my little hater.
So this represents the first - that I recall, at least - public sharing of any of the Divunal source material, since the Twisted Reality Demo Server was online 16 years ago. It's definitely incomplete. Some of it will probably be bad; I know. I ask for your forbearance, and with it, hopefully I will publish more of it and thereby get better at it.
I have been working on the same video game, off and on, for more or less my entire life. I am an extremely distractable person, so it hasn't seen that much progress - at least not directly - in the last decade or so. I'm also relentlessly, almost pathologically committed to long-term execution of every dumb idea I've ever had, so any minute now I'm going to finish up with this event-driven networking thing and get back to the game. I'll try to avoid spoilers, in case I'm lucky enough for any of you ever actually play this thing.
The symbol comes from early iterations of that game, right about the time that it was making the transition from Zork fan-fiction to something more original.
Literally translated from the in-game language, the symbol is simply an ideogram that means "person", but its structure is considerably more nuanced than that simple description implies.
The world where Divunal takes place, Divuthan, was populated by a civilization that has had digital computers for tens of thousands of years, so their population had effectively co-evolved with automatic computing. They no longer had a concept of static, written language on anything like paper or books. Ubiquitous availability of programmable smart matter meant that the language itself was three dimensional and interactive. Almost any nuance of meaning which we would use body language or tone of voice to convey could be expressed in varying how letters were proportioned relative to each other, what angle they were presented at, and so on.
Literally every Divuthan person's name is some variation of this ideogram.
So a static ideogram like the one I use would ambiguously reference a person, but additional information would be conveyed by diacritical marks consisting of other words, by the relative proportions of sizes, colors, and adornments of various parts of the symbol, indicating which person it was referencing.
However, the game itself is of the post-apocalyptic variety, albeit one of the more hopeful entries in that genre, since restoring life to the world is one of the player's goals. One of the things that leads to the player's entrance into the world is a catastrophe that has mysteriously caused most of the inhabitants to disappear and disabled or destroyed almost all of their technology.
Within the context of the culture that created the "glyph" symbol in the game world, it wasn't really intended to be displayed in the form that you see it. The player first would first see such a symbol after entering a ruined, uninhabited residential structure. A symbol like this, referring to a person, would typically have adornments and modifications indicating a specific person, and it would generally be animated in some way.
The display technology used by the Divuthan civilization was all retained-mode, because I imagined that a highly advanced display technology would minimize power cost when not in use (much like e-paper avoids bleeding power by constantly updating the screen). When functioning normally, this was an irrelevant technical detail, of course; the displays displayed what you want them to display. But after a catastrophe that has disrupted network connectivity and ruined a lot of computers, this detail is important because many of the displays were still showing static snapshots of a language intended to use motion and interactivity as ways to convey information.
As the player wandered through the environment, they would find some systems that were still active, and my intent was (or "is", I suppose, since I do still hold out hope that I'll eventually actually make some version of this...) that the player would come to see the static, dysfunctional environment around them as melancholy, and set about restoring function to as many of these devices as possible in order to bring the environment back to life. Some of this would be represented quite concretely as time-travel puzzles later in the game actually allowed the players to mitigate aspects of the catastrophe that broke everything in the first place, thereby "resurrecting" NPCs by preventing their disappearance or death in the first place.
Coen refers to the self, the physical body, the notion of "personhood" abstractly. The minified / independent version is an ideogram for just the head, but the full version as it is presented in the "glyph" ideogram is a human body: the crook at the top is the head (facing right); the line through the middle represents the arms, and the line going down represents the legs and feet.
This is the least ambiguous and nuanced of all the symbols. The one nuance is that if used in its full form with no accompanying ideograms, it means "corpse", since a body which can't do anything isn't really a person any more.
This is the trickiest ideogram to pronounce. The "ks" is meant to be voiced as a "click-hiss" noise, the "e" has a flat tone like a square wave from a synthesizer, and the "t" is very clipped. It is intended to reference the power-on sound that some of the earliest (remember: 10s of thousands of years before the main story, so it's not like individuals have a memory of the way these things sounded) digital computers in Divuthan society made.
Honestly though if you try to do this properly it ends up sounding a lot like the English word "cassette", which I assure you is fitting but completely unintentional.
Kset refers to algorithms and computer programs, but more generally, thought and the life of the mind.
This is a reference to the "Ee" spell power rune in the 80s Amiga game, Dungeon Master, which sadly I can't find any online explanation of how the manual described it. It is an object poised on a sharp edge, ready to roll either left or right - in other words, a symbolic representation of a physical representation of the algorithmic concept of a decision point, or the computational concept of a branch, or a jump instruction.
Edec refers to connectedness. It is an ideogram reflecting a social graph, with the individual below and their many connections above them. It's the general term for "social relationship" but it's also the general term for "network protocol". When Divuthan kids form relationships, they often begin by configuring a specific protocol for their communication.
This is how boundary-setting within friendships and work environments (and, incidentally, flirting) works; they use meta-protocol messages to request expanded or specialized interactions for use within the context of their dedicated social-communication channels.
Unlike most of these other ideograms, its pronunciation is not etymologically derived from an onomatopoeia, but rather from an acronym identifying one of the first social-communication protocols (long since obsoleted).
"Zenk" is the ideogram for creation. It implies physical, concrete creations but denotes all types of creation, including intellectual products.
The ideogram represents the Divuthan version of an anvil, which, due to certain quirks of Divuthan materials science that is beyond the scope of this post, doubles for the generic idea of a "work surface". So you could also think of it as a desk with two curved legs. This is the only ideogram which represents something still physically present in modern, pre-catastrophe Divuthan society. In fact, workshop surfaces are often stylized to look like a Zenk radical, as are work-oriented computer terminals (which are basically an iPad-like device the size of a dinner table).
The pronunciation, "Zenk", is an onomatopoeia, most closely resembled in English by "clank"; the sound of a hammer striking an anvil.
"Lesh" is the ideogram for communication. It refers to all kinds of communication - written words, telephony, video - but it implies persistence.
The bottom line represents a sheet of paper (or a mark on that sheet of paper), and the diagonal line represents an ink brush making a mark on that paper.
This predates the current co-evolutionary technological environment, because appropriately for a society featured in a text-based adventure game, the dominant cultural groups within this civilization developed a shared obsession for written communication and symbolic manipulation before they had access to devices which could digitally represent all of it.
All Together Now
There is an overarching philosophical concept of "person-ness" that this glyph embodies in Divuthan culture: although individuals vary, the things that make up a person are being (the body, coen), thinking (the mind, kset), belonging (the network, edec), making (tools, zenk) and communicating (paper and pen, lesh).
In summary, if a Divuthan were to see my little unadorned avatar icon next to something I have posted on twitter, or my blog, the overall impression that it would elicit would be something along the lines of:
"I'm just this guy, you know?"
And To Answer Your Second Question
No, I don't know how it's pronounced. It's been 18 years or so and I'm still working that bit out.
12 Jan 2015 9:00am GMT
01 Jan 2015
The scientific computing platform for Erlang/LFE has just been announced on the LFE blog. Though written in the Erlang Lisp syntax of LFE, it's fully usable from pure Erlang. It wraps the new py library for Erlang/LFE, as well as the ErlPort project. More importantly, though, it wraps Python 3 libs (e.g., math, cmath, statistics, and more to come) and the ever-eminent NumPy and SciPy projects (those are in-progress, with matplotlib and others to follow).
(That LFE blog post is actually a tutorial on how to use lsci for performing polynomial curve-fitting and linear regression, adapted from the previous post on Hy doing the same.)
With the release of lsci, one can now start to easily and efficiently perform computationally intensive calculations in Erlang/LFE (and any other Erlang Core-compatible language, e.g., Elixir, Joxa, etc.) That's super-cool, but it's not quite the point ...
While working on lsci, I found myself experiencing a great deal of joy. It wasn't just the fact that supervision trees in a programming language are insanely great. Nor just the fact that scientific computing in Python is one of the best in any language. It wasn't only being able to use two syntaxes that I love (LFE and Python) cohesively, in the same project. And it wasn't the sum of these either ;-) You probably see where I'm going with this ;-) The joy of these and many other great aspects of inter-operation between multiple powerful computing systems is truly greater than the sum of its parts.
I've done a bunch of Julia lately and am a huge fan of this language as well. One of the things that Julia provides is explicit interop with Python. Julia is targeted at the world of scientific computing, aiming to be a compelling alternative to Fortran (hurray!), so their recognition of the enormous contribution the Python scientific computing community has made to the industry is quite wonderful to see.
A year or so ago I did some work with Clojure and LFE using Erlang's JInterface. Around the same time I was using LFE on top of Erjang, calling directly into Java without JInterface. This is the same sort of Joy that users of Jython have, and these are more examples of languages and tools working to take advantage of the massive resources available in the computing community.
Obviously, language inter-op is not new. Various FFIs have existed for quite some time (I'm a big fan of the Common Lisp CFFI), but what is new (relatively, that is ... as I age, anything in the past 10 years is new) is that we are seeing this not just for programs reaching down into C/C++, but reaching across, to other higher-level languages, taking advantage of their great achievements -- without having to reinvent so many wheels.
When this level of cooperation, credit, etc., is done in the spirit of openness, peer-review, code-reuse, and standing on the shoulders of giants (or enough people to make giants!), we get joy. Beautiful, wonderful coding joy.
And it's so much greater than the sum of the parts :-)
01 Jan 2015 9:01pm GMT
28 Dec 2014
The previous post on Python support in Erlang/LFE made Hacker News this week, climbing in fits and starts to #19 on the front page. That resulted in the biggest spike this blog has seen in several months.
It's a shame, in a way, since it came a few days too early: there's a new library out for the Erlang VM (written in LFE) which makes it much easier to use Python from Erlang (the language from Sweden that's famous for impressing both your mum and your cats).
The library is simply called py. It's a wrapper for ErlPort, providing improved usability for Python-specific code as well as an Erlang process supervision tree for the ErlPort Python server. It has an extensive README that not only does the usual examples with LFE, but gives a full accounting of usage in the more common Prolog-inspired syntax Erlang. The LFE Blog has a new post with code examples as well as a demonstration of the py supervision tree (e.g., killing Python server processes and having them restart automatically) which hasn't actually made it into the README yet -- so get it while it's hot!
The most exciting bits are yet to come: there are open tickets for:
- work on multiple Python server processes
- scheduling code execution to these, and
- full Python distribution infrastructure with parallel execution.
28 Dec 2014 1:09am GMT
26 Dec 2014
Update 1: This post has a sequel here.
Update 2: There is a new LFE library that provides more idiomatic access to Python from LFE/Erlang by wrapping ErlPort and creating convenience functions. Lisp macros were, of course, involved in its making.
This is a short little blog post I've been wanting to get out there ever since I ran across the erlport project a few years ago. Erlang was built for fault-tolerance. It had a goal of unprecedented uptimes, and these have been achieved. It powers 40% of our world's telecommunications traffic. It's capable of supporting amazing levels of concurrency (remember the 2007 announcement about the performance of YAWS vs. Apache?).
With this knowledge in mind, a common mistake by folks new to Erlang is to think these performance characteristics will be applicable to their own particular domain. This has often resulted in failure, disappointment, and the unjust blaming of Erlang. If you want to process huge files, do lots of string manipulation, or crunch tons of numbers, Erlang's not your bag, baby. Try Python or Julia.
But then, you may be thinking: I like supervision trees. I have long-running processes that I want to be managed per the rules I establish. I want to run lots of jobs in parallel on my 64-core box. I want to run jobs in parallel over the network on 64 of my 64-core boxes. Python's the right tool for the jobs, but I wish I could manage them with Erlang.
(There are sooo many other options for the use cases above, many of them really excellent. But this post is about Erlang/LFE :-)).
Traditionally, if you want to run other languages with Erlang in a reliable way that doesn't bring your Erlang nodes down with badly behaved code, you use Ports. (more info is available in the Interoperability Guide). This is what JInterface builds upon (and, incidentally, allows for some pretty cool integration with Clojure). However, this still leaves a pretty significant burden for the Python or Ruby developer for any serious application needs (quick one-offs that only use one or two data types are not that big a deal).
erlport was created by Dmitry Vasiliev in 2009 in an effort to solve just this problem, making it easier to use of and integrate between Erlang and more common languages like Python and Ruby. The project is maintained, and in fact has just received a few updates. Below, we'll demonstrate some usage in LFE with Python 3.
If you want to follow along, there's a demo repo you can check out:
Change into the repo directory and set up your Python environment:
Next, switch over to the LFE directory, and fire up a REPL:
Note that this will first download the necessary dependencies and compile them (that's what the [snip] is eliding).
Now we're ready to take erlport for a quick trip down to the local:
And that's all there is to it :-)
Perhaps in a future post we can dive into the internals, showing you more of the glory that is erlport. Even better, we could look at more compelling example usage, approaching some of the functionality offered by such projects as Disco or Anaconda.
26 Dec 2014 6:06am GMT
22 Dec 2014
I caught Toshio Kuratomi's post about asyncio initialization patterns (or anti-patterns) on Planet Python. This is something I've dealt with a lot over the years using Twisted (one of the sources of inspiration for the asyncio developers).
To recap, Toshio wondered about a pattern involving asynchronous initialization of an instance. He wondered whether it was a good idea to start this work in
__init__ and then explicitly wait for it in other methods of the class before performing the distinctive operations required by those other methods. Using asyncio (and using Toshio's example with some omissions for simplicity) this looks something like:
def __init__(self, ...):
loop = asyncio.get_event_loop()
self.init_future = loop.run_in_executor(None, self._reading_init)
# ... do some initialization work,
# presumably expensive or otherwise long-running ...
# Don't do anything until initialization is done
yield from self.init_future
# ... do some work that depends on that initialization ...
It's quite possible to do something similar to this when using Twisted. It only looks a little bit difference:
def __init__(self, ...):
self.init_deferred = deferToThread(self._reading_init)
# ... do some initialization work,
# presumably expensive or otherwise long-running ...
# Don't do anything until initialization is done
# ... do some work that depends on that initialization ...
Despite the differing names, these two pieces of code basical do the same thing:
_reading_initin a thread from a thread pool
sync_latestis called, first suspend its execution until the thread running
_reading_inithas finished running it
One thing this pattern gives you is an incompletely initialized object. If you write
m = Microblog() then
m refers to an object that's not actually ready to perform all of the operations it supposedly can perform. It's either up to the implementation or the caller to make sure to wait until it is ready. Toshio suggests that each method should do this implicitly (by starting with
yield self.init_deferred or the equivalent). This is definitely better than forcing each call-site of a
Microblog method to explicitly wait for this event before actually calling the method.
Still, this is a maintenance burden that's going to get old quickly. If you want full test coverage, it means you now need twice as many unit tests (one for the case where method is called before initialization is complete and another for the case where the method is called after this has happened). At least. Toshio's
_reading_init method actually modifies attributes of
self which means there are potentially many more than just two possible cases. Even if you're not particularly interested in having full automated test coverage (... for some reason ...), you still have to remember to add this yield statement to the beginning of all of
Microblog's methods. It's not exactly a ton of work but it's one more thing to remember any time you maintain this code. And this is the kind of mistake where making a mistake creates a race condition that you might not immediately notice - which means you may ship the broken code to clients and you get to discover the problem when they start complaining about it.
Another thing this pattern gives you is an object that does things as soon as you create it. Have you ever had a class with a
__init__ method that raised an exception as a result of a failing interaction with some other part of the system? Perhaps it did file I/O and got a permission denied error or perhaps it was a socket doing blocking I/O on a network that was clogged and unresponsive. Among other problems, these cases are often difficult to report well because you don't have an object to blame the problem on yet. The asynchronous version is perhaps even worse since a failure in this asynchronous initialization doesn't actually prevent you from getting the instance - it's just another way you can end up with an incompletely initialized object (this time, one that is never going to be completely initialized and use of which is unsafe in difficult to reason-about ways).
Another related problem is that it removes one of your options for controlling the behavior of instances of that class. It's great to be able to control everything a class does just by the values passed in to
__init__ but most programmers have probably come across a case where behavior is controlled via an attribute instead. If
__init__ starts an operation then instantiating code doesn't have a chance to change the values of any attributes first (except, perhaps, by resorting to setting them on the class - which has global consequences and is generally icky).
Loss of control
A third consequence of this pattern is that instances of classes which employ it are inevitably doing something. It may be that you don't always want the instance to do something. It's certainly fine for a
Microblog instance to create a SQLite3 database and initialize a cache directory if the program I'm writing which uses it is actually intent on hosting a blog. It's most likely the case that other useful things can be done with a
Microblog instance, though. Toshio's own example includes a
post method which doesn't use the SQLite3 database or the cache directory. His code correctly doesn't wait for
init_future at the beginning of his
post method - but this should leave the reader wondering why we need to create a SQLite3 database if all we want to do is post new entries.
Using this pattern, the SQLite3 database is always created - whether we want to use it or not. There are other reasons you might want a
Microblog instance that hasn't initialized a bunch of on-disk state too - one of the most common is unit testing (yes, I said "unit testing" twice in one post!). A very convenient thing for a lot of unit tests, both of
Microblog itself and of code that uses
Microblog, is to compare instances of the class. How do you know you got a
Microblog instance that is configured to use the right cache directory or database type? You most likely want to make some comparisons against it. The ideal way to do this is to be able to instantiate a
Microblog instance in your test suite and uses its
== implementation to compare it against an object given back by some API you've implemented. If creating a
Microblog instance always goes off and creates a SQLite3 database then at the very least your test suite is going to be doing a lot of unnecessary work (making it slow) and at worst perhaps the two instances will fight with each other over the same SQLite3 database file (which they must share since they're meant to be instances representing the same state). Another way to look at this is that inextricably embedding the database connection logic into your
__init__ method has taken control away from the user. Perhaps they have their own database connection setup logic. Perhaps they want to re-use connections or pass in a fake for testing. Saving a reference to that object on the instance for later use is a separate operation from creating the connection itself. They shouldn't be bound together in
__init__ where you have to take them both or give up on using
You might notice that these three observations I've made all sound a bit negative. You might conclude that I think this is an antipattern to be avoided. If so, feel free to give yourself a pat on the back at this point.
But if this is an antipattern, is there a pattern to use instead? I think so. I'll try to explain it.
The general idea behind the pattern I'm going to suggest comes in two parts. The first part is that your object should primarily be about representing state and your
__init__ method should be about accepting that state from the outside world and storing it away on the instance being initialized for later use. It should always represent complete, internally consistent state - not partial state as asynchronous initialization implies. This means your
__init__ methods should mostly look like this:
def __init__(self, cache_dir, database_connection):
self.cache_dir = cache_dir
self.database_connection = database_connection
If you think that looks boring - yes, it does. Boring is a good thing here. Anything exciting your
__init__ method does is probably going to be the cause of someone's bad day sooner or later. If you think it looks tedious - yes, it does. Consider using Hynek Schlawack's excellent characteristic package (full disclosure - I contributed some ideas to characteristic's design and Hynek ocassionally says nice things about me (I don't know if he means them, I just know he says them)).
The second part of the idea an acknowledgement that asynchronous initialization is a reality of programming with asynchronous tools. Fortunately
__init__ isn't the only place to put code. Asynchronous factory functions are a great way to wrap up the asynchronous work sometimes necessary before an object can be fully and consistently initialized. Put another way:
# ... __init__ as above ...
def from_database(cls, cache_dir, database_path):
# ... or make it a free function, not a classmethod, if you prefer
loop = asyncio.get_event_loop()
database_connection = yield from loop.run_in_executor(None, cls._reading_init)
return cls(cache_dir, database_connection)
Notice that the setup work for a
Microblog instance is still asynchronous but initialization of the
Microblog instance is not. There is never a time when a
Microblog instance is hanging around partially ready for action. There is setup work and then there is a complete, usable
This addresses the three observations I made above:
- Methods of
Microblognever need to concern themselves with worries about whether the instance has been completely initialized yet or not.
- Nothing happens in
Microbloghas some methods which depend on instance attributes, any of those attributes can be set after
__init__is done and before those other methods are called. If the
from_databaseconstructor proves insufficiently flexible, it's easy to introduce a new constructor that accounts for the new requirements (named constructors mean never having to overload
__init__for different competing purposes again).
- It's easy to treat a
Microbloginstance as an inert lump of state. Simply instantiating one (using
Microblog(...)has no side-effects. The special extra operations required if one wants the more convenient constructor are still available - but elsewhere, where they won't get in the way of unit tests and unplanned-for uses.
I hope these points have made a strong case for one of these approaches being an anti-pattern to avoid (in Twisted, in asyncio, or in any other asynchronous programming context) and for the other as being a useful pattern to provide both convenient, expressive constructors while at the same time making object initializers unsurprising and maximizing their usefulness.
22 Dec 2014 12:54am GMT
09 Dec 2014
It seems that docker is all the rage these days. Docker has popularized a powerful paradigm for repeatable, isolated deployments of pretty much any application you can run on Linux. There are numerous highly sophisticated orchestration systems which can leverage Docker to deploy applications at massive scale. At the other end of the spectrum, there are quick ways to get started with automated deployment or orchestrated multi-container development environments.
When you're just getting started, this dazzling array of tools can be as bewildering as it is impressive.
A big part of the promise of docker is that you can build your app in a standard format on any computer, anywhere, and then run it. As docker.com puts it:
"... run the same app, unchanged, on laptops, data center VMs, and any cloud ..."
So when I started approaching docker, my first thought was: before I mess around with any of this deployment automation stuff, how do I just get an arbitrary docker container that I've built and tested on my laptop shipped into the cloud?
There are a few documented options that I came across, but they all had drawbacks, and didn't really make the ideal tradeoff for just starting out:
- I could push my image up to the public registry and then pull it down. While this works for me on open source projects, it doesn't really generalize.
- I could run my own registry on a server, and push it there. I can either run it plain-text and risk the unfortunate security implications that implies, deal with the administrative hassle of running my own certificate authority and propagating trust out to my deployment node, or spend money on a real TLS certificate. Since I'm just starting out, I don't want to deal with any of these hassles right away.
- I could re-run the build on every host where I intend to run the application. This is easy and repeatable, but unfortunately it means that I'm missing part of that great promise of docker - I'm running potentially subtly different images in development, test, and production.
I think I have figured out a fourth option that is super fast to get started with, as well as being reasonably secure.
What I have done is:
- run a local registry
- build an image locally - testing it until it works as desired
- push the image to that registry
- use SSH port forwarding to "pull" that image onto a cloud server, from my laptop
Before running the registry, you should set aside a persistent location for the registry's storage. Since I'm using
boot2docker, I stuck this in my home directory, like so:
me@laptop$ mkdir -p ~/Documents/Docker/Registry
To run the registry, you need to do this:
1 2 3 4 5 6 7 8
me@laptop$ docker pull registry ... Status: Image is up to date for registry:latest me@laptop$ docker run --name registry --rm=true -p 5000:5000 \ -e GUNICORN_OPTS=[--preload] \ -e STORAGE_PATH=/registry \ -v "$HOME/Documents/Docker/Registry:/registry" \ registry
To briefly explain each of these arguments -
--name is just there so I can quickly identify this as my registry container in
docker ps and the like;
--rm=true is there so that I don't create detritus from subsequent runs of this container,
-p 5000:5000 exposes the registry to the docker host,
-e GUNICORN_OPTS=[--preload] is a workaround for a small bug,
STORAGE_PATH=/registry tells the registry to look in
/registry for its images, and the
-v option points
/registry at the directory we previously created above.
It's important to understand that this registry container only needs to be running for the duration of the commands below. Spin it up, push and pull your images, and then you can just shut it down.
Next, you want to build your image, tagging it with
me@laptop$ cd MyDockerApp me@laptop$ docker build -t localhost.localdomain:5000/mydockerapp .
Assuming the image builds without incident, the next step is to send the image to your registry.
me@laptop$ docker push localhost.localdomain:5000/mydockerapp
Once that has completed, it's time to "pull" the image on your cloud machine, which - again, if you're using
boot2docker, like me, can be done like so:
1 2 3
me@laptop$ ssh -t -R 127.0.0.1:5000:"$(boot2docker ip 2>/dev/null)":5000 \ mycloudserver.example.com \ 'docker pull localhost.localdomain:5000/mydockerapp'
If you're on Linux and simply running Docker on a local host, then you don't need the "
1 2 3
me@laptop$ ssh -t -R 127.0.0.1:5000:127.0.0.1:5000 \ mycloudserver.example.com \ 'docker pull localhost.localdomain:5000/mydockerapp'
Finally, you can now run this image on your cloud server. You will of course need to decide on appropriate configuration options for your applications such as
1 2 3 4
me@laptop$ ssh mycloudserver.example.com \ 'docker run -d --restart=always --name=mydockerapp \ -p ... -v ... -e ... \ localhost.localdomain:5000/mydockerapp'
To avoid network round trips, you can even run the previous two steps as a single command:
1 2 3 4 5 6
me@laptop$ ssh -t -R 127.0.0.1:5000:"$(boot2docker ip 2>/dev/null)":5000 \ mycloudserver.example.com \ 'docker pull localhost.localdomain:5000/mydockerapp && \ docker run -d --restart=always --name=mydockerapp \ -p ... -v ... -e ... \ localhost.localdomain:5000/mydockerapp'
I would not recommend setting up any intense production workloads this way; those orchestration tools I mentioned at the beginning of this article exist for a reason, and if you need to manage a cluster of servers you should probably take the time to learn how to set up and manage one of them.
However, as far as I know, there's also nothing wrong with putting your application into production this way. If you have a simple single-container application, then this is a reasonably robust way to run it: the docker daemon will take care of restarting it if your machine crashes, and running this command again (with a
docker rm -f mydockerapp before
docker run) will re-deploy it in a clean, reproducible way.
So if you're getting started exploring docker and you're not sure how to get a couple of apps up and running just to give it a spin, hopefully this can set you on your way quickly!
(Many thanks to my employer, Rackspace, for sponsoring the time for me to write this post. Thanks also to Jean-Paul Calderone, Alex Gaynor, and Julian Berman for their thoughtful review. Any errors are surely my own.)
09 Dec 2014 2:14am GMT
28 Nov 2014
If I am creating a new feature in library code, I have two choices with the implementation details: I can make them public - that is, exposed to application code - or I can make them private - that is, for use only within the library.
If I make them public, then the structure of my library is very clear to its clients. Testing is easy, because the public structures may be manipulated and replaced as the tests dictate. Inspection is easy, because all the data is exposed for clients to manipulate. Developers are happy when they can manipulate and test things easily. If I select "public" as the general rule, then developers using my library will be happy, because they'll be able to inspect and test everything quite easily whether I specifically designed in support for that or not.
However, now that they're public, I have to support them in their current form into the forseeable future. Since I tend to maintain the libraries I work on, and maintenance necessarily means change, a large public API surface means a lot of ongoing changes to exposed functionality, which means a constant stream of deprecation warnings and deprecated feature removals. Without private implementation details, there's no axis on which I can change my software without deprecating older versions. Developers hate keeping up with deprecation warnings or having their applications break when a new version of a library comes out, so if I adopt "public" as the general rule, developers will be unhappy.
If I make them private, then the structure of my library is a lot easier to understand by developers, because the API surface is much smaller, and exposes only the minimum necessary to accomplish their tasks. Because the implementation details are private, when I maintain the library, I can add functionality "for free" and make internal changes without requiring any additional work from developers. Developers like it when you don't waste their time with trivia and make it easier to get to what they want right away, and they love getting stuff "for free", so if I adopt "private" as the general rule, developers will be happy.
However, now that they're private, there's potentially no way to access that functionality for unforseen use-cases, and testing and inspection may be difficult unless the functionality in question was designed with an above-average level of care. Since most functionality is, by definition, designed with an average level of care, that means that there will inevitably be gaps in these meta-level tools until the functionality has already been in use for a while, which means that developers will need to report bugs and wait for new releases. Developers don't like waiting for the next release cycle to get access to functionality that they need to get work done right now, so if I adopt "private" as the general rule, developers will be unhappy.
28 Nov 2014 11:25pm GMT
This blog post is a bit different than other technical posts I've done in the past in that the majority of the content is not on the blog in or gists; instead, it is in an IPython notebook. Having adored Mathematica back in the 90s, you can imagine how much I love the IPython Notebook app. I'll have more to say on that at a future date.
I've been doing a great deal of NumPy and matplotlib again lately, every day for hours a day. In conjunction with the new features in Python 3, this has been quite a lot of fun -- the most fun I've had with Python in years (thanks Guido, et al!). As you might have guessed, I'm also using it with Erlang (specifically, LFE), but that too is for a post yet to come.
With all this matplotlib and numpy work in standard Python, I've been going through Lisp withdrawals and needed to work with it from a fresh perspective. Needless to say, I had an enormous amount of fun doing this. Naturally, I decided to share with folks how one can do the latest and greatest with the tools of Python scientific computing, but in the syntax of the Python community's best kept secret: Clojure-Flavoured Python (Github, Twitter, Wikipedia).
|Spoiler: observed data and
polynomial curve fitting
Looking about for ideas, I decided to see what Clojure's Incanter project had for tutorials, and immediately found what I was looking for: Linear regression with higher-order terms, a 2009 post by David Edgar Liebke.
Nearly every cell in the tutorial notebook is in Hy, and for that we owe a huge thanks to yardsale8 for his Hy IPython magics code. For those that love Python and Lisp equally, who are familiar with the ecosystems' tools, Hy offers a wonderful option for being highly productive with a language supporting Lisp- and Clojure-style macros. You can get your work done, have a great time doing it, and let that inner code artist out!
(In fact, I've started writing a macro for one of the examples in the tutorial, offering a more Lisp-like syntax for creating class methods. We'll see what Paul Tagliamonte has to say about it when it's done ... !)
If you want to check out the notebook code and run it locally, just do the following:
This will do the following:
- Create a virtualenv using Python 3
- Download all the dependencies, and then
- Start up the notebook using a local IPython HTTP server
If you just want to read along, you're more than welcome to do that as well, thanks to the IPython NBViewer service. Here's the link: Scientific Computing with Hy: Linear Regressions.
One thing I couldn't get working was the community-provided code for generating tables of contents in IPython notebooks. If you have any expertise in this area, I'd love to get your feedback to see how I need to configure the custom ihy IPython profile for this tutorial.
Without that, I've opted for the manual approach and have provided a table of contents here:
- Loading the Observed Data
- Viewing the Data
- Polynomial Linear Regression
- A Linear Model Class
- Plotting the Model with the Observed Data
28 Nov 2014 8:11pm GMT
21 Nov 2014
Being a bit of an origins nut (I always want to know how something came to be or why it is a certain way), one of the things that always bothered me with regard to Lisp was that no one seemed to talking about the origin of lambda in the lambda calculus. I suppose if I wasn't lazy, I'd have gone to a library and spent some time looking it up. But since I was lazy, I used Wikipedia. Sadly, I never got what I wanted: no history of lambda.  Well, certainly some information about the history of the lambda calculus, but not the actual character or term in that context.
Why lambda? Why not gamma or delta? Or Siddham ṇḍha?
To my great relief, this question was finally answered when I was reading one of the best Lisp books I've ever read: Peter Norvig's Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp. I'll save my discussion of that book for later; right now I'm going to focus on the paragraph at location 821 of my Kindle edition of the book. 
The story goes something like this:
- Between 1910 and 1913, Alfred Whitehead and Bertrand Russell published three volumes of their Principia Mathematica, a work whose purpose was to derive all of mathematics from basic principles in logic. In these tomes, they cover two types of functions: the familiar descriptive functions (defined using relations), and then propositional functions. 
- Within the context of propositional functions, the authors make a typographical distinction between free variables and bound variables or functions that have an actual name: bound variables use circumflex notation, e.g. x̂(x+x). 
- Around 1928, Church (and then later, with his grad students Stephen Kleene and J. B. Rosser) started attempting to improve upon Russell and Whitehead regarding a foundation for logic. 
- Reportedly, Church stated that the use of x̂ in the Principia was for class abstractions, and he needed to distinguish that from function abstractions, so he used ⋀x  or ^x  for the latter.
- However, these proved to be awkward for different reasons, and an uppercase lambda was used: Λx. .
- More awkwardness followed, as this was too easily confused with other symbols (perhaps uppercase delta? logical and?). Therefore, he substituted the lowercase λ. 
- John McCarthy was a student of Alonzo Church and, as such, had inherited Church's notation for functions. When McCarthy invented Lisp in the late 1950s, he used the lambda notation for creating functions, though unlike Church, he spelled it out. 
Somehow, this endears lambda to me even more ;-)
 As you can see from the rest of the footnotes, I've done some research since then and have found other references to this history of the lambda notation.
 Norvig, Peter (1991-10-15). Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp (Kindle Locations 821-829). Elsevier Science - A. Kindle Edition. The paragraph in question is quoted here:
The name lambda comes from the mathematician Alonzo Church's notation for functions (Church 1941). Lisp usually prefers expressive names over terse Greek letters, but lambda is an exception. Abetter name would be make - function. Lambda derives from the notation in Russell and Whitehead's Principia Mathematica, which used a caret over bound variables: x( x + x). Church wanted a one-dimensional string, so he moved the caret in front: ^ x( x + x). The caret looked funny with nothing below it, so Church switched to the closest thing, an uppercase lambda, Λx( x + x). The Λ was easily confused with other symbols, so eventually the lowercase lambda was substituted: λx( x + x). John McCarthy was a student of Church's at Princeton, so when McCarthy invented Lisp in 1958, he adopted the lambda notation. There were no Greek letters on the keypunches of that era, so McCarthy used (lambda (x) (+ xx)), and it has survived to this day.
 Norvig, 1991, Location 821.
 History of Lambda-calculus and Combinatory Logic, page 7.
 Norvig, 1991, Location 821.
 Looking at Church's works online, he uses lambda notation in his 1932 paper A Set of Postulates for the Foundation of Logic. His preceding papers upon which the seminal 1932 is based On the Law of Excluded Middle (1928) and Alternatives to Zermelo's Assumption (1927), make no reference to lambda notation. As such, A Set of Postulates for the Foundation of Logic seems to be his first paper that references lambda.
 Norvig indicates that this is simply due to the limitations of the keypunches in the 1950s that did not have keys for Greek letters.
 Alex Martelli is not a fan of lambda in the context of Python, and though a good friend of Peter Norvig, I've heard Alex refer to lambda as an abomination :-) So, perhaps not beloved for everyone. In fact, Peter Norvig himself wrote (see above) that a better name would have been make-function.
21 Nov 2014 9:12pm GMT
As a manager in the software engineering industry, one of the things that I see on a regular basis is a general lack of knowledge from less experienced developers (not always "younger"!) with regard to the foundations of computing and the several related fields of mathematics. There is often a great deal of focus on what the hottest new thing is, or how the industry can be changed, or how we can innovate on the decades of profound research that has been done. All noble goals.
Notably, another trend I've recognized is that in a large group of devs, there are often a committed few who really know their field and its history. That is always so amazing to me and I have a great deal of admiration for the commitment and passion they have for their art. Let's have more of that :-)
As for myself, these days I have many fewer hours a week which I can dedicate to programming compared to what I had 10 years ago. This is not surprising, given my career path. However, what it has meant is that I have to be much more focused when I do get those precious few hours a night (and sometimes just a few per week!). I've managed this in an ad hoc manner by taking quick notes about fields of study that pique my curiosity. Over time, these get filtered and a few pop to the top that I really want to give more time.
One of the driving forces of this filtering process is my never-ending curiosity: "Why is it that way?" "How did this come to be?" "What is the history behind that convention?" I tend to keep these musings to myself, exploring them at my leisure, finding some answers, and then moving on to the next question (usually this takes several weeks!).
However, given the observations of the recent years, I thought it might be constructive to ponder aloud, as it were. To explore in a more public forum, to set an example that the vulnerability of curiosity and "not knowing" is quite okay, that even those of us with lots of time in the industry are constantly learning, constantly asking.
My latest curiosity has been around recursion: who first came up with it? How did it make it's way from abstract maths to programming languages? How did it enter the consciousness of so many software engineers (especially those who are at ease in functional programming)? It turns out that an answer to this is actually quite closely related to a previous post I wrote on the secret history of lambda. A short version goes something like this:
Giuseppe Peano wanted to establish a firm foundation for logic and maths in general. As part of this, he ended up creating consistent axioms around the hard-to-define natural numbers, counting, and arithmetic operations (which utilized recursion). While visiting a conference in Europe, Bertrand Russell was deeply impressed by the dialectic talent of Peano and his unfailing clarity; he queried Peano as to his secret for success (Peano told him) and them asked for all of his published works. Russell proceeded to study these quite deeply. With this in his background, he eventually co-wrote the Principia Mathematica. Later, Alonzo Church (along with his grad students) sought to improve upon this, and in the process Alonzo Church ended up developing the lambda calculus. His student, John McCarthy, later created the first functional programming language, Lisp, utilizing concepts from the lambda calculus (recursion and function composition).
In the course of reading between 40-50 mathematics papers (including various histories) over the last week, I have learned far more than I had originally intended. So much so, in fact, that I'm currently working on a very fun recursion tutorial that not only covers the usual practical stuff, but steps the reader through programming implementations of the Peano axioms, arithmetic definitions, the Ackermann function, and parts of the lambda calculus.
I've got a few more blog post ideas cooking that dive into functions, their history and evolution. We'll see how those pan out. Even more exciting, though, was having found interesting papers discussing the evolution of functions and the birth of category theory from algebraic topology. This, needless to say, spawned a whole new trail of research, papers, and books... and I've got some great ideas for future blog posts/tutorials around this topic as well. (I've encountered category theory before, but watching it appear unsearched and unbidden in the midst of the other reading was quite delightful).
In closing, I enjoy reading not only the original papers (and correspondence between great thinkers of a previous era), but also the meanderings and rediscoveries of my peers. I've run across blog posts like this in the past, and they were quite enchanting. I hope that we continue to foster that in our industry, and that we see more examples of it in the future.
Keep on questing ;-)
21 Nov 2014 9:10pm GMT
22 Oct 2014
[I wanted a central place to put my CoC Clan War strategy tips so I can refer people to them.]
- A town hall outside the walls is great for farming, but your war base should have amazingly good protection of the town hall, otherwise they get, essentially, a free one star (together with the one star for 50% that people can get by just taking down the outermost buildings with an archer rush, this almost always means free two stars).
- Air defenses should be well protected, or even a simple "take out the air defenses" together with a castle dragon can let even relatively low-level town hall take out pretty impressive bases.
- Do not bother with walls around your town hall. If giants got to the point where they have nothing to do but to take out your town hall, you have bigger problems and otherwise, the archers will take out your town hall while leaving the wall intact. Instead, use walls to protect the giants' favorite targets: wizards and mortars.
- Avoid the "eggshell" design: one strong outer wall with no internal walls. Once the outer wall is breached, your base is effectively wall-free.
- Meta tip #1: Remember to question your instincts if you raid for trophies or loot a lot. War has different incentive schemas and different pros and cons.
- Meta tip #2: [Continuation of meta tip #1] You have more than 30 seconds to figure out your strategy. You can look at the enemy village, and even tap buildings to see ranges. Spend some times thinking about your strategy before sending in your first troop,
- If you are not the first to attack, watch replays of all previous attacks. Make sure to memorize:
- Location of traps
- Location of hidden tesla towers
- Composition of clan castle
- Go for the three stars. A one-star attack is almost useless, and a two-star attack is worth only 66% of a three star attack. Only go for the one-star if nothing else seems realistic.
- The clan castle almost certainly has troops in it. Probably a mix of archers and wizards.
- Check the range of the clan castle ahead of time, and plan how to draw the troops out.
- Giants and, to a lesser extent, hog riders, are extremely vulnerable to castle troops, because they do not fight back. Clear castle troops before sending them in, if possible.
- Make sure to draw out troops and kill them with either a lightening spell or archers/wizards (you'll probably need the equivalent of 20-30 housing spaces, in either archers or wizards, to demolish a 20-25 sized castle).
- If you draw out troops, try drawing them out to an area that's free of other defensive buildings.
- Make sure you drew out all troops: some will sometimes stay in. Better safe than sorry.
- If you are going to send in dragons or healers, it is probably a good idea to get rid of the air defenses using giants or hog riders first. Air defenses are extremely effective against flying troops. [This does not apply if you plan your attack taking into the air defenses into account and being OK with the flying troops having a limited life time.]
- Walls should be dealt with, if possible, by wall breakers and not keeping the giants there hacking at the wall. First, this is an inefficient use of the giants' hit points, and worse, this wastes a lot of time. Time is of the essence for getting all three stars.
- Send troops (somewhat) en-masse. Sending the archers or wizards one-by-one just lets the defensive buildings take them out one by one. Even better, send mass amounts of archers or wizards hidden behind giants to let giants soak up the pain while the archers take out buildings.
22 Oct 2014 3:52pm GMT
13 Oct 2014
As I wrap up my time with Stripe's Open Source Retreat, I have quite some things to be thankful for. (Also, I just always wanted to give a thank-you speech.) So here goes:
I am grateful to Glyph Lefkowitz, Ying Li, and Christopher Armstrong for their long-suffering patience and support. Thanks also to Allen Short, who coaxed work out of me when I badly needed to feel capable of it.
I would like to thank Jessica McKellar, for being generally and specifically brilliant, for teaching me how to be a meticulous manager, and for helping me find my things when I lost them in a scary building.
I am grateful to Stripe, for giving me a place to be. And the monitor. To all the people there who showed me where the good coffee is hidden: thank you! Thanks too to those who went climbing with me, pretended to not hear me when I said I wanted to stop, and patiently helped me improve.
Thanks to friends near and far - for helping me deal with dead things, for teaching me all about alligators and crocodiles, and for helping me pronounce words correctly.
I am grateful to the authors of the good books I steal phrases from.
And lastly, I am grateful to my family, for spoiling me always.
13 Oct 2014 10:54pm GMT
07 Oct 2014
I (along with about 6 million other people, according to the little statistics widget alongside it) just saw this rather heartbreaking post from Lennart Poettering.
I have not had much occasion to interact with Lennart personally, and (like many people) I have experienced bugs in the software he has written. I have been frustrated by those bugs. I may not have always been charitable in my descriptions of his software. I have, however, always assumed good faith on his part and been happy that he continues making valuable contributions to the free software ecosystem. I haven't felt the need to make that clear in the past because I thought it was understood.
Apparently, not only is it not understood, there is active hostility directed against his participation. There is constant, aggressive, bad-faith attempts to get him to stop working on the important problems he is working on.
Thank you for your work on GNOME, for working on the problem of getting free software into the hands of normal people.
Thank you for furthering the cause of free software by creating PulseAudio, so that we can at least attempt to allow users to play sound on their Linux computers from multiple applications simultaneously without writing tedious configuration files.
Thank you for your work on SystemD, attempting to bring modern system-startup and service-management practices to the widest possible free software audience.
Thank you, Lennart, for putting up with all these vile personal attacks while you have done all of these things. I know you could have walked away; I'm sure that at times, you wanted to. Thank you for staying anyway and continuing to do the good work that you've done.
While the abuse is what prompted me to write this, I should emphasize that my appreciation is real. As a long-time user of Linux both on the desktop and in the cloud, I know that my life has been made materially better by Lennart's work.
This shouldn't be read as an endorsement of any specific technical position that Mr. Poettering holds. The point is that it doesn't have to be: this isn't about whether he's right or not, it's about whether we can have the discussion about whether he's right in a calm, civil, technical manner. In fact I don't agree with all of his technical choices, but I'm not going to opine about that here, because he's putting in the work and I'm not, and he's fighting many battles for software freedom (most of them against our so-called "allies") that I haven't been involved in.
The fact that he felt the need to write an article on the hideous state of the free software community is as sad as it is predictable. As a guest on a podcast recently, I praised the Linux community's technical achievements while critiquing its poisonous culture. Now I wonder if "critiquing" is strong enough; I wonder if I should have given any praise at all. We should all condemn this kind of bilious ad-hominem persecution.
Today I am saying "thank you" to Lennart because the toxicity in our communities is not a vague, impersonal force that we can discuss academically. It is directed at specific individuals, in an attempt to curtail their participation. We need to show those targetted people, regardless of how high-profile they are, or whether they're paid for their work or not, that they are not alone, that they have our gratitude. It is bullying, pure and simple, and we should not allow it to stand.
Software is made out of feelings. If we intend to have any more free software, we need to respect and honor those feelings, and, frankly speaking, stop trying to make the people who give us that software feel like shit.
07 Oct 2014 8:32am GMT
25 Sep 2014
When I studied math in high-school, I absolutely hated geometry. It pretty much made me give up on math entirely, until I renewed my fascination in university. Geometry and I had a hate/disgust relationship since. I am putting it out there so if you want to blame me for being biased, hey, I just made your day easier.
But it made me question: why are we even teaching geometry? Unlike the ancient Egyptians, few of us will need to collect land taxes on rapidly changing land sizes. The usual answer is that geometry is used to teach the art of mathematical proofs. There are lemmas-upon-lemmas building up to interesting results. They show how mathematical rigor is achieved, and what it is useful for.
This is bullshit.
It is bullshit because there is an algorithm one can run to manufacture a proof for every true theorem, or a counter-example for every non-theorem. True, understanding how the algorithm works takes about two years of math undergrad studies. The hand-waving proof is here: first, build up the proof that real number pairs as points and equations of lines as lines obey the Euclidean axioms. Then show that the theory of real numbers is complete. Then show the theory of real numbers is quantifier-free. QED.
When we are teaching kids geometry, we are teaching them tricks to solve something, when an algorithm would do it at well. We are teaching them to be slightly-worse than computers.
The proof above is actually incorrect: Euclidean geometry is missing an axiom for it to work. (The axiom is "there is no line and a triangle such that the line intersects the triangle in exactly one edge".) Euclid missed it, as have generations after him, because geometry is visually seductive: it is hard to verify proofs formally when the drawings look "correct". Teaching kids rigor through geometry is teaching them something not even Euclid achieved!
Is there an alternative? I think there is. The theory of finite sets is a beautiful little gem of mathematics. The axioms are the classic ZF axioms, with the infinity axiom inverted ("every one-to-one function from a set to itself is onto"). One can start building the theory the same as building the ZF theory: proving that ordinals exist, building up simple sets and the like - and then introduce the infinity axiom and its inversion, show a tiny taste of the infinity side of the theory, and then introduce the "finiteness axiom", and show how you can build the natural numbers on top of it.
For the coup-de-grace, finite set theory gives a more natural language to talk about Godel's incompleteness theorem, showing that we cannot have an algorithm for deciding questions about finite sets - or the natural numbers.
Achieving rigor is much easier: one uses Venn diagrams as intuitions, but a formal derivation as proof. It's beautiful, it's nice, and it is the actual basis of all math.
25 Sep 2014 6:42pm GMT