Workflow

Contents

  1. Reviews and Merge Requests
  2. Functional Testing
  3. Deployment
  4. Git Workflow
  5. Retrospective

Reviews and Merge Requests

Reviews according to the multiple-eye principle help to identify errors, but also to work out concepts better and make them more accessible to the masses. The latter is particularly useful when a market analysis is difficult or the effort required is disproportionate. In addition to their role as quality assurance, reviews can also serve to disseminate knowledge. Not only can the reviewers gain a better understanding of the concept, they also train their knowledge of the code base and thus the ability to recognize errors faster as well as to develop faster themselves. Merge requests on the other can be utilized to secure the review process. In the course of our project, both design and code reviews were explicitly performed. However, reviews after researching important topics could also occur.

To assure code and functional quality, the Core team used GitLab’s merge request approval rules. A merge request to the Core’s main branch (whether initiated from within the Core team itself or coming from StudyBuddyMatch or SmartPlanner) required at least two approvals, while any other merge request to the Core’s repository only required one approval. The assignees who were tasked with reviewing the code and approving the merge request had not seen the code in question before and brought a new perspective during the review. This way, each merge request (which usually involved the addition of a completed feature) only included functioning code that was reviewed by at least one external person. Merge conflicts were usually solved by the author of the merge request or the Core team leader.

When StudyBuddyMatch or SmartPlanner completed one of their planned features, they created merge requests to the Core repository. These merge requests were then reviewed by the Core team. During the review, the reviewers tested the code, looked at ways to improve the code, and asked questions in case some coding choices were not clear. Members of the StudyBuddyMatch or SmartPlanner teams then answered these comments and remarks. After the review phase, the merge request was approved and the included commits were merged into the Core repository. Since most of the merge requests affected several files with several hundred lines of code, most of the Core team worked on the same merge request and divided the files among each other. This way, merge requests took on average only 5 days to be reviewed and merged.

The Core team created merge requests to the super repository when milestones in the development of our project were completed or when important events, e.g. usability tests, were expected. These merge requests to the super repository were then reviewed by the project managers and, after approval, were merged into that repository, which was then deployed to the project server. Using these pipelines and structures, we established a two-instance review process, where members of the Core team reviewed the code and subsequently the project managers reviewed the code again to ensure proper functionality, coding, and security practices in the final version of the project.

Design Reviews

Design reviews are an important part of the conceptualization of a feature. While a design can cover all requirements of a feature, it does not necessarily have to focus on usability and accessibility. Some requirements even become apparent only during the design process itself. In addition, designs can also turn out inconsistently, especially when several designers are involved. To counteract this, designs were presented and roughly discussed within a module group after completion, and the details were improved through a lively exchange on the design components themselves (for an exemplary design review process, see step 4 of A 4-Step Design Process . Since the designs were created in Figma, it was convenient to also use this to asynchronously write feedback to the designs directly via the comment function. Overall, the design reviews helped to create a consistent picture of the design, at least within the individual modules. In addition, it allowed inexperienced designers to try out design tasks, as they could later revise their design with the help of the others. The usability tests also showed that SmartUni is, on the whole, easy to use. Thus, the design reviews paid off.

Code Reviews

A code review is used to systematically evaluate the code of an application. The aim is to identify errors and improve the code quality. In addition, it makes an important contribution to knowledge distribution and can help inexperienced developers to improve. If a code review is carried out at the right point in the development process, it can prevent faulty code from getting into the final product or later development processes being made more difficult by bad architecture decisions. In a task-branch based development process (i.e. each new task gets a new branch; see also Git Workflow), it is therefore a good idea to perform the code review after completing a task but before merging it with the rest of the code. How exactly code reviews were handled within each subteam varied. In most cases, however, they were each performed by a more experienced developer. The reviewer checked that all requirements were met, that all cases that needed to be considered were considered, and that all functionality was correct. Some errors were not immediately apparent. For example, the recurring events were fully usable, but only as long as there was no more than one user. However, this could be fixed by a code review. In addition, care was taken to ensure that the code was clean, understandable, and consistent. Besides the code reviews in the individual subteams, cross-team reviews were also carried out as part of the merge requests to merge the modules together, which followed stricter rules. Problems that were found in these requests were mostly rather small, which speaks to the effectiveness of the detailed quality assurance process within the module teams themselves.

Functional Testing

Functional testing involves checking a function against its functional requirements. In this process, a tester gradually goes through all the functionalities of an application manually and checks them for errors. This procedure forms an important aspect of quality assurance. Normally, care is taken during the development of a feature to ensure that it functions without errors. However, this is usually not sufficient if (1) more than one person is working on the same or a related feature, (2) there are already several related features that need to be considered during development, or (3) the complexity of the functionalities to be considered is too high to be easily manageable. The former was true for most of the features. The second for instance occurred with SmartPlanner categories, which are used in events, tasks as well as the calendar overview itself. The latter arose, for example, in the case of the recurring events in SmartPlanner, where there were nine different cases of concern about how a single event could be updated, e.g. from a weekly pattern to an annual pattern or else to no pattern at all. Therefore, a functional test of either a single feature or the entire application is usually performed on a cycle-by-cycle basis, such as after a feature is developed, but also before a release. Extensive testing of these functionalities often requires time, a good understanding of the context and of the cases to be covered. In order to reduce the effort somewhat, functional testing was usually not performed after every single feature, but after the completion of a milestone. This way, correlations could be tested directly while still ensuring regular testing. In the SmartPlanner module, for example, the tests were performed about every two months a total of three times by all subteam members, as well as before each deployment by the project managers. Since functional testing was not the only quality assurance applied on our application (see also Reviews, Unit Tests and Usability Testing), this was sufficient for our purposes.

Deployment

There are two systems which come into play when discussing a hosted application - the production system, and the development system(s). “Production system” is the name for the instance of the application which users see and interact with when they navigate to the respective website. It is connected to a different database during deployment than the proto-databases (usually dummy databases) used in development. The development systems use the dummy databases and are the instances of an application which the developers of an application usually interact with.

Separating the development and deployment environments from each other is crucial to maintain proper function of a website and easy development. If both development and deployment accessed and edited the same code and live database, both would likely be compromised, resulting in the website and application at least temporarily being unusable for its users.

The production system for SmartUni is deployed on a virtual server in the Rechenzentrum (computing center) of the University of Osnabrück. In the initial setup of this server, a production settings file was created changing the secret key and the saved e-mail address for e-mail notifications, and adding the other production-specific settings the server would need to run the code in a deployment environment. The production system is connected by a GitLab access token to the main repository from which all other repositories of the teams are forked (more on this in the project structure section).

Deployment of SmartUni happened in multiple iterations over the course of the project. After a review of a merge request (created by the Core team) to the super repository to which the deployment server is linked, the project managers reviewed the merge request and went over any issues they found with the module teams. Depending on the issues, they were solved immediately and added as commits to the merge request or collected and delegated to the respective team. This was decided upon in cooperation with the team leaders, who were assignees on each such merge request. The project managers took the role of reviewers on each request. After the review was successfully completed and the merge request approved, the merged code was pulled onto the server. After that, the new migrations were applied and the new static files collected on the server. The server’s website deployment was always temporarily deactivated when new code was added, but was never down for longer than a few hours. Issues where fixed as they came up or again delegated to the team leaders when an ad-hoc fix was not possible. With this system, the server was continuously updated. This way there was no deployment overhead at the end and the arising bugs were fixed in a close-to-feature implementation.

Git Workflow

Establishing a common Git Workflow is recommended for any kind of large software project. Especially if multiple people are working on a common software system, parallelized coding can result in highly deviating development branches, causing potentially difficult merge sessions. In addition to uncoordinated isolated development, bugs and feature conflicts might be detected very late if a common workflow strategy is missing. Considering the fact that a long-term project requires new members to join while old members leave, complex individual workflows are hard for newcomers to understand, leaving them confused and causing unnecessarily long settling-in periods.

All these issues can be addressed by introducing a common Git Workflow, ideally at the start of the project. This includes agreeing on a common branching hierarchy as well as regular updates for smaller integration steps. There are many different branching strategies presented by various repository hosting platforms (e.g., GitLab and Github) which propose main branches, development branches, feature branches, release branches, and much more. For this project, since the project involved around 20 to 30 people working in three teams, we decided on the Workflow of Github, adding the option of personal branches within the teams. For easier integration of updates from the SBM and SPM team, fork repositories were created from the Core repository (SPC). This way, updates could flow two-ways from the platform development (SPC) to the modules (SPM and SBM) and vice-versa. For deployment purposes, a super repository on top of the Core repository was created.

Fig. 1: Example branching strategy including main, feature and personal branches

The Github Workflow includes a main branch which always contains a clear working state of the software. The main branch exists only once per repository. For the SmartUni project, the Core repository holds the main one while the modules maintain a differently named main branch for their forked version of the core repository. The main one is ideally protected such that only main branch maintainers (e.g., the Core team) are allowed to merge to it. For each major (or even minor) feature, a feature branch will be branched off the main one and development of the feature will take place on this separate branch. There can be multiple feature branches at once depending on how many functionalities are being worked on simultaneously. Feature branches are named according to the final functionality that is intended to be implemented on that branch, and the feature branches are merged back into the main branch once the feature is fully implemented and tested. Merge requests and code reviews are required. Personal branches are branched off from the feature branches for individual development and are merged back into the feature branches once a personal working package is finished. How personal branches were managed was up to the individual teams and their members’ preference. Multiple personal branches are also possible, e.g. when a person is working on multiple features/issues at the same time. In general, branches should be deleted once they are merged (or rebased if they are being reused, which may occur in the case of personal branches), to avoid accumulation of branches in the repository. Besides the branching strategies, Git Issues were used to track open problems and bugs. Git Issues allow for collecting resources, having discussions, and aggregating work progress (commits) in a common place. Issues can also be created to track open tasks and working packages. Once an issue is resolved, it should be closed. Like issues, merge requests were also incorporated in our workflow and offer similar functionalities as the issues. Merge requests require code reviews and merge approvals before merging. GitLab will automatically close merge requests once they are merged.

Retrospective

The retrospective was a regularly occurring team meeting within the SmartPlanner team in which the previous development phase was discussed and reflected on. The focus was on the essential questions “What went well?” and “What did not work so well?” During the development phase, the SmartPlanner team had four retrospectives that took place in intervals of two months. The other teams did not have an explicit meeting for retrospectives, but rather talked about upcoming problems on the run.

Process

The proceedings were always similar. Since most of the study project took place remotely, the retrospective was held online. The various questions were therefore created and edited via a Miro Board, a tool we used for project management.
A retrospective was usually led by one person. First, the moderator prepared the questions and the respective Miro board. A few days before the retrospective, the participants were then asked to review the last interval for themselves. In the team meeting, everyone had time to anonymously add post-its with ideas and comments to the board (see Fig. 2). Subsequently, the points were discussed and approaches for improvement were collected. Points that went well, and should be kept, were also written down and shared in the group. Then we compared the outcomes of this retrospective with the ones of the previous one and evaluated the changes.

Fig. 2: Example of a Retrospective Miro Board

Outcome

Since the retrospective was meant to be a safe place to express one’s ideas and fears, all discussions cannot be described openly in this report. However, with the team’s consent, a real-life example can be walked through: Since much in this study project happened remotely, it was a significant challenge for the team to work together and to co-work on certain parts. When this was identified as lacking and desirable in one retrospective, we came up with ideas on how we could better work together remotely. As a result, a new channel was opened in the element chat, where everyone could notify the others when they were working on the SmartPlanner. This allowed the others to join and strengthened the feeling of working together. In addition, there was more collaboration within the team and questions and problems could be solved faster. In the following retrospective, we then listed this point under “what went well.”