A Practical Guide to DevOps for SAP ERP
If you like this post, you might enjoy the follow up. IaC enables us to deploy new systems with only two lines of code. https://blogs.sap.com/2021/12/17/infrastructure-as-code-devops-and-the-future-of-enterprise/
We’ve been applying DevOps for SAP to our product development and couldn’t be happier with the results. Below is a high-level overview of how we implemented DevOps for our team, and I hope it helps move the practice forward and gain adoption within SAP.
- Run SAP ECC in a Docker container and allow each developer to run an isolated system.
- Use abapGit to save ABAP code with a code repo such as GitHub.
- Leverage ABAP Unit to execute unit tests and measure coverage.
- Configure GitHub Actions to
- Run all tests and ensure minimum coverage
- Enforce syntax rules with abaplint
- Require peer review
- Spin up a “QA” system for the test team to use
- Code that makes it to the main branch is production-ready code
Feel free to comment if you have any questions.
Containers Change the Game
If you’re not familiar with containers, you can think of them similarly to virtual machines. A virtual machine allows you to run an operating system, and a container enables you to run a single program. In our case, the goal was to run SAP ECC in a container. One advantage of containers is that they are quickly replaceable. For example, you can break your system and start a new container in about three minutes. This is possible because containers are based on images. Images are like “snapshots” that store the system in a known state.
Each developer, functional resource, or tester can use containers to run their own SAP system. Running SAP in a container environment provides system isolation, so work never impacts others. Isolation is a massive advantage as you don’t have to worry about object locks, overwriting data someone else was using, or creating inaccurate results if your work depends on theirs.
There are several options to run containers, but one of the most popular is Docker. We built our containers using Docker mainly due to the large community and trusted name.
You have multiple images available to use:
- SAP ERP 3 years of data
- SAP ERP 1 month of data
- SAP ERP no data
- SAP S/4HANA 2020
You receive a requirement to format all the phone numbers in your SAP ERP system to match the country’s format for that customer. You start a container based on “SAP ERP 3 years of data” and write your first draft of the logic. You test it individually for 12 phone numbers, and it works. Then you decide to run it on all 125,000 customers and realize that it deletes every other phone number.
In a traditional scenario, this might make any developer panic. However, container isolation means you only impacted the current container you are running. You decide to remove that container and start a new one, again based on the image “SAP ERP 3 years of data,” so all of your customer phone number data is back to the original state after 3 minutes. Time to try again.
The Missing Source Code Manager
The keen reader might wonder, “what happens to my code if I remove a container?” Any changes you make to a container are wiped when you remove it. The new container is a replica of the image you use, introducing a new problem – how do we save our code?
abapGit to the rescue! abapGit is an opensource git client for ABAP. It allows us to use a tool such as GitHub for source code management. Instead of transports, we use abapGit to manage our code changes inside a container. There are countless tutorials on git and GitHub, so I will only cover the basics.
Git uses the concept of repositories which are very similar to SAP packages. Each repository corresponds to an SAP package. By default, your repository has one main branch considered the definitive branch. You can create feature branches to experiment with before committing it to the main branch. When you begin working on a feature or bug fix, you create a branch (e.g., my-feature-branch.) Any code changes you make are committed to this branch. The branch is now part of the repository and visible to others who have access. Now you can start a new container and pull your feature branch into the new container.
Before removing my container, I create a branch “nl-format-phone-numbers” and commit the changes. Then I can safely remove that container and start a new one. When the new container spins up, it will pull the main branch by default, but I can navigate to t-code ZABAPGIT and change the branch from main to the nl-format-phone-numbers branch. I can now pull my feature code and continue working where I left off.
Goodbye Test Team
As a developer, reducing the cycle of code, test, debug, repeat is crucial. The reality is that testing is difficult, and the feedback loop when humans are testing is far too long. Automated testing helps reduce this cycle and deliver better software.
Testing requires an organizational change. ABAP unit testing is not new in SAP but is rarely used. Using automation to enforce unit testing can train developers to follow the recommended practice. It’s too easy in a standard development workflow to skip the tests. Using GitHub Actions, you can make it a requirement to have adequate test coverage and tests that pass to merge a feature branch to the main branch.
Writing tests upfront is more work, but it’s well worth it in the long run. Tests don’t need to be overly complicated. The benefit is realized because they are run in aggregate by a machine and expose any dependencies across projects. If you do not have automated testing, a human needs to be aware of all the dependencies and manually test them when any change is made. This manual approach is not reasonable or sustainable.
The “Goodbye Test Team” is said tongue-in-cheek. In reality, we’re just shifting the test team’s responsibilities to help develop tests cases before development begins. The updated test process allows the developer to write code to test valid business scenarios and provide sufficient coverage. It also changes the flow so that the test team doesn’t need to perform the repetitive task that a machine can perform.
- Select 50 customer phone numbers at random and validate that the final format is correct.
- If reasonable, check at least one phone number from each country and validate the final format is correct.
- Check that the total number of entries with a valid phone number are the same before and after formatting.
Clean Code Only
Putting it all together leads to the final step before merging a feature branch to the main branch. This step uses GitHub Actions and is highly configurable, but we share a proposed strategy that can be used by organizations starting their DevOps journey.
GitHub Actions allows you to automate workflows. In our case, when a developer completes a feature, they will want to merge the code to the main branch via a pull request (PR). Before allowing this, we need to:
- Execute all unit tests and make sure everything passes and the minimum test coverage is met.
- Run abaplint to confirm the correct syntax is used.
- Require a code review from another developer.
- Spin up a “QA” system that the test team can use to run any manual tests required.
This entire process should only take a few hours. It provides a better separation of duties so that once a developer completes their development, it is unlikely the code will come back to them for additional revisions. This updated workflow allows all team members to focus more on their core responsibility instead of wasting time in the back and forth involved with the legacy process.
- I complete my feature branch, run my automated tests on my local environment, and commit my changes.
- I go to the GitHub website and create a PR that triggers the workflow.
- All my tests pass, but during the code review process, a fellow developer notices that my comments are not helpful and provides suggestions on how to improve them. They do not approve the request and instead request I implement the changes.
- I update my comments, commit my changes, and add a comment on GitHub, letting the reviewer know, “Thanks for the suggestions. Comments are now updated!”
- The reviewer approves the code.
- The test team runs some manual tests and finds nothing wrong. They approve the changes.
- GitHub has everything it needs and merges the nl-format-phone-numbers branch with the main branch.
- GitHub Actions triggers another action to pull the code in dev and create and release a transport.
- The transport is safe to move to PRD and moves automatically via a batch job at 2 AM.
Change is Hard
We treat the main branch as production. Once code makes it to the main branch it is production-ready. A transport can be automatically created and released in the development system. Since the code has been tested in a containerized version of QA, it is safe to move directly to production.
Of course, there are exceptions, but these can be handled as such and outside the standard workflow. For example, you must coordinate the process and manually move transports if a manual process is required.
As a starting point, it’s good to handle transports manually to provide confidence that this modern process works and does not disrupt production. If appropriate, you can move to more automation after establishing a certain comfort level.