Over the past few months, in my (nonexistent) spare time, I've been playing around with Go, the Google backed language created by some of my programming heroes. At this point, it feels to me like a cross between a much nicer C and a bit stricter (in a good way) Python. After you get past all the language niceties, the ultimate trade-off versus an interpreted language like Python is static typing for speed and increased type safety. And that's something I'm at least willing to explore.
Rather than an information-laden article, this post is a real question about a situation I'm currently in and need help with. The setup is simple: I have a project (sandman) on GitHub with a reasonably long commit history and list of contributors. I've re-written the project from scratch. It shares no git history with the original project. How do I make the new project the official version (without offending those who contributed to the original one)?
As I see it, I have three choices. The first is just to delete the old repo, rename the new repo, and call it a day. None of the old project will be preserved. On a positive note, however, the commit history will be clean and accurate, and reflect exactly what work was done on the project.
Or I could "migrate" the old project to the new one, by simply adding the new files in the old repo and deleting any others that are no longer used (almost all of the old files). In this way, I keep the commit history and contributors of the original project, but at the cost of a weird history that doesn't make much sense. It would really be the history of two separate projects spliced together at a specific point.
The third choice, of course, is to just keep the old project the way it is and not use the rewrite. Each day that goes by, though, this seems less and less viable a solution, as the new project is almost at feature parity with the old. That brings me to another question:
Versioning and Backwards Incompatibility
How do I version the new project? The old project never hit 1.0 and thus it
could be argued the API was always open to breaking changes, but this isn't a
change to the API, it's an entirely new and different API. The current version
sandman is something like
0.9.8. If I replaced the old project with the
new one, what would the version be? Keep in mind that for PyPI, the version
would need to be higher than the version of the old project for PyPI to
consider the new package the latest version.
I'm really kind of stuck here, which is why I'm asking for help. My hope is someone much smarter than me sees another solution, or a better way to implement one of the ones I mentioned. So please, if you have any ideas, let me know! Feel free to either leave a comment here or in the thread on Chat For Smart People.
sandman is by far my most popular
project. I think there's a good reason for that: it does something genuinely
useful. Ever had to deal with a legacy database through some awful system or
sandman auto-magically creates a fully RESTful API service for your
legacy database without you needing to write a line of code. You simply enter
the connection details for your database at the command line, hit enter, and
"hello REST API!".
That's all great, but what about the code that powers it? I'll be the first to
sandman, while well-tested and well-documented, is implemented in a
bit of a crazy way. The reason for this is a combination of my limited knowledge
(at the time) of SQLAlchemy and a few shortcomings in SQLAlchemy's reflection
capabilities. I had to do some code gymnastics to get it all working properly.
But SQLAlchemy released a new major version (0.9) with a new, if
under-publicized, feature called "automapping". This is as perfect a fit for
sandman as it sounds: you can use it to automatically create classes based on
reflected database tables. Once I saw this, I instantly realized this could be a
boon to simplifying
sandman. Still, though, I hadn't been writing REST APIs
for very long and didn't have a great handle on how to generalize things enough
to properly make use of
That changed in the past few months, though, and in the back of my mind I began
to hear the siren's song calling me to rewrite
sandman from scratch. The
problem, though, was the original
sandman worked. It worked due to awesome
people entering Issues on GitHub and me feeling bad that my baby had problems
sandman baby. Not Alex, my real baby, who is perfect). I didn't want to
lose all the work I had put into
Finally, yesterday, I decided to pull the trigger and see just how small I could
sandman. As it seems to be the most used feature, I decided to focus just
on the case where the user wants
sandman to reflect all of their database
tables and doesn't want to customize anything. How quickly, and in how many
lines of code, could it be done?
The preparation for my talk on Monday at the Wharton Web Conference got me thinking a lot about the impedance mismatch between web frameworks and REST APIs. The more you develop REST APIs with frameworks like Django or Flask, the more clear it is that something is amiss. It's a subtle feeling of needing to fight against the grain to accomplish your goal.
Which of course led me down another rabbit hole: server-side web frameworks in general. There are two things they pretty much suck at right now: helping you write REST APIs and supporting bidirectional communication over things like WebSockets.
A year ago yesterday, I made my first commit to what would eventually become
sandman ( official homepage ).
It remains my most popular Python project by a wide margin. Why? Because it solves
a real problem that I've faced many times. July 14, 2013 was just the day I
decided to do something about it. And so, as I sit in my hotel at the University
of Pennsylvania writing this post, preparing to give a 90 minute talk on Python,
REST APIs, and
sandman, I'm struck by how far the project has come in a year
and the effect it has had on me.