惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
WordPress大学
WordPress大学
博客园 - 叶小钗
B
Blog RSS Feed
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
B
Blog
V
V2EX
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives
雷峰网
雷峰网
The Register - Security
The Register - Security
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
H
Hackread – Cybersecurity News, Data Breaches, AI and More
U
Unit 42
Security Latest
Security Latest
NISL@THU
NISL@THU
腾讯CDC
S
SegmentFault 最新的问题
小众软件
小众软件
The GitHub Blog
The GitHub Blog
月光博客
月光博客
A
Arctic Wolf
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
Netflix TechBlog - Medium
IT之家
IT之家
D
DataBreaches.Net
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
J
Java Code Geeks
TaoSecurity Blog
TaoSecurity Blog
P
Privacy International News Feed

Secret Weblog

Becoming More Xee: A Modern XPath and XSLT Engine in Rust Looking for new challenges! Repeat Yourself, A Bit The Curious Case of Quentell The Humble For Loop in Rust The Humble For Loop in JavaScript Don Question Best Practices I Was a 1980s Teenage Programmer Part 5: Achieving Assembly I Was a 1980s Teenage Programmer Part 4: The Call of Assembly The Tooling Shift I Was a 1980s Teenage Programmer Part 3: MSX-2 JavaScript: when you need two ways to do it! Empowering Programming Languages Bloat and Retrofuturism Refreshing my Blog Again Random Rust Impressions Apilar: An Alife System I Was a 1980s Teenage Programmer Part 2: Olivetti M24 I Was a 1980s Teenage Programmer: the Alphatronic SolidJS fits my brain Is premature optimization the root of all evil? Framework Patterns: JavaScript edition Roll Your Own Frameworks Framework Patterns Secret Weblog Highlights Refactoring to Multiple Exit Points mstform: a form library for mobx-state-tree Seven Years: A Very Personal History of the Web Morepath 0.16 released! Is Morepath Fast Yet? Introducing Bob Strongpinion Punctuated Equilibrium in Software Morepath 0.15 released! Impressions of React Europe 2016 Morepath 0.14 released! Morepath 0.13 now with Dectate Dectate: advanced configuration for Python code JavaScript Dependencies Revisited: An Example Project The Incredible Drifting Cyber A Brief History of Reselect The Emerging GraphQL Python stack Thoughts about React Europe Build a better batching UI with Morepath and Jinja2 GraphQL and REST Server Templating in Morepath 0.10 10 reasons to check out the Morepath web framework in 2015 A Review of the Web and how Morepath fits in Morepath 0.9 released! Better REST with Morepath 0.8 Morepath 0.7: new inter-app linking They say something I don Life at the Boundaries: Conversion and Validation BowerStatic 0.4 released! Morepath 0.6 released! Morepath 0.5(.1) and friends released! New HTTP 1.1 RFCs versus WSGI Against On Naming In Open Source My visit to EuroPython 2014 Morepath 0.4.1 released (with Python 3 fixes) Morepath 0.4 and breaking changes Announcing BowerStatic Morepath 0.3 released! Morepath 0.2 Morepath Python 3 support The Call of Python 2.8 Morepath 0.1 released! WebOb and Werkzeug compared Morepath: from Werkzeug to WebOb Racing the Morepath: SQLAlchemy Integration The Centre Cannot Hold Breaking Morepath Changes Morepath Update How to do REST with Morepath Morepath Security the Gravity of Python 2 #python2.8 discussion channel on freenode Alex Gaynor on Python 3 Morepath Documentation Starting to Take Shape Back to the Center Morepath App Reuse Implementing Grok Grok: the Idea Why Linux Works for Me On the Morepath Reg, Now With More Generic! The New Zope as a Web Framework Jim Fulton, Zope Architect Object Publishing The Weirdness of Zope The Rise of Zope My Exit from Zope Reg: Component Architecture Reimagined JSConf EU 2013 impressions Obviel 1.0! JS Dependency Tools Redux Obviel 1.0rc1 released! Succinct data structures
Renewing Zope
Martijn Faassen · 2013-10-24 · via Secret Weblog

Introduction

The Zope community in late 2001 had been around for a few years already, almost an eternity in web time back then. Still, we weren't afraid to do bold new things. Perhaps too bold, as we'll see.

Zope Rewrite

We were learning new, better ways to do web development. Led by Jim Fulton, lead architect of Zope, we set out to rewrite Zope, fix mistakes, explore new innovations, make Zope cleaner, easier, and more powerful. I say we now, as by that time I and many others were fully engaged in this project to build its next generation.

One way that this engagement was fostered was by sprints. The Zope community pioneered the sprints now widely adopted in the Python community; we would gather together in real life to work on the new Zope. At such a sprint you would often find yourself working with Jim Fulton himself, so they were quite the draw.

In the new Zope, we would have more powerful and more clean extensibility and reuse mechanisms. Zope components would be developed as normal Python packages. We would do away with the weird magic of acquisition. We would make the glueing together of components into applications an explicit, coherent notion instead of a collection of ad-hoc APIs.

Central to this was the Zope Component Architecture, which introduced the notion of an explicit interface, along with a way to register and look up components that would enrich models (we called them views and adapters). It could also fulfill the role of a service locator, and provided the basis for an event system.

Besides sprint-driven development we were also early adopters of strongly test-driven development.

This exciting renewal of Zope was done as a complete rewrite. That's scary; rewrites have a habit of never being completed, and you risk the second system effect. But in many ways we succeeded -- we had a capable, very powerful and much cleaner web framework in the new Zope. (There were flaws, as it was not easier, just difficult in new ways, but I'll go into that later.)

So we had an exciting new Zope. We had a practical problem, however. Almost all of the real work done with Zope was done with the old Zope. This new, better Zope was held up as the future, but was tantalizingly out of reach for those of us with large codebases built on top of the old Zope.

Five: Redefining Zope

I've written a lot of code over the years, some of it generally useful, most of it not. But I believe some of my biggest contributions to Zope were not in the form of code, but projects that helped redefine what Zope was all about, giving people new ways to use it, and giving the project new directions.

The first such redefinition I attempted was Five, a name I came up with by adding together the version numbers of the old Zope (2) and the new (3). It was cute, and stuck in people's mind, and such things can matter.

The new Zope was out of reach to users of the old Zope. The community had been led to believe that the new Zope would be the next Zope. We thought that at some point in the nebulous future there would be a transition to the next system, some form of compatibility, some way to transfer code from the old to the new system. How this would work was left unspecified.

I grew doubtful about whether it would work at all. It was in the future and seemed to stay there. And I wanted to use the new stuff.

So in 2004 I took a different approach. I worked out a way to add the code of the new Zope to the old, using the new Zope as a library, extending the old Zope: Five. Through Five, the new ways of developing became available in the old system. We could use the new Zope, right then and there, in the context of the old Zope. We could use the better ways of doing things without giving up our existing codebases.

By 2006 the Five technology was merged into the core of the old Zope: Five became an integral part of it. Finally in 2009 we fixed the confusing, now deceitful naming, which was still suggesting after all these years that Zope 3, the new Zope, was the next Zope, which it was not. We let the new Zope evaporate into a puff of libraries. The next Zope was no more; there was just Zope. Its code lives on, in the old Zope, and various successor frameworks.

The Wisdom of Hindsight

Was the Five solution ideal? It was not. It made the old Zope more complex. While code written in the new way was more clean and maintainable, we didn't gain all of the cleanliness, because the old stuff was still there. The transition from old to new ways of doing things would be a very long one. The Plone developers, for instance, adopted the new ways many years ago, but are only now finally able to remove some of the old ways from the next version of their CMS.

Should we have done things differently? In retrospect, we should perhaps not have created the new Zope at all. Instead we could have embarked on a project to renew the old Zope from within, directly. That would have been very difficult as well, though. We might have missed out on something too. A clean slate, after all, lets you take a step back from what you're doing, and helps you think things through more clearly. We benefited from that as well.

The new Zope project was flawed, and the approach to merge it into the old Zope generated difficulty as well as opportunity. But through these projects Zope did continue to evolve, renew itself, and stay relevant.

This blog entry is a part of a series on Zope and my involvement with it. Previous. Next.

Chris McDonough

Maybe as much as second-system effect, I suspect poor distribution factoring played a role in the the not-better-ness of Zope 3. It was laudable to try to break it up into bits, but the actual breaking up was done incredibly poorly given the resulting dependency graph of the pieces. Only things like the ZCA and ZODB and a handful of utility packages like zope.deprecation were actually useful outside the big ball of dependencies. The rest of the stuff was broken up very mechanically in 2001, and a good number of distributions in the zope-dot namespace had (and still have) transitive dependencies on basically every other zope-dot distribution. This signifies, to me at least, that they probably should have been left as one big distribution, at least until the truly reusable bits fell out. Breaking them out without considering whether the bits being broken out were actually reusable added to the toolchain and release burden (the "KGS" was of outsized importance). It eventually made Zope-the-web-framework irrelevant by turning us into packaging accountants instead of programmers for a good number of years, while other frameworks just ignored packaging almost entirely and focused on creating software.

The number of zope-dot distributions that are truly reusable vs. the total number of zope-dot distributions is still tiny. An otherwise uninterested party can make zero sense of why e.g. https://pypi.python.org/pyp... exists as its own thing, because it's plain just not sensible for it to exist outside of some larger whole. This led to a lot of confusion and mistrust, because Zope 3 was supposed to be this tightly-factored thing made up of small parts, but in reality it was not; with some notable exceptions, the distributions it was split up into were not factored well enough for someone who didn't want to swallow a bunch of other distributions (sometimes dozens) too. So it just became easier for people to ignore zope-things than to try to figure out which parts were useful by themselves and which parts weren't.

What I think we learned as a community from that is that if something doesn't actually have a life of its own (e.g. its own docs, its own set of users who are interested in this particular part, but might not be interested in some other part of the system) it should either a) not be released or b) be kept as part of a larger whole that has its own identity. And although the specific factoring was largely a failure, the exercise of actually doing the distribution splitting did end up really helping the Python packaging story, if only for being an early adopter of setuptools.

Martijn Faassen

I agree that the factoring of Zope 3 into sub-packages was bad. Splitting it up into independent packages around 2006 in some ways made things worse, though it did make the bad factoring more clear. I agree that you should only split stuff off when it looks like this thing can have an identity on its own.

The transitive dependency issue of each zope._ package on the rest of zope._ hairball was solved back in 2009, actually. After that we could finally dump the useless Zope 3 ZMI code, for instance. Pushing for that refactoring was one of my last contributions to Zope. It succeeded but didn't open up Zope for further development as I'd wished. By then it was far too late.

Packaging accountancy was a distraction, but I don't think it was the primary cause of stagnation. I think that was broken decision making: we couldn't agree on doing new stuff anymore. To do innovation we had go around Zope, not through it - see Grok or Repoze for instance. Package accountancy was one of the last things we could find common ground on, because it was boring, so it still happened. You still see such maintenance common ground in upgrading various libraries to be Python 3 compatible today.

Chris McDonough

That's a good theory.

We should probably treat PyPI more like a retail store than a warehouse these days, and we probably should have been for years.

Possibly internally the packaging dependency hairball bust-up was solved for some definition of solved. But from the perspective of a "retail customer" just walking up to the ecosystem, even with all of our contributions towards trying to untangle it, and even with your efforts to put a more friendly face on Z3 via Grok, not so much. It was, and is, still just as intimidating and confusing to even a seasoned Python programmer as it was in 2004 and possibly more so, because the jukes we did to break dependencies just added conditional code instead of removing the actual complexity. Even today, zope.authentication depends on packages that have zero life outside of the whole like zope.location or ones like zope.browser which exist only to service a self-inflicted packaging problem. There's just no real chance of explaining why these things are the way they are to some otherwise uninterested person.

And I think this really did contribute to stagnation. If you can't get other people excited about your systems, what's the point of releasing them? At least this is true for me; I saw no point in continuing to have total fidelity with the Zope brand when it was so tarnished, and I think as much as anything, the packaging decisions really did contribute to that tarnish. There were other problems too that you tried to address (e.g. over-reliance on ZCML), but I think we might have survived that if the distribution story didn't just almost-immediately turn everyone off.

I am glad you are working on things like Reg, which seems to be more retail-friendly, because you can very easily detect its outline; you know where it starts and where it stops and who might want to use it.

FWIW, I am actually working on something a bit similar but possibly more ambitious and therefore more risky, factored out of stuff that already exists in Pyramid. Possibly we should compare notes at some point, at least once I've gotten some software together to demonstrate the requirements. The main one that ZCA doesn't provide is predicates unrelated to adaptation (e.g. execute this view if the request method is GET, without needing to attach some otherwise pointless IGET interface to the request). So I'm going to see if I can get something going there that is reusable, because I need it in both Pyramid and in things like Substance D. That said, I am dreading working on it because it's a deep dive that will consume me for weeks.

Martijn Faassen

Oh, sure, if you walk up to PyPI and look at zope.* packages you'll be hopelessly lost. No question about that. We solved the technical issue of "pull in one dependency, get all the others", not the usefulness of the libraries themselves. You need to solve the technical issue too if you want to make libraries useful, but that's indeed a pretty backwards way of doing things, just the only step forward I could see if you want to evolve the existing split up codebase as we had it then. Libraries should start out being useful.

But we worked on the dependency hairball for other reasons too - we could dump lots of dependencies weren't using anymore but were still pulling it. The effort wasn't a total loss for us using Grok or Zope 2.

I agree that the intimidating codebase without approachable contributed to stagnation. Paradoxically enough splitting things up was actually intended to make the codebase less intimidating, but in some ways made it worse. But this predates putting stuff on PyPI too: there were far too many packages in the zope.* tree early on already, when the codebase itself was still maintained as a single tree.

I see the splitup into PyPI as a mixed bag; it helped expose underlying problems and made things even less approachable at the same time.

A reworking of the component stuff more ambitious than Reg? In Reg I actually have a Predicate registry that plugs into the rest of Reg; I use it in Morepath, though I haven't gone through Pyramid's more complicated predicate use cases yet.