Understanding strategies for deploying the code
For projects where the development team is not the end user, it is important to come up with a strategy to deploy the code for the end user. For relatively large-scale projects, when there is a well-defined DEV
and PROD
environment, deploying the code and strategizing it becomes important.
Python is the language of choice for cloud and cluster computing environments as well.
Issues related to deploying the code are listed as follows:
- Exactly the same transformations need to happen in
DEV
,TEST
, andPROD
environments. - As the code keeps getting updated in the
DEV
environment, how will the changes be synced to thePROD
environment? - What type of testing do you plan to do in the
DEV
andPROD
environments?
Let's look into two main strategies for deploying the code.
Batch development
This is the traditional development process. We develop the code, compile it, and then test it. This process is repeated iteratively until all the requirements are met. Then, the developed code is deployed.
Employing continuous integration and continuous delivery
Continuous integration/continuous delivery (CI/CD) in the context of Python refers to continuous integration and deployment instead of conducting it as a batch process. It helps to create a development-operations (DevOps) environment by bridging the gap between development and operations.
CI refers to continuously integrating, building, and testing various modules of the code as they are being updated. For a team, this means that the code developed individually by each team member is integrated, built, and tested, typically many times a day. Once they are tested, the repository in the source control is updated.
An advantage of CI is that problems or bugs are fixed right in the beginning. A typical bug fixed on the day it was created takes much less time to resolve right away instead of resolving it days, weeks, or months later when it has already trickled down to other modules and those affected may have created multilevel dependencies.
Unlike Java or C++, Python is an interpreted language, which means the built code is executable on any target machine with an interpreter. In comparison, the compiled code is typically built for one type of target machine and may be developed by different members of the team. Once we have figured out which steps need to be followed each time a change is made, we can automate it.
As Python code is dependent on external packages, keeping track of their names and versions is part of automating the build process. A good practice is to list all these packages in a file named requirements.txt
. The name can be anything, but the Python community typically tends to call it requirements.txt
.
To install the packages, we will execute the following command:
$pip install -r requirements.txt
To create a requirements
file that represents the packages used in our code, we can use the following command:
$pip freeze > requirements.txt
The goal of integration is to catch errors and defects early, but it has the potential to make the development process unstable. There will be times when a member of the team has introduced a major bug, thus breaking the code, if other team members may have to wait until that bug is resolved. Robust self-testing by team members and choosing the right frequency for integration will help to resolve the issue. For robust testing, running testing each time a change is made should be implemented. This testing process should be eventually completely automated. In the case of errors, the build should fail and the team member responsible for the defective module should be notified. The team member can choose to first provide a quick fix before taking time to resolve and fully test the problem to make sure other team members are not blocked.
Once the code is built and tested, we can choose to update the deployed code as well. That will implement the CD part. If we choose to have a complete CI/CD process, it means that each time a change is made, it is built and tested and the changes are reflected in the deployed code. If managed properly, the end user will benefit from having a constantly evolving solution. In some use cases, each CI/CD cycle may be an iterative move from MVP to a full solution. In other use cases, we are trying to capture and formulate a fast-changing real-world problem, discarding obsolete assumptions, and incorporating new information. An example is the pattern analysis of the COVID-19 situation, which is changing by the hour. Also, new information is coming at a rapid pace, and any use case related to it may benefit from CI/CD, whereby developers are constantly updating their solutions based on new emerging facts and information.
Next, we will discuss commonly used development environments for Python.