What this book covers
Chapter 1, Introduction, Code Formatting, and Tools, is an introduction to the main tools the reader needs to set up a development environment in Python. We cover the basics a Python developer is recommended to know to start working with the language effectively. It also includes some guidelines for maintaining readable code in the project, such as tools for static analysis, documentation, type checking, and code formatting. Having a common understanding of coding standards is a good thing but relying on good intentions only doesn't scale. That's why the chapter concludes by discussing tools to work more effectively.
Chapter 2, Pythonic Code, looks at the first idioms in Python, which we will continue to use in the following chapters. We cover the particular features of Python, how they are meant to be used, and in this chapter, we start building knowledge around the idea that Pythonic code is in general of much better quality.
Chapter 3, General Traits of Good Code, reviews general principles of software engineering making the focus on writing more maintainable code. With the knowledge gained from the previous chapter, we take a look at general clean design ideas, and how they can be implemented in Python.
Chapter 4, The SOLID Principles, covers a set of design principles for object-oriented software design. This acronym is part of the language or jargon of software engineering, and we see how each one of them can be applied to Python. In particular, the reader will learn how dependency injection makes the code more maintainable, a concept that will be very useful in the next chapters.
Chapter 5, Using Decorators to Improve Our Code, looks at one of the greatest features of Python. After understanding how to create decorators (for functions and classes), we put them in action for reusing code, separating responsibilities, and creating more granular functions. Another interesting learning point from this chapter is how to use decorators to our advantage to simplify complex and repetitive function signatures.
Chapter 6, Getting More Out of Our Objects with Descriptors, explores descriptors in Python, which take object-oriented design to a new level. While this is a feature more related to frameworks and tools, we can see how to improve the readability of our code with descriptors, and also reuse code. The content revisited in this chapter will make the reader achieve a higher level of understanding of Python.
Chapter 7, Generators, Iterators, and Asynchronous Programming, starts by showing how generators are a fantastic feature of Python. The fact that iteration is a core component of Python could make us think that it leads to a new programming model. By using generators and iterators in general, we can think differently about the way we write our programs. With the lessons learned from generators, we go further and learn about coroutines in Python and the basics of asynchronous programming. This chapter wraps up by explaining the new syntax (and new magic methods!) for asynchronous programming and asynchronous iteration.
Chapter 8, Unit Testing and Refactoring, discusses the importance of unit tests in any codebase that claims to be maintainable. We discuss refactoring as a pre-requisite to evolve and maintain a code base, and how unit tests are critical for this. All of this, with the support of the proper tools (mainly the unittest
and pytest
modules). Finally, we learn how the secret for good testing lies not so much on the tests themselves, but on having testable code.
Chapter 9, Common Design Patterns, reviews how to implement the most common design patterns in Python, not from the point of view of solving a problem, but by examining how they solve problems by leveraging a better and more maintainable solution. The chapter mentions the peculiarities of Python that have made some of the design patterns invisible and takes a pragmatic approach to implement some of them. We discuss other (not so "conventional") patterns that are Python-specific.
Chapter 10, Clean Architecture, focuses on the idea that clean code is the base of good architecture. All those details we mentioned in the first chapter, and everything else revisited along the way, will play a critical role in the entire design when the system is deployed.