 Thank you for coming to my talk. My name is Patrick Altman, VP of Engineering at Eldarion, and core developer on the PNACS project. Well, there we go. So there's currently over 60 open source projects in the PNACS ecosystem. And this morning I'd like to discuss how we've added extensibility to many of them. I cannot figure out how to make these advance. Guess it's gonna do it, so on and so on. So why should you care about extensibility? Number one, it's the foundation of reusability. When we're writing Jango apps, we want them to be reusable. Second, we have a chance to delight our users. We've all experienced this. I know at least I have. Jango is a great example of this, whether it's extending the admin, using class-based views, or using a custom user model. And lastly, we have a chance to make the world a better place. I know it's a pretty grandiose statement, but really if we reduce the need to reinvent the wheel, we increase the time and cognitive capacity that is available to spend working on new and interesting problems. The community benefits and becomes more productive and even more innovative, resulting in more value creation for and in the world around us. Just how do we go about creating extensibility? There's a lot of different ways, but I want to focus just on three today. The first is what we call hook sets. This is a term coined by, it's a term coined by Brian Rosner. He created hook sets in Jango user accounts and it was driven by a client need, where the use of signals didn't quite support the requirement, at least not as cleanly as we'd liked. And it was simply a class with methods that can be overridden at the site level. Then we have class-based views, Russell Keith McGee discussed this at length on Tuesday, and they're a great way to modify and extend behavior of an app inside a site. And lastly, plugins. Plugins permit loose coupling between the plugin and consumer. They allow for rapid expansion of functionality due to the ease of writing individual plugins. And they're used mostly to extend a single app or a website. They're less about reusability. So, Jango user accounts is probably one of Eldarren's most used apps out of Penax. It provides a ton of functionality that we've all come to expect from web applications. Things like sign up, login, email confirmation, password resetting, and more. But a lot of these rely heavily on sending emails. Up until Hooksets, we were really only able to modify, up until Hooksets, we were really only able to modify the content of the email templates and not really change how the emails were being sent. The client in this case wanted to control the content of the email through a third-party website, a third-party service that he had subscribed to, and it would require us to make API calls providing the context for those emails. So, the solution was to create a Hookset method in Hookset methods to override how the emails are being sent so we could implement this in his site. So, let's take a look at some code, if I can make these advance. So, the default Hookset implementation that ships with Jango user accounts basically just pulled out all of the blocks of sending email into individual methods in this object, in this class. Then we have a Hook proxy and we use this Hookset object, the instance of the Hookset proxy, to wrap the pulling of the settings and that setting is what allows us to override the default Hookset so we can create a Hookset in our application, in our website that allows us to override how the emails work. So, here in our Conf module, you can see we use Janice L. Jango App Conf for application settings. It's a fantastic way to encapsulate all the settings in your reusable app. Highly recommend it. So, we ship with default Hookset configured as you see here in this Hookset property of the main Conf module. But to override it, it's as simple as creating your own class at the, and inheriting from the base Hookset and putting it somewhere in your site and then setting the account Hookset setting in your settings.py. Here in the models of the Jango user accounts, you can see in this sign up model, we have a method called send and there used to be a block of your typical send mail code here and that was replaced with this Hookset method send invitation email. And that's what keeps it, that's what allows us to override how the email sent. So, for the client, we ended up just making API calls and replacing the default Hookset. So, moving on to class space views. We had a client with specific needs for our sign up, for the sign up process, as well as complexity of passwords. Geez, I really apologize by these slides, guys. Anyways, the client needed support for a profile creation of coupon codes right upon sign up and passwords had very specific business rules like containing certain characters and whatnot that out of the box are really supported by Jango user accounts. So, we had to extend the sign up view and override some of the forms to modify them to collect and process this extra data, but we didn't wanna rewrite, have to rewrite the entire sign up view and the forms that dealt with the passwords, all we really need to do is add a little bit of extra validation by just going back on. So, as you can see here in the view, this is the views module of the project. We are pulling in the sign up view from Jango user accounts, subclassing it and then overriding just a few methods, two that deal with user creation and one that's called, it's an after sign up method that gives us access to the form. And we use that to basically take the created user, create a profile and process any coupon codes. In addition, we're pulling in the custom sign up form from that has the password, secure password mix in that we'll see here. And really all we needed to do to change these three forms that deal with passwords is to create a mix in and to encapsulate in one place the business rules that were around validating that the password was, the password was up to his complexity requirements and mix it in with the other three forms without really changing any of the forms themselves. Except for the sign up form, obviously we had to add some additional fields there. And we tie it all together and the URL's pie. We override routes provided by Jango user accounts for the change password and password reset views. We're using the stock views, but we're overriding them here so we can use the forms that we overrode. And then of course using our custom sign up view. And now into plugins. So Eldurian has a site that's really an early development KPI tree. It's a tool for teams to track metrics, scorecards and key performance indicators. Core to this app is collecting metrics. Some of this will be manual and there's a lot of metrics. Some of this is manual like we'll come to the site and fill out a form or respond to an email, but there's a lot of metrics that are generated from systems and so it makes sense to automate the collection of those. About to throw my computer across the room. So yeah, so for the automated metrics, we wanted to wait to easily write, geez, there's my rehearsal from last night. Funny enough, when you're rehearsing this, it doesn't automatically advance like this. Okay, I believe I was talking about the automation. So we needed a way to easily write integrations for the automated collections. We'll likely end up writing a bulk of these, but we wanted to expose the ability for anyone to contribute and add to them. We're gonna open source this package so people can submit their own and to encourage this we need it to be dead simple. This is nothing new. Sites like Get Century offer this, GitHub you can send pull requests to extend a plugin. And the idea is you should only have to implement a single class to conform and conform to an API and not have to worry about any of the internals of the host system. So there's really just two parts here that make this plugin system work. The first is the registry, which is really just a small wrapper around a dictionary. And you can see here we create an instance and then delete it to create a singleton. And the important point here is this registry object is a single point of interface between the internals of the website and the plugin system. And the second half of this base.py module that's implementing this whole plugin system are as a base plugin class. Some languages would be an abstract base class, but important to note here, you can see it has this thing called a meta class, which is this, the registrable class at the top. And the really cool thing about this is any definition of a new plugin will automatically register itself. It's one less thing to worry about in configuration on our side or for the plugin developer to have to get right. So here's an example of a plugin that I wrote for our use. We use it to integrate with user voice, specifically to pull in support metrics from Gondor. So this is about all there is to implementing a plugin. Obviously I've cut out the implementation details because they're not important and the slide's only so big. But the idea is you just implement these methods to interact with, in this case, user voice API and not have to worry about the internals of how it's consumed. So here's an example of how it's being consumed internally. This is a model's module of one of our internal apps in the project. The auto collection is simply a model with the user will create an instance of and as such will select a provider, in this case like user voice. The choices are populated from the registry. There's a method on there that will group all the choices together. And the inputs are the user input that the plugin needs to execute, whether it's OAuth tokens or whatever and the plugin developer's responsible for telling it what it needs. This, it will actually validate against the plugins inputs method to make sure that all the required inputs are there. And then I cut a lot of code out here for brevity but in the process method, we're gonna call and fetch the data and then create metrics internally. And the beautiful thing about this is the plugin developer doesn't have to know how this is being consumed and KPI tree doesn't have to know what plugin it's talking about. It's a very clean separation. And earlier I mentioned when, about the meta class and how that works and things get registered automatically when things are defined and imported. Well, to import them, we have, we use a startup.py module on all of our projects. That's gonna quickly change now with Django 1.7. But for the past two years, we've wanted to organize all of our startup code in one place and not have to do things like import things into URLs.py relying on the fact that Django auto loads that. So in all of our projects, we have at least this run method and the auto load method to run the auto discover for the admin and to load all of our receivers modules where we store things like signal handlers. Instead of putting signal handlers inside models, we put them in our receiver's pie to keep that all organized well. So for the KPI tree project, we added this function called load sub modules. And all it's gonna do is loop over this KPI tree integrations package and import all of its modules. In our case, they are plugins. And that's what, and when that happens, they get auto registered. So in order for this run method to execute, we have to modify the two entry points to our application. And that's the whiskey module. You can see here we import KPI tree startup and call startup run. We do the same thing in the manage.py. So as of Tuesday, we've had over 5,000 star gazers on across those 60 PNX projects. And for the ones that are packaged, for example, we have startup project templates. But for the ones that are packaged over a million, close to a million downloads. And I say this because with hook sets, class space views and plugins, it's helped Eldar and make apps more extensible. And in doing so, we've seen greater reuse. And as evidenced by these stars and downloads, I like to think that we're delighting our users, at least some of them. And after three plus years of working at Eldarion, I can honestly attest that our immediate world has gotten better, both for us and our clients, because I've seen that we are building more things and we're building them faster, lots faster than where we were three years ago, both for ourselves and for our clients. So I've covered a lot here really quick. This wasn't really designed to be a tutorial, but just to kind of get things, get you thinking. I'm around the rest of the afternoon. If you wanna talk any more, talk any deeper about any of these things, just find me and let's connect. So with that, are there any questions?