Why we use Sanic—build fast, run fast
Let's begin by looking at Sanic's goal:
Source: https://sanic.dev/en/guide/#goal.
Most people who are familiar with the Sanic project will tell you that its defining feature is its performance. While this is important, it is only a single part of the core philosophies of the Sanic project.
The Sanic tagline is: "Build fast. Run fast." This highlights the performance orientation of the project. It also speaks to the goal that building an application in Sanic is meant to be intuitive. Getting an application up and running should not mean learning a complex set of APIs and having a near-constant second browser window open to the documentation. While other tools make heavy usage of "black box" type features such as global variables, "magic" imports, and monkey patching, Sanic generally prefers to head in the direction of well-written, clean, and idiomatic Python (that is, Pythonic code). If you know Python, you can build a web API with Sanic.
If performance alone is not the defining feature, then what is? The front page of the Sanic project's website gives six reasons for us to explore:
- Simple and lightweight
- Unopinionated and flexible
- Performant and scalable
- Production-ready
- Trusted by millions
- Community-driven
Simple and lightweight
The API is intentionally lightweight. This means that the most common properties and methods are easily accessible and that you do not need to spend a long time memorizing a particular call stack. Early on in the history of the project, there were discussions about adding certain features. But often, adding features can lead to bloat. The SCO decided that it was more important to focus on the specifics of providing a quality developer experience than on providing "bells and whistles" features.
For example, if my application is meant to be consumed by third-party applications, then why does it need CORS? There are so many differing needs for web applications that it was decided that these features are better left to plugins and developers. This leads to the next reason.
Unopinionated and flexible
Being unopinionated is a huge asset. It means that the developer decides if they want sessions or token authentication and if they want an ORM, raw SQL queries, a NoSQL database, a combination, or even no data store at all. That is not to say that these things can't be achieved in other frameworks. But there are certain design decisions to take into account. Rather than focusing on all these features, Sanic would rather provide you with the tools to implement the features you need, and nothing more. Tooling beats features. Borrowing from a popular proverb: Sanic does not give you the fish, it teaches you how to fish.
Performant and scalable
This is what Sanic is well-known for. With a performance-first approach toward development and implementations that include tools such as uvloop and ujson, Sanic tends to outperform other asynchronous Python frameworks. We will not spend too much time on benchmarks because I tend to feel they have limited use when it comes to comparing frameworks. Something more important regarding performance is the ability to build fast and scale fast. Sanic makes it simple to run multiple server instances from a single deployment. Chapter 8, Running a Sanic Server, will talk more about scaling. It's also important to note that Sanic is very well suited to building monolithic applications, microservices, and everything in-between because of the intentional flexibility of the API.
Production-ready
It is common for frameworks to ship with a development server. These development servers make the process of building simpler by including features such as auto-reload while you are working on a project. However, these servers don't tend to be ready for production environments. Sanic's web server is intentionally built to be the primary strategy for deployment in production systems. This leads to the next reason.
Trusted by millions
Sanic is installed in and powers many applications, both large and small. It is used in corporate-built web applications and personal web projects. It tends to be one of the most downloaded frameworks from PyPI. Between April 2019 and April 2020, there were 48 million downloads of Django. Sanic, in that same period, had about 44 million downloads. It is a project with high visibility and widespread adoption in a variety of use cases.
Community-driven
Since its move from an individual repository to a community organization in 2018, decision-making has become shared across the members of the community in what they call "lazy consensus." Here's what the SCO's website says:
Source: https://sanic.dev/en/org/scope.html#lazy-consensus
Another important factor of the community is the ability of all members (whether a regular contributor or a first-time user) to enter the conversation and input valuable information into the conversation. As much as possible, Sanic attempts to be "of the community, by the community" to ensure its stability, feature set, and future.
The insistence on a community-first organization is meant to create a level of stability. All the work on the project is done by volunteers. It is a labor of love. With that said, projects driven by passion alone are at risk of becoming unmaintained if it rests upon the shoulders of a single person. This is exactly the scenario Sanic was trying to escape when the SCO was created. Being a project "of the community" means that multiple people are willing and capable to help carry the torch forward. Sanic achieves this with a rotating set of developers and balances long-term stability with staggered terms.
More on the SCO
If you want to learn more about the structure of the SCO and how you can get involved, check out the Sanic Community Organization Policy E-manual (SCOPE): https://sanic.dev/en/org/scope.html#lazy-consensus.
What drives code decisions?
Although not exactly formalized, there is an underlying set of principles that the architects and engineers of Sanic use when making coding decisions. Keeping in mind that this project is built by the hands of many people, from many backgrounds and experience levels, it is no surprise to learn that maintaining a set of consistent coding practices is itself a challenge.
I am not specifically talking about things such as formatting—tools such as black, isort, flake8, and mypy have abstracted that away. Rather, what should the code look like, how should it be organized, and what patterns should be followed?
The principles behind developing Sanic's code base are as follows:
- Performance
- Usability (unopinionated)
- Simplicity
Any line of code that is going to run during the execution of the request/response cycle will be highly scrutinized for its performance impacts. When faced with a question that puts two or more of these core philosophies in opposition, the performance consideration will almost always win. However, there are times when a slower alternative must be used. This will help not force developers into an awkward development pattern or add an undue level of complexity for developers. Part of the "speed" of Sanic is not just application performance, but also development performance.
When using Sanic, we can feel confident that there is a team of developers scrutinizing every line of code and its impact on performance, usability, and simplicity.
Let's imagine you are being asked to build an API by a project manager, who has a deadline in mind. To meet that goal, you want to get up and running as quickly as possible. However, you also want to make sure that you will have the freedom to iterate on the problems that face you without fear of being boxed into making bad decisions. One of the goals of this book is to help you identify useful patterns to adapt to help you get there.