© Ben Lopatin 2020
B. LopatinDjango Standalone Appshttps://doi.org/10.1007/978-1-4842-5632-9_9

9. Scoping and drawing boundaries

Ben Lopatin1 
(1)
New York, NY, USA
 

In the first chapter, we discussed in brief what it means to scope a Django standalone app, including your goals in creating a standalone app, the considerations of third-party dependencies, and the job the app is expected to perform.

In this chapter, we’ll revisit these same considerations in more depth and specifically with respect to looking at a possible Django standalone app in the context of an existing codebase.

Scoping and the nature of the problem

Defining the scope of a software project is one of the first challenges in a project, and one of the most important. The scope defines what it will do and where the boundaries are and influences not just the size of a project in lines of code but also how complicated it is, how many features it can support, and how challenging it is to test and maintain the software.

The app as written in your own project may have an explicit scope, but it’s easy for the boundaries to become blurred when it’s an integrated part of your project source code. This may be because of feature creep or because of some immediate convenience – it was simpler or more expedient to include some new small feature within the app even though the purpose of that feature is orthogonal to the app’s core job, or is overly specific to your particular project.

The scope of the app will influence what dependencies are required as well. As the “dependency surface area” increases, so does the brittleness of the app with regard to maintenance and version support. If your standalone app depends on Django, then it’s simply tied to Django versions. If however it requires Django, and one or more additional standalone apps, then it’s most likely limited by the degree to which all of the dependencies overlap in their support of Django and Python versions. Reducing the scope of your standalone app from what you might have included in your own project has the expected effect of making it far simpler to maintain.

The job of a standalone app

  • What would you say you do here?

If you’re looking for a heuristic for scoping and defining the boundaries of the app, you can do worse than to simply write a brief job description. As an employee you may have an ill-fitting job title and a multitude of varied responsibilities, but if you strip it down, then more than likely you can define a purpose for your job beyond the things you do. As a software developer, your job is to translate business needs into working software. As a CEO your job is to lead the company to growth and profitability (in most places, at least). There may be more job responsibilities, and these may be important, but nearly every job has a singular purpose. Likewise, your standalone app should have a guiding purpose that can be briefly and concisely described.

Put yourself in the shoes of a marketer (no, really). How would you describe your app? What problem does it solve? How does it solve that problem? How does it solve this problem for many other applications?

The answers to these questions will be helpful in marketing an open source package, but that’s not why we’re asking them.

Here are several popular standalone Django apps and, in my own words, their brief job description:
  • The job of Wagtail is to make it easier to model and serve user-editable content in a user friendly way.

  • The job of Django REST Framework is to provide a Django-like experience for creating RESTful APIs and connecting existing Django apps to the API.

  • The job of django-taggit is to make it easy to add tags, in the taxonomical sense, to any kind of object in a Django project

  • The job of Easy Thumbnails is to create resized images for a single uploaded image.

These apps vary in their size and the scope of features they provide, but in each case all of those features can be traced back to a singularly stated purpose.

The dimensions for creation and extraction

There are a number of dimensions by which you can look at a standalone app; here I want to focus on the axis that I’ll call vertical and horizontal segmentation, or in other words, business feature vs. technical foundation. In the following figure, we see that a feature (yellow bar) is a vertical slice through the horizontal components of any app or project (Figure 9-1).
../images/486718_1_En_9_Chapter/486718_1_En_9_Fig1_HTML.jpg
Figure 9-1

Vertical and horizontal segmentation

Do not be persuaded that this allows for some kind of scientific taxonomy; rather, it’s a handy way of assessing how modules are broken up and organized and, in the context of standalone Django apps, how to define the job they do.

Horizontally segmented modules – apps or otherwise – provide some kind of common “infrastructure” that can be used across projects that supports the development of features. This is code that delivers something only a developer will experience (by and large).

Examples include
  • django-model-utils

  • django-extensions

  • django-crisyforms

These primarily solve problems that development teams face, like making it easier to render complex forms and providing common base classes to avoid repeated boilerplate code.

Horizontally organized code within a project looks like this, emphasizing organization by what the code does first and what business domain it solves for second:
app/
        forms/
        models/
                ...
                image_models.py
                user_models.py
                subscription_models.py
        views/

This will look familiar since this is the convention for organizing code within a Django app, but it’s also the convention for organizing project code in other frameworks.

Vertically segmented modules, on the other hand, are organized first around a business need, that is to say, usually something that a user will experience.

Examples include
  • django.contrib.auth

  • Haystack

  • django-suit

It should be obvious that this isn’t an “either/or” distinction of course. But Django’s app-centric architecture encourages vertical or feature-based organization. A Django app includes everything from models to URL routes to forms and views. This is necessarily how standalone apps ship, but this is also the default pattern for apps within a Django project.

If the functionality you’re targeting looks like something that’s feature agnostic, it probably warrants inclusion in an app separate from features.

Sizing the scope of an app

A standalone Django app should be big enough to do its job, and no bigger. But how big is that? What are the consequences of mis-sizing the scope a standalone app? And how can you solve for an app that looks too small or unwieldy large?

First, an app should be no bigger than its job. But it should also be big enough. If it is too big, it’s either doing too much, or it’s another framework in and of itself. Too small and it may not warrant creating a standalone app, or even an installable package.

When an app is too big

What does it mean for an app to be too big? There are some rather large standalone apps that aren’t necessarily too big. The answer is as clear as mud: it depends. The first thing that makes an app too big is including extraneous features that either aren’t critical to the app or would be sufficiently useful in their own app. A tractable example of this would be an app that includes its own utility base classes, like the kind you’d find in django-model-utils. These extra features can become distractions when maintaining the app and adding features down the road. They increase the amount of code that needs to be tested, as well. Don’t jettison them if they’re necessary, but make sure they’re necessary.

A couple of solutions stand out for apps that are too large:
  • Break it up into separate packages.

  • Organize into sub-apps.

Breaking into separate packages is a good idea if at least one of the potential packages is sufficiently useful on its own. The benefit of separate packages in such a case is of a wider net for more use cases. However, each additional package, whether a standalone app or not, increases the cost of maintenance and may make it more challenging to ensure that the two components continue to work well together.

If they’re mutually interdependent, then there’s no benefit in creating separate packages, and using sub-apps or mini apps in a single package is a superior choice.

Organizing a standalone app into sub-apps requires then that each app be added individually to a target project’s INSTALLED_APPS like so:
INSTALLED_APPS = [
        ...
        "cms",
        "cms.pages",
        "cms.photos",
        ...
]

This strategy consists of a primary, top-level app with subsidiary and constituent feature apps included as their own installable apps. While clunkier than adding only the one “core” app, this may allow you to better structure the components logically and to allow developer users to exclude functionality that they don’t need. This doesn’t reduce the footprint of your app’s source code, but it does reduce the scope that anyone using the app must consider.

When an app is too small

The problems of making an app that is too small are different and arguably less significant than those of an app that is too large. The main issue is that it risks leading to a preponderance of tiny dependencies that all need to be included and maintained. The benefit of using standalone packages decreases when their number transcends what you can easily remember. And we’d like to minimize the dependencies our app introduces into other people’s projects.

If you are looking at creating multiple small apps, first consider whether they really make sense on their own, or if they have sufficient commonality, in either functionality or business domain to bundle together. If you find yourself using these features together in more than one project, that is likely the case.

Creating a tiny standalone app shouldn’t be treated as forbidden though. And there’s an obvious tension between the two ends of the spectrum.

Summary

In this chapter, you learned how to approach scoping your app, by defining the job that the app is to accomplish, by assessing the possible feature and component dimensions of the app, and additionally identifying how the size of the scope can be assessed and adjusted. In the next chapter, we’ll learn how to begin the process of refactoring and extracting your app from an existing Django project.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.150.80