There are many reasons it's a great time to be a developer.
One of them is because there are so many choices around data access and databases.
So this week, we take a tour with our guest, Jim Fulton,
of some of the databases you may not have heard of or haven't given a try yet.
You'll hear about the pure Python database, Zodb.
There's Zerodb, an end-to-end encrypted database
in which the database knows nothing about the data it's even storing.
And NewtDB, spanning the world of Zodb and JSON-friendly Postgres.
This is Talk by Thunderby, episode 105, recorded Thursday, March 16, 2017.
Developers, developers, developers, developers.
I'm a developer in many senses of the word
because I make these applications, but I also use these verbs to make this music.
I construct it line by line, just like when I'm coding another software design.
In both cases, it's about design patterns.
Anyone can get the job done.
It's the execution that matters.
I have many interests.
Sometimes...
Welcome to Talk Python to Me, a weekly podcast on Python,
the language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter, where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm
and follow the show on Twitter via at Talk Python.
This episode is brought to you interruption-free by GetStream.
That's right, GetStream, a new sponsor of the show,
has a really cool offer for you guys.
If you're building an application that has some form of activity stream
like you might see in Slack or Facebook or Instagram and others,
then you owe it to yourself to have a look at GetStream.
They provide scalable, reliable, and personalizable hosted API feeds as a service.
The feed is the most intensive component of these types of applications,
yet there's no need for you to reinvent the underlying feed technology
when GetStream has the infrastructure and a Python API already in place.
Go from zero to scalable feed in hours, not weeks or months.
They even use advanced machine learning to serve up personalized results to each and every user.
Stream powers the feeds for over 500 companies, including Makerspace and Fabric,
with a total of 70 million end users.
Try the API yourself in a short five-minute interactive tutorial at talkpython.fm/stream.
Be sure to create an account and try it for yourself.
It helps support the show.
Jim, welcome to Talk Python.
Thank you. It's nice to be here.
It's great to have you here.
We have a whole bunch of really cool topics generally around data, but not all data, right?
So we're going to talk about Zodb, something called ZeroDB,
which is something I'd never heard of and really interesting, actually.
NewtDB.
And then a little bit more process with some agile concepts and continuous integration and so on.
But of course, before we get to all those, let's start at the beginning.
What's your story?
How did you get into programming?
I was exposed to programming fairly young, although back then it wasn't very common or very accessible.
I'd say I really got hooked in grad school when I was doing research on rainfall runoff model calibration.
And I had to hack some alternate statistical techniques, calibration techniques, into a rainfall runoff model.
And I found that I enjoyed that quite a bit.
That became, for years, I was a civil engineer slash hydrologist.
And the software aspect of it kept pulling me and pulling me until it finally extracted me.
I think that's really interesting.
A lot of people get into programming that way and somewhat grudgingly like,
okay, I have to learn this programming thing to make whatever it is I'm doing actually work, right?
But I sort of went down that path myself to some degree.
And after a few years, I realized, actually, what am I doing this other stuff for?
This programming stuff is really great.
I'm just going to go do more of that.
And it's funny how life is sort of serendipitous like that.
But it's also good, right?
So was that original bit of work?
Was that in Python or was that in something else?
Oh, no.
That was in Fortran.
Oh, yeah.
Fortran.
I mean, I went through a lot of languages over my career.
That work was in 1981.
Okay.
So probably not Python.
Yeah, definitely not Python.
Because it was 10 years before it released.
But, yeah, I've used a lot of different languages.
I used Fortran for a long time.
I used PL1 for a little while.
I used ADA for a little while.
I really like OO languages.
I used – I couldn't afford Smalltalk for a long time.
So I used a language called Actor for a while.
And then much later, I did an interesting application with GNU Smalltalk, which was an adventure in and of itself because it was fledgling and the garbage collector was broken.
So I had to use a special branch with a non-broken garbage collector.
So anyway, I've had lots of fun with different languages over the years.
Yeah, that sounds like you've really been through a lot of them.
So are you doing mostly Python these days?
Yeah.
Although I did – a couple years ago at Zoap Corporation, we did a bunch of Android development.
I got to use Scala, which I really enjoyed.
I like to describe Scala as a beautiful evil language because it just invites so much abuse.
But it allows you to produce beautiful code within the JVM and just insane, mind-blowing notions of type-based development where you – people do interesting development tasks in the compiler.
Wow.
That sounds interesting and evil.
It was a lot of fun.
I haven't done any of that.
I did some Rust lately, which kind of reminded me of a lightweight version of that this last year.
Sure, sure.
Okay.
Yeah, I've been wanting to learn Rust, but I haven't really gotten into it.
I did look at Go recently this year, but I don't know.
I'm just not sold on Go.
I still like Python a lot better.
We'll see about that.
I'm actually very anti-Go.
Yeah.
I think it's bad on multiple levels, but I like Rust quite a bit.
Okay.
Well, that's interesting.
Maybe I'll be learning Rust eventually.
But what do you do day-to-day these days?
You're not still at the Zope Corporation doing Android development, right?
Nope.
At Zope, I did a ton of different things.
But towards the end, we were doing some Android development, among other things.
But these days, I'm splitting my time between paid work to sort of keep the lights on and
open source work.
I got an opportunity to work with a company called ZeroDB about a year ago.
That and also my sons are grown and they've moved away.
And so we were sort of downsizing.
So that was an opportunity to sort of have enough money and reduce my run rate and focus
on some open source stuff for a while.
And so that's really what I'm doing right now is paying attention to some open source
projects that have been neglected for a while, as well as exploring some new ideas.
That's really, really great.
And it must feel really good.
It must just be great to just stop, look at these projects that are pretty mature and say,
okay, I'm going to work on these things.
And I don't have to go to meetings.
I don't have to hit some silly deadline that's not realistic or work on some feature that I
think adds no value, right?
Just be able to focus on what you want, right?
Yep.
Yeah.
Excellent.
So we'll be touching on some of these projects, I'm sure.
So let's start with one of the older projects, I guess.
It's been around since 1996 with Zodb.
What is Zodb?
So Zodb is an object-oriented database for Python.
And when I say object-oriented, I contrast that with object-based because lots of people
refer to databases that are object-based that I don't really consider object-oriented.
The original goal of object-oriented databases, which were a pretty exciting thing back in
the, I don't know, late 80s, maybe early 90s, was to try to reduce or eliminate the impedance
mismatch between programming languages and databases.
So in databases, you know, you have a very different computational model than you do in a programming
language, especially some of the, you know, especially object-oriented programming languages.
Yeah.
You have hierarchies of object graphs in object-oriented languages, and you have highly
normalized data that work to minimize duplication and let you approach the data from any angle
you want.
But there's always this.
I pull it into Python and build it into an object graph, and then I tear it back into part
into all the other tables and put it back again, right?
So these object databases, they try to just say, let's keep them in the same shape, something
like that?
Well, again, I don't think there are many object-oriented, I don't know, I'm not sure I know of any object-oriented
databases today other than ZDV.
I mean, I'm sure there are some.
My sense is that a lot of the object-based languages let you get objects, but they don't necessarily
avoid having to do queries and doing assembly.
Like, for example, some databases referred to as object-based seem to be more like graph-based,
where you have the ability to query graphs, but it's still somewhat of a foreign object.
I see.
Like, when you use ZODB, there are some exceptions, but you have to subclass a special
base class, and you have to identify transaction boundaries, which that latter aspect is usually
automated, depending on your situation.
But beyond that, it's literally just as if you were working with objects in memory.
You don't really query a database.
You know, the way you query a database is the way you query something in Python.
You maybe look up a key in a mapping, or maybe you access an object's attribute.
Accessing an object's attribute might cause data to be loaded from the database, but that's
transparent to you.
Okay.
How interesting.
So does it use, like, interesting descriptors or something like that for attributes to do
that?
That's where the base class comes in.
So the base class, I can't remember.
There must be a meta class.
It's been so long since I've implemented it that I don't remember if there's a meta class
lurking.
I wouldn't be surprised if there was.
But basically, yeah, the base class does a couple of things.
I've actually had a project that I've wanted to do for some time, which is to get rid of
the base class.
I have some hacks in mind involving weak reference data structures.
But basically, the base class, it watches attribute accesses.
And so when you modify an attribute, it marks the object as dirty.
And when you access an attribute, if the object is something we call a ghost.
So in Zodb, when you first load an object from the database, typically by referencing it from
some other object, it's loaded as a ghost.
And then when you actually access an attribute, which includes any method, then the ghost is
activated and its state is loaded into memory.
I see.
There's an in-memory object cache that is effectively an incomplete database replica.
At transaction boundaries, any changes that have been made in the database by other clients
are then cause any objects that were affected that are in your cache to be invalidated.
And so then the next time you access them, they're loaded automatically.
So the data in memory is always consistent with the committed database as of some point in time.
Okay. Yeah. So you have transaction support and all those sorts of things as well.
That's pretty interesting.
So I can get an object from the database and pass it around.
And maybe it was passed off to some other module.
But eventually, that reference will be updated because someone committed a transaction.
Right.
The only sort of caveat there is that the data...
So when you access the database, you open a connection.
And on that connection is a root object.
And then all other accesses you make are from that root object, possibly through many steps.
And then there's an object cache associated with that connection.
And so that connection, its cache, can only be accessed by one thread at a time.
So you couldn't hand it off to a different process.
And you couldn't hand it off to another thread and have both threads operating on it.
But you can have multiple threads with their own database connections.
And they're essentially coordinating their activities via transaction commit.
Very much in the way that software transactional memory either was going to...
I'm not sure this is the current status, but I should have looked it up.
Much in the way that software transactional memory is supposed to do that for PyPy.
Interesting. Okay.
So I don't think I've talked about software transactional memory previously.
Maybe you could just give us the quick elevator pitch for what that is.
Well, it's like ZODB, but not persistent.
I see.
You know, there are lots of different sort of models for managing concurrency.
And so some of the traditional models like locking are very expensive.
And what a lot of systems have moved towards is something called the actor model, where you
have different independent actors and message queues.
And that's a model that works really well.
But of course, it's fairly invasive.
You have to architect your model or your application around that.
I think what the PyPy people were wanting to do was to get rid of the GIL and trying to find some way to get rid of the GIL without being crushed by all the locking overhead of managing concurrency.
So with transactions, you basically have multiple copies of the object space, possibly with shared and copy and write, etc.
I'm not really super familiar with either their implementation or their status.
But the idea is that you have basically different copies of memory.
Those copies get synchronized when you reach a transaction boundary.
And that means that at the transaction boundary, that's when you sync everything up.
And everything else is completely independent.
So you don't need any locks because you've only got one logical thread of control accessing the data.
Right.
And so that sounds really cool.
Like, basically, it's a very optimistic view of the world, right?
We're going to grab all this stuff in memory and we're going to try to make a bunch of changes.
And it's probably fine.
But if it's not fine, then we're actually going to have to retry that function or whatever that was working at it.
Right. So there's this instead of taking locks, it'll basically restart parts of your code, which is really quite a different way of thinking about solving this problem, isn't it?
It's how most modern databases work now.
I know Postgres uses multiversion concurrency control, which is basically the same idea.
I think Oracle does as well.
But yeah.
And so you sort of have to come to terms with what we call conflict errors.
Yeah.
You have to instead of being blocked, you have to deal with here's how I resolve it when something went wrong.
I mean, it's fine if it's all within one database or within your memory.
But if I've called two web services and written a file and then it says, no, no, roll back.
Right.
Well, now what, right?
Yep.
Already charged your credit card.
Roll back.
What are you talking about?
Yep.
So it's just a, yeah, it's interesting.
So would you call Zodb a NoSQL database?
I mean, was it NoSQL before NoSQL is a thing?
Well, one of the stories I like to tell about how I learned Python was I was at USGS and we were using this system called RANDRDB, which was based on an earlier system.
But basically it was based on managing relational data as flat files.
And since I stopped using that project, it sort of evolved and it called itself NoSQL because it didn't use SQL.
Right.
Really, NoSQL is a terrible name.
To me, in my mind, modern NoSQL databases have nothing to do with not having SQL.
Yes, I agree.
Some of them do have SQL.
You know, really the, the, a better characterization of the, most of the NoSQL databases that I'm familiar with is that they're no transaction.
And they're no transaction because transactions at some point do limit scalability.
Although there's, you know, continuing to be work to make databases like Oracle and Postgres scalable even with transactions.
But the NoSQL databases have much weaker notions of consistency and really are optimized to allow very fast writes.
And I, the sort of problem domain that I think they're really well suited to is collecting massive amounts of data that you collect and, and analyze, but never really have to update and aren't really part of any business processes.
Some kind of analytics or something.
Right.
And so, so in that sense, ZADB is not a NoSQL database, but it doesn't use SQL.
Although with Newt, you can, you can now start to leverage SQL in ZADB.
Yeah.
We'll talk about Newt as well.
Yeah.
I saw a really great quote by somebody who was trying to talk about NoSQL and said something like, my toaster doesn't use SQL.
Is it NoSQL?
No.
I'm a better definition.
And I really feel like, I feel like, like my definition and your definition are probably quite similar from what you said.
I feel like NoSQL databases are the ones that give up some relational features in order to be more scalable, possibly more horizontally scalable, things like that.
Right.
Like a lot of them give up joins.
A lot of them give up transactions, but not all of them.
Right.
They, they give up different things here and there for different things to optimizing.
I'm not aware of many, there was a foundation DB, which is no longer a thing that had transactions, but some databases will talk about atomicity, but their notion of atomicity is kind of laughable because, well, we update a single record atomically.
Yes, exactly.
But that's not really, I'm sure there's some NoSQL databases out there that are transactional, but if there are, they're probably not scalable the way that some of the other ones are.
I mean, I think that's, I, to me, in my mind, transactions are the big trade-off.
And I think it's a trade-off that most people don't really understand.
Yeah, I think you're probably right.
If I, if I think of them, the one, the thing they give up first is probably transactions.
The thing they give up second is probably joins.
Right.
I mean, MongoDB does have the isolated operator, which does let you work on multiple documents, but it's, it's not quite the same as, as this just global isolation level serializable that you get in a lot of relational databases.
Well, and in fact, the giving up joins is really closely related to that because giving up joins means that there are more problems for which only being able to do one operation at a time atomically makes sense.
Yep.
Absolutely.
Nice.
Okay.
So if I want to use ZeoDB, how do I get started?
Can I just pip install it?
Yep.
Okay.
What's it written at?
Is it written in Python?
Yep.
It has some C extensions.
It has some C extensions, but it also works with PyPy.
There's all of the C extensions have Python versions.
Right.
So if you run it with, if you run it with PyPy, then it'll, it'll use the Python versions.
And zeoDB.org has some pretty decent documentation.
I was, I was noticing yesterday that I, some topics that I need to add, but getting started is pretty easy.
You can run it with an in-memory database if you want, just while you're playing around.
Okay.
Yeah.
That's really nice.
Nice for testing as well, right?
Well, it's testing stories is especially strong.
ZeoDB has a, what I call a pluggable storage architecture.
So the, there's a defined API or set of APIs that storages can provide.
And then there are a bunch of different storage implementations ranging from an in-memory implementation to a, a file-based implementation to a client server implementation to, or to an implementation that sits on top of, well, there are a couple of client server implementations actually.
And then there's a implementation that sits on top of a relational database.
And then there are also, we sort of follow a pattern of, of layering those with adapters.
And so one of the interesting adapters for testing is something called the demo storage.
And with a demo storage, you have a demo storage, wraps two storages, a base storages, a storage and a changing storage.
Okay.
And so in testing, what you'll typically do is you'll have for a suite or a set of tests, you'll, you might set up a base database.
And then each test will use a demo storage on top of that.
And then, you know, whatever changes are made are made in the changes.
And then the demo storage is discarded.
And then next test creates a new one.
Oh, that's a really cool feature because one of the super painful things of testing is, well, how do I load up the test data?
How much is enough to be representative, et cetera, et cetera.
So you can put like, a snapshot on top of the data in a sense, right?
Basically.
And you can layer that as many levels deep as you want.
In fact, we've had, I've written Selenium tests where basically there were sort of push and pop operations on your database.
So you make some changes and then push another demo storage on top of that.
And then for, for staging, what, what, what we've often done was to, one of the, one of the layers, one of the layers you can add is something called a before storage.
And what it does is it wraps a, a, a, a writable storage, like our client server storage.
But it, it, it says, okay, only show me the data as of this point in time.
And then that becomes the base for a demo storage.
And then you have a file storage as your changes.
And now you can stage a large production database, make substantial changes to it, but it's all in, in, in this sort of layered snapshot.
So, which you can then discard after staging and it doesn't affect any of the actual production data.
Yeah, that's really cool.
Okay. So that sounds like the storage system is, is really robust there.
And of course that's going to play into zero DB when we get into it.
But let me ask you two quick questions on zero DB before we move on.
When is it a good idea to use zero DB?
Like what's the ideal use case for this?
I think a really good use time to use it is when you don't want to spend a lot of time writing software.
Yeah, sure.
So it makes writing software a lot easier in a lot of ways because you're, you're, again,
you've, you don't have that database impedance mismatch.
Does it store things in the basically pickled form or something to that effect?
Right.
Okay.
So you could just say, these are the things I want in the database, put them in the database
and they're the database, right?
As long as, as long as they're pickleable.
And we could or could not have a discussion about pickle.
Pickle, pickle, pickle has a bit of a bad reputation.
That's a little bit fudtastic.
Yeah, sure.
But, but anyway, yeah, it basically uses pickle.
So you can store anything that's pickleable.
All right.
Nice.
And you talked about the good testing story as well.
When should we not use Zodb?
You shouldn't use Zodb.
And I think this is changing actually, but.
Maybe it's being changed by things like NewtDB, right?
Well, it's being changed by, for example, when, when you, I think Newt, I think Newt can help
quite a bit.
Yeah.
Because Zodb can sit on top of say Postgres or Oracle, it can scale more or less as far
as they can scale.
Right.
Okay.
Traditionally, Zodb has managed its own, provided its own search facilities on the client side.
And so you, when you do that aggressively, you end up with lots of extra objects in the
database to support indexing.
So, so there are Zodb based implementations of B-trees.
And then on top of that, various sorts of indexes like inverted indexes and regular B-trees
indexes and things that are sort of like Postgres GIN indexes a little bit.
But that tends to bloat the database quite a bit and cause lots of extra rights and lots
of opportunities for conflicts.
So I've in the past sort of said, well, don't necessarily use, if your application is very
search intensive, then maybe you don't want to use Zodb.
If your application is sort of object intensive and, you know, you're, you're primarily working
on application objects and traversing application objects, then, then it's a much better fit.
But I think especially with Newt, by pushing the search back into the relational database,
it can greatly reduce some of the challenges.
And plus you just have a much more powerful search engine.
Sure.
So let's talk about NewtDB a little bit, then we'll come back to Zodb.
So Newt is kind of a marriage between Zodb, which we talked about a lot of the features
there.
And it's one of its shortcomings, I guess you could say, is it is really hard to query.
You talked about how your app is search intensive, then maybe you don't want to use it because
this is not really normalized.
It's not flat text and integers and stuff in columns, but it's object graphs as binary
stuff.
So doing that is challenging, but something like Postgres is really good at storing that
data and querying it.
So NewtDB, you called this the amphibious database, which I think is really interesting.
Right.
What is it?
Okay.
Well, I'd like to argue with your previous assertion, but let's, let's come back to that.
Which one is that?
Well, so in terms of searching, it's the issue isn't so much that the search capabilities
of Zodb catalogs, which is sort of the common pattern for this, are not really that different
from a lot of the NoSQL database search mechanisms.
In fact, a lot of the NoSQL mechanisms, even something like SQLAlchemy, to a fault, I think,
tries to express searches as data.
And so the catalog is often quite good at that.
In fact, if you're indexing data fits in memory, the search, the searching in Zodb, I mean, I've
seen it actually smoke Postgres.
Wow.
Okay.
But for larger databases where it's not all in memory, then, you know, Postgres ends up
being a win.
But it's not so much that it's hard to search, other than that you can't use SQL.
But I think most humans can't use SQL anyway.
Right.
But anyway, so the ease of search is debatable, but I think it's reasonable to expect that on
average, Postgres is going to do a lot better.
And so the reason I called Newt the amphibious database was that it sort of gives you two views
on your data.
It gives you a very Python-centric, object-oriented view on your data via Zodb.
One of the problems that traditional object-oriented databases have had in terms of what they've
been criticized for is that they're kind of closed.
They're limited to a single language.
And they may even depend very heavily on the classes.
I mean, that's the whole point is, you know, in Zodb, when you're storing objects, they're
objects that have specific classes.
And traditionally in Zodb, if you wanted to access the data, you had to have the class around.
So it's a little bit more of a restrictive environment.
Right.
So if I want to call it from like JavaScript, it's not going to be fun.
Right.
So what the idea is, is in Newt, you've got your regular OO Python view of your data.
And then you also have a Postgres view of your data.
And in Postgres, you can see your data as JSON.
You can access it from anything that can access JSON in Postgres.
So you could conceivably write reporting applications that reported against it.
You can index it and you can search it using PostgresQL.
Okay.
Interesting.
So basically it stores two copies of any given record and it keeps them in sync.
One pickled version and one JSON version.
And then you leverage the JSON capabilities of Postgres to work with that thing from other
languages.
Okay.
There's also sort of lurking around there some interesting patterns about synchronizing
your data.
So Newt has sort of two modes you can use it in.
It has the sort of default mode where it writes the JSON data as it's committing the transaction.
But there's also sort of asynchronous mode where you can run a separate updater process that
watches the database and generates the JSON asynchronously.
And one of the things I think that's interesting about that is that you can generalize that.
So you could, for example, eventually, instead of updating JSON in Postgres, you could update
an Elasticsearch database.
Or you could even conceivably asynchronously update a relational representation of the data.
Right.
Exactly.
Right now you're just taking it and turning it into JSON because it's such a close fit.
But theoretically, you could have a SQLAlchemy type representation as well.
Something to that effect, right?
So what flexibility does the Postgres add besides just other clients or other technologies?
Is there better searching?
Can I work with more data?
What's the story?
Postgres has a large community behind it.
So there are lots of people working on scaling Postgres in various ways.
So yes, I'm sure you can work with more data than you can with, say, the built-in client server
storage in Zodb.
Although there is a project called Neo where they're doing some interesting things in terms
of scaling database without Postgres.
But also, Postgres has this interesting model.
I don't know if Oracle does this, but in Postgres, when you create an index, you can index expressions
rather than indexing columns.
Okay.
And that gives you a lot of power.
So for example, if you're building a text index, you can have, instead of saying, I want to
index this column, you can say, well, here's a Postgres function, which could be written
in Postgres's stored procedure language, or it could conceivably be written in Python.
But here's a function that will extract the text from this data record.
And this function that's extracting the text from the data record could actually make queries
and get text from related data records.
We're actually using that in the project.
And then what happens is then you say, okay, now I want to build an index on this function.
And what happens is that at index time, it goes through the data and calls that function,
gets the result of that function, and builds the index based on that.
And so the function could be doing pretty interesting, possibly expensive things,
and none of that has to happen at search time.
It can all happen at index time.
Right.
Okay.
That's really interesting.
So basically, your inserts might get a little slower and your updates might get a little slower,
but it could be really worth it if it dramatically improves your query speed.
Something that came to mind, I was thinking, it's like, well, if you have, say, an email address,
you could index just the domain part of the email address.
I want to find everybody in this company, which has this google.com or whatever in there,
their email address, right?
Would something like that?
Absolutely.
Okay.
Absolutely.
Well, for example, I think most people index their, in Postgres, for example,
when you have a text column, and it's not a free text.
It's like a person's name or a city name or something like that.
I think most people tend to index those incorrectly because they index it based on,
just by creating an index on the column.
And A, there's a certain way that you build those indexes so that they're usable in like queries.
But also, if you want it to be able to search a case insensitively,
what you really need to do is you need to index calling lower on it.
Exactly.
Yeah.
I find that lowercase, lowercase or case insensitivity in a lot of databases can be really challenging
if you want to index the thing that has to be case insensitive, right?
You've got to maybe even change your schema a little bit,
like store the original and a lowercase version and put the index on the lowercase version
or something funky like that, right?
But you don't have to do that.
See, that's the beauty of this feature of Postgres.
And I have to be careful to say this feature of Postgres because I don't know that it's not
in other databases.
But this pattern of indexing expressions is wildly powerful.
And it's one of these things that people should zen up on because once you start thinking about
it that way, then lots of doors open up.
Yeah.
It sounds really powerful to me.
And I can certainly think of some places I would have used it had I had it available,
but I don't.
Another interesting example is that in a lot of applications that I work with, the data are
hierarchical.
Think of a content management system where the content is arranged hierarchically, possibly
by organization.
And there's often interesting security policies about what you can access based both on who
you are and where you are in the tree.
And so you can – and the most common – the sort of most common case is to ask, can you view
this document?
And so you can write a function that says, okay, for any particular piece of content, which
principles can view this document?
And then – and you can write a function that returns an array of principles that indexes that
document and then create something called the GIN index, which is basically an inverted index
that allows you to say, okay, here's a set of principles.
Can any of them view this document?
Where the set of principles may be the user and the groups that they're in.
Yeah.
And you basically can say, okay, can this set of principles access this particular record?
And that can be an index query, even though in order to make that decision, at some point
you have to walk the tree to find all the security assertions.
Excuse me, security assertions.
Yeah, yeah.
You can have sort of inherited security stuff that flows down the tree and use your little
function to build the index without actually putting on every single level.
Okay.
That sounds awesome.
All right.
So NewtDB is definitely an interesting project.
What's – how does its, like, ideal use case vary from, say, ZODB?
Well, it addresses two of the major objections to ZODB.
I would say the major objections to ZODB would be it's transactional, which I believe limits
scalability at some point, although, again, that limit is getting higher and higher all
the time.
But the other – and I actually think that's a limitation that most people should ignore.
But then I'd say the two biggest objections are the searchability and the overhead associated
with trying to support that and the complexity associated with trying to support that and access
from outside.
So people with ZODB databases, there's a temptation to feel like their data is imprisoned, especially
if you're not very familiar with the technology.
So Newt basically gives you – sort of makes the datable accessible without Python, without
any special skills.
It's just sort of sitting there in JSON.
You can search it using a much more powerful search mechanism.
Now, you still – you know, there's no free lunch.
So you can search it using clever tricks like indexing functions against the JSON, but you
have to learn how to do that.
And you have to understand how to use Postgres as explained so you can see how the query optimizer
is analyzing the query.
Sure.
That's a good thing to do anyway if you're working with data.
Know how to ask, are you using an index?
Which index are you using?
And so on.
Right.
But still, interesting.
Okay.
Can you update the JSON and have it update – those updates flow to the ZODB Python side?
Or is it read-only on the JSON and read-write on the ZODB side?
The latter.
Okay.
Yep.
The JSON is a read-only representation.
Gotcha.
Okay.
That seems pretty reasonable.
All right.
Very, very nice.
So let's come back and talk about ZODB.
So the ZODB stuff that you've been doing kind of led you to work with ZODB.
And they actually were the catalyst for a really cool move for you.
But let's start with just what is ZODB?
Well, so ZODB was about trying to have your data be encrypted at rest.
So the only client – so with ZODB, the goal was that only the database client, the applications would be able to unencrypt the data, would be able to access the data because the encryption would happen on the client.
Right.
There's different levels of encrypted at rest.
But you're talking about even encrypted in the memory of the database, and the database itself can't get it, right?
That's a different level than I've set up a file system where when I save the data finally to disk, that part is encrypted.
Like there's more to it than just that, right?
Well, not much more to it than that.
I mean, it was certainly encrypted in the memory of the database server.
So the database server itself couldn't see the data.
But by the time it reached the application, it was unencrypted in the application's memory.
Sure.
So they sell this – they position this as a really great database for the cloud because your data might live in the cloud.
But even if somebody were to get access to it and, you know, walk away with your virtual machine in some unknown way or even just log into the database server, potentially your data is still safe, right?
Right.
Okay.
That's pretty unique.
I don't really know a lot of other databases that have that.
And the fact that, you know, one of ZVDB's – I mean, a decision that I made a long time ago with ZVDB was that the search – basically all the sort of application logic would happen on the client, that the server was really dumb.
That was partly a reflection of my ability to write a smarter server.
But that actually, you know, fit ZeroDB's use cases really well because, you know, by doing everything on the client, only the client needs to have unencrypted data.
I see.
So basically the client or the application, even if it's like a web app, it has some kind of private key that it can decrypt its data with.
So how does it do queries and things like that?
In ZVDB, when you're – in doing a query the sort of the traditional way, you're accessing B-trees and higher-level facilities built on B-trees that are regular database objects just like any other object.
So they're encrypted.
They're part of your database.
So when you – let's say that you want to look up something in a B-tree.
What happens is you access the top of the B-tree and that gets loaded from the server.
And then you start walking the nodes of the B-tree to find the value you're looking from.
And those nodes get loaded from the server as necessary.
And then they're all cached locally.
I see.
Then the execution of the actual way of clause or whatever happens on the client.
And so you said it was the 0DB guys that made it possible for you to make this transition to sort of being independent, working on these open source projects and so on.
Yeah.
You want to tell us that story?
Well, I don't know that there's much to tell.
They needed some scalability help.
And also they didn't really have a lot of deep knowledge of Zodb.
So I could sort of provide a lot of help in terms of how they architect their application.
They funded – the sort of client-server part of Zodb was written a long, long time ago and it used async core.
And it really needed to be modernized for performance, for maintainability, and also to facilitate adding SSL support.
Sure.
And so they funded that along with a bunch of other work.
Nice.
And I saw they released 0DB on GitHub not too long ago.
So that's pretty cool.
They've really sort of switched gears.
In fact, I think they've renamed the company.
So I don't think that the project of 0DB on top of Zodb – I don't think it's actually active at this point.
Okay.
Their customers were banks and that sort of financial people.
And so having a Python database wasn't really all that interesting to them.
Sure.
And so they've changed their focus towards dealing with big data.
And I don't really know all the details, but basically it's the same sort of thing.
Your data is encrypted at rest, but while you're processing it, then it's encrypted in the processing pipelines.
Sure.
Okay.
I see maybe they've changed the underlying storage engine, but the general idea is still probably more or less the same.
There's three databases that are probably not super familiar to people.
Four if you count Postgres, but that one's more familiar to folks.
I think it's really interesting to look at all these different tradeoffs and study the different databases.
It gives you a sense for what the value of the tradeoffs are, right?
Yep.
Yeah.
Cool.
All right.
So let's switch gears just a little bit towards the process side of things and talk about two projects that you're working on.
One, a tool for continuous integration like things, and one that's more about Kanban type stuff.
So first one I want to talk about is Buildout.
So this is an automation tool written in and extended with Python.
So is this a continuous integration server, or is this more than that, or what is Buildout?
It's something different than that.
So it's really about, let's say you want to work on a Python project.
So you check out the code, and now you want to actually run stuff.
And so for a lot of people, what they do is there's a requirements text file sitting around.
Maybe they create a virtual ENV, and then they run pip against that requirements.txt file.
Or sadly, what many people will do is they'll just run pip from their machine's system Python
and install a bunch of things in there, and then they'll have things in there.
And then they'll run whatever scripts are generated.
And if the scripts need configuration files, well, maybe they'll write them,
and they'll check them into version control.
And if they need extra processes on top of that, it's sort of outside the realm of pip.
And then the question is, well, what do you do to automate all of that?
And so Buildout, you know, when we were working on projects many years ago at Zoop Corporation,
we would, and this was actually before there was even distutils,
we were in a mode for a while of creating applications for customers.
And then the customers would run them on their machines,
and their environments were totally different.
Their environments were typically completely uncontrolled,
and usually bad things would happen.
And so we needed to automate that.
And in those days, the automation typically involved building Python from source
because most people's Python environments are in an unpredictable state.
Okay.
So you would get like some well-known version and download it and compile it and say,
we're going to start from here?
Well, not just, the biggest problem isn't the well-known version,
although that certainly is part of it, but the contents of site packages.
Right. Okay.
Over the years, that evolved.
And so Buildout was very much geared towards installing exactly the packages you need
and then generating the artifacts around that.
So, for example, I have a project related to the Kanban where the JavaScript client is significant,
and I need to assemble all those artifacts.
And I, maybe I'm old-fashioned, but it offends me to check them into version control.
Yeah.
I have a Buildout configuration that among the things it does is it runs Grunt to,
what is it Grunt or, I forget what it runs, maybe Grub.
It runs some JavaScript tools to assemble all the JavaScript requirements.
And, of course, it uses Buildout's own mechanisms to assemble the Python requirements.
It generates configuration files that something like PaceScript would need to use.
It generates daemon configs.
So, for example, when I run the process, I usually don't run it in the foreground.
I mean, I may, but I may want to run it in the background.
And so there's a tool called zdaemon, which is kind of like SupervisorD, but a little bit more.
Okay.
A bit simpler.
And so that has a configuration file.
Or if you're using Supervisor, you would want to have a Supervisor configuration file.
And those files may depend on things that are specific to your environment.
They might depend on, you know, files that are outside the environment that have paths in them.
I mean, there are all sorts of reasons why you may not be able to have static configurations that are just checked in.
Right.
Okay.
So Buildout will look at the system, look at all the requirements, and put it together in just the way needed for that location, huh?
That's one way of putting it.
Basically, with Buildout, you give it a single configuration file that represents all of the parts of what you're trying to deploy, whether you're trying to deploy to production or to CI or staging or to production.
And it basically says, okay, I've got all these parts that I need to build, and it just basically builds them.
And it also keeps track of what it's built so that it can unbuild them.
And, like, if a part specification changes, it knows to uninstall what it did before and then reinstall it.
Okay.
That's really cool.
How much of this is a general software assembly tool and how much of this is for Python projects?
Like, could I work on a C++ project only with Buildout?
You could.
And there are people using Buildout in non-Python environments, but the vast majority is Python.
Right.
Because it's written in Python.
People, Python folks are automatically attracted, you know, disproportionately to it.
Right.
And, of course, it has built-in support for assembling Python applications in a particular way that's interesting.
Right.
Okay.
There's a project called SlapOS, which seeks to be a lightweight virtualization environment that's built on top of...
Buildout.
And the things that they deploy in that environment, the vast majority of them are not Python.
All right.
Yeah, that sounds really interesting.
Cool.
One of the comments you made on the page is that software deployment should be highly automated and really should be able to, like, run one or two commands and just you're ready to go.
And I feel like the more of that that we can do, the better.
The more frequently we're at least smaller versions because it's not such a challenge for people to get the new version and all sorts of stuff.
So I think that's a great philosophy there.
And I think that the sort of DevOps movement has kind of gotten stalled in too much of an ops rut.
So I see way too little automation in a lot of things that I see.
At Zone Corporation, we had things to the point where basically we had a representation of our system as a tree that we stored in Zookeeper.
Each service was, you know, anywhere from two or three to ten lines of very high-level specification.
And then we had textual models of our entire system for multiple customers and multiple services and multiple applications and how they interconnected.
And when we wanted to deploy a change, all we did was modify that tree and check it into Git.
That's really cool.
And a few minutes later, it would be deployed.
Yeah, that's the way it should be, right?
Definitely the way it should be.
Cool.
Okay, so let's talk about your final project called Two-Tiered Kanban.
So I suspect most people know what Kanban is, but maybe you just give us the elevator pitch and then we can talk about the two-tiered version.
Sure.
The compelling thing about, well, there's sort of two compelling things about Kanban.
And one is sort of philosophical, which is that it's very focused on providing value as quickly as possible.
Whereas in contrast to something like Scrum that I think focuses on doing work.
Sure.
So the concept of providing value as quickly as possible.
We sort of grew this culture at Zove Corporation both as part of trying to be better software developers as well as trying to follow some lean startup kinds of ideas.
Part of that was related to the fact that we could develop software and check it into Git, but until it was actually in front of customers, it wasn't really providing any value.
And then the other part of it is really sort of old-fashioned common sense of finish what you start, which Kanban has the highfalutin term of work in progress, limiting work in progress.
But that's just a fancy-pants way of saying finish what you start before you start something else.
Right.
Don't put more stuff on the board.
Yeah.
Get it to the end.
Right.
Then you put something on the board, right?
This is kind of like Trello boards if people haven't seen the Kanban boards, right?
You've got the columns.
You move the cards from left to right, like from planned to assigned to in-dev and test, whatever.
But you said that, or the project says, that typical Kanban boards focus on development.
And products don't, just because they've had development done on them, don't provide value.
They provide value in features, land, and customers' hands, hopefully through a single button press to deploy them, right?
And actually, when we started doing this, we were nowhere near a single button press.
So being able to track things beyond development was actually pretty valuable.
And often, even with a single button press, there are things that you have to do.
Like, for example, if your schema changes, you may have to migrate the schema, and you might have to do that before the software is deployed, and there are things.
But I'd put it a slightly different way.
So a traditional Trello board or a traditional Kanban board, or even a Scrum board, you have all these trees sitting on the board, but you can't really see the forest.
Scrum addresses that a little bit through Sprint.
So perhaps in a Sprint, you're all focused on a single goal, which is good.
But whereas, you know, the problem with Kanban is it's always been just sort of this sea of separate tasks, and it's hard to know how they relate, and it's hard to know how they relate to value.
This idea of two-tier Kanban, which, you know, I read about as I was learning about Kanban, but have to this date never really found an implementation of, although I've heard rumors of implementations.
The basic idea of a two-tier Kanban is that you have a high-level Kanban that represents units of value, typically, you know, features.
Right.
Where a feature may require a number of development tasks, and ideally as few as possible, but sometimes, for example, there might be a new feature that requires lots of UI components, and then lots more sort of below the waterline.
Right.
Like the designer work, the database work, the APIs to make it go, the data, the backup, the management.
There can be many things, right?
Right.
Of course.
So the idea is that you want to be able to have – you want to be able to represent the feature as a whole, the value as a whole, and really focus on moving that value to completion and getting the benefit of it.
But you also need to be able to manage the things that make that up.
And so you have this high tier, which is the features, and then the low tier, which is, you know, once you've entered development, all the things you need to do to actually, you know, implement that feature.
And so typically what you have is you have a board where you have features that move across various columns, and then they hit the development column, and then they explode into the various pieces that make up that feature.
Okay.
And each – yeah, each one of the things that moves down the board that is a feature, that's basically its own Kanban board as well, right?
Essentially, yeah.
Yeah.
Okay.
That's the two-tier part.
Yeah, it sounds really valuable to me.
I always find these hierarchical things in Scrum or in Kanban really hard to deal with, like, okay, well, this feature costs this much, but the thing I'm working on actually costs this other thing, and someone else has to work on the data part of it, and they need to estimate that.
And just, you know, it's challenging to represent those.
So this seems like a nice way to organize it.
And it provides a little bit of automation around that.
I mean, you know, most Kanban people will sort of poo-poo estimation.
And I've been around enough people who needed estimates to know that you can't sort of completely punt on that.
But I really am a fan of really low-rent estimation and then automation to track the low-rent estimates and basically keeping the process really simple.
I've been exposed to some environments, some Scrum environments where, and I think this is actually the norm, is that people sort of go through a bunch of motions, and there's a lot of ceremony.
And a heck of a lot of time gets sucked up in ceremony.
Right.
Yep.
I've seen it as well.
Okay, cool.
So we'll definitely include a link.
And the link goes to a GitHub project that looks like it is executable code.
What do you actually get when you go to that GitHub repo?
Well, you get – right now you get a substantial amount of bit rot.
Okay.
But that's why I need to – I want to get back to it.
Some of the bit rot is because initially I punted on authentication and used Persona, Mozilla Persona Project, which actually worked really well, but it relied on Mozilla doing a bunch of work.
And they finally got tired of doing that work.
And so they've – they no longer run that service.
And so I have to go back and –
That's a challenge for your authentication and identity management.
Yeah.
So my – I need to go back and I want to add hooks to be able to use things like – I don't really want to manage – I don't really particularly want to manage usernames and passwords.
So I want to be able to work with like Google Auth and various others, you know, Facebook Auth, et cetera, and let people choose that.
Some other bit rot that I've sort of got is that it was written for Zodb 4 and Zodb 5 changed in ways.
There's actually discussion on the Zodb list right now about – I don't know if you're familiar with RethinkDB.
Yeah.
But so there's this idea of having data pushed to you.
And that's actually how Zodb works under the hood.
But that's never really been exposed.
Right.
With the transaction commits and sort of refreshing the objects people have memory, right?
Yeah.
Right.
So when you use a number of the Zodb storages, when a transaction commits, then the IDs of all the objects that were modified are pushed to all of the other clients.
And they're invalidated.
So there's already interesting information being pushed to clients.
But that's never really been surfaced at the application level.
And in Zodb 4, it was really easy with a small monkey patch to get at that.
And the Kanban relied on that.
But now in Zodb 5, that's no longer possible.
So I'm in the process of adding that feature to Zodb 5, adding it as an official feature.
Yeah.
That's the way to do it anyway, right?
Officially?
Yeah.
Right.
Well, the Kanban has been – the original version that we used at Zope Corporation was actually a client server thing on top of the Asana API.
And so the one that we used there was built on top of Asana.
And Asana's API became really, really slow.
They, too, got tired of providing an expensive service for free.
Yeah.
We'll run on this one $10 server over there.
Exactly.
So since that, it's been kind of an R&D side project.
And I'd like to really push it to completion and maybe even try to offer some sort of – offer it as a service.
Because I wouldn't care so much, especially my last job, which the company was a great company, but they really struggled with process.
And I think they would have liked to have used the Kanban, but it wasn't quite ready.
And that was really frustrating for them and for me.
So I'd like to soon take some time to actually get it much closer to completion.
Yeah.
It sounds like a great software-as-a-service type thing.
So hopefully you can do that.
All right.
Very cool.
Well, it looks like we should probably leave it there.
We've covered a lot of ground on this episode, but we're pretty much out of time.
So before we move on, let me ask you two final questions.
We now have over 100,000 packages on PyPI, so hooray for that.
And there's many that I'm sure you've come across that are noteworthy, that are not necessarily the most popular, but would be really cool to find out about.
So what one would you like to recommend people look into?
Well, it really depends.
I mean, obviously it depends on what you do.
But Bodo has delighted me over the years whenever I've had to touch AWS.
So I'm a big fan of Bodo.
Yeah, I use Bodo as well.
I'm also a huge fan of Mach.
Right.
Okay.
I think he did a really nice job of balancing dynamism and functionality.
I could go on and on, but those are a couple that sort of come to mind.
And of course, Zodb.
Of course.
Yeah.
And NutDB as well, right?
Very nice.
Okay, cool.
So thanks for that.
And finally, when you write some Python code, what editor do you open up?
Emacs, of course.
Emacs.
All right.
Right on.
That's definitely a popular one.
I'm giving a webinar next week on PyCharm.
And I have to say, I'm actually pretty impressed with PyCharm.
I like the, you know, as a straight text editor, I still like Emacs a lot.
But they really assemble a nice package of things along with that, like, you know, database access and REST clients.
And it's an interesting pile of functionality.
Yeah, absolutely.
And when you give that one, maybe if they have it recorded by the time we release this, we can put the link to your webcast in there.
That'd be cool.
Okay.
Awesome.
All right.
Well, that all sounds great.
Any final call to action for the listeners?
Anything you want them to check out or do?
Learn about transactions and then check out Newt.
I'll definitely have Newt, DB, and all the other ones in the show notes so people should be able to get right to them.
Cool.
Yeah.
Jim, thank you for being on the show.
It's been great to learn about all these different projects with you.
Thank you for having me.
You bet.
Bye.
This has been another episode of Talk Python to Me.
Our guest on this episode has been Jim Fulton.
And this episode is brought to you by GetStream.
If you're building an app with a feed, make sure to check out GetStream at talkpython.fm/stream.
They have the intelligent, scalable, and tested feed API you need to be one step closer to launching your app.
Are you or a colleague trying to learn Python?
Have you tried books and videos that just left you bored by covering topics point by point?
Well, check out my online course, Python Jumpstart, by building 10 apps at talkpython.fm/course to experience a more engaging way to learn Python.
And if you're looking for something a little more advanced, try my WritePythonic code course at talkpython.fm/pythonic.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
Corey just recently started selling his tracks on iTunes, so I recommend you check it out at talkpython.fm/music.
You can browse his tracks he has for sale on iTunes and listen to the full-length version of the theme song.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Smix, let's get out of here.
Smix.
I'll pass the mic back to who rocked it best.
you