GSoC’20 Project Report
For the past three months, I have been contributing to OpenWISP under GSoC’20 to develop the notifications module, i.e. OpenWISP Notifications. The project spanned over 45+ PRs consisting of over 65+ commit making over 6000 additions. Let’s take a dive into OpenWISP Notifications!
About the Project
The main goal of the project was to develop a stand-alone notification module that abstracts and simplifies generating and sending notifications for OpenWISP network events. It was aimed to make consuming notification easy for users. A key feature was to provide users control over the notifications they receive, i.e. they could define their notification preferences. Above everything, the major goal of the project was to provide freedom of customization to users. A user should be able to register their custom notification types and use them instead of defaults which come with OpenWISP.
Need for OpenWISP Notifications
It is desired by a network management software that it notifies users for network events. Say, when a device becomes unreachable it should notify concerned personnel about the event such that they can act accordingly. Another example, OpenWISP is often configured to trigger integrations with external services and it may be possible that a particular service may observe a fault resulting in undesired behavior. Therefore, immediate reporting of such evebts is required to solve them at the earliest. It is safe to say that notifications are a vital part of any newtwork management software.
Before OpenWISP Notifications, there was limited support of sending notifications which too was embedded inside OpenWISP Monitoring(another unreleased module at that time). Therefore, to bring notifications to OpenWISP as a mainstream feature, a dedicated notifications module was needed. A stand-alone notifications module also serves a greater purpose. It not only abstracts the required logic for sending notifications, but it also helps to allow easy customization by users. It basically helps users to avoid re-inventing the wheel and ensures code re-usability.
Following are some notable features of OpenWISP Notifications:
- Multi-tenant Notifications
- Notification Types
- Notification Widget
- REST API for CRUD Operations
- Real-time Notifications
- Notification Preferences
Major Development Milestones
Extracting Notifications module from OpenWISP Monitoring
A notification module was previously built into OpenWISP Monitoring which utilized Django Notifications and provided limited functionality of creating and viewing notifications. A major leap in the development of OpenWISP Notifications was decoupling notifications from OpenWISP Monitoring. Early decoupling of these modules helped in avoiding hindrance in their development. Post decoupling, development of OpenWISP Notifications commenced as a stand-alone package.
Related work: The Initial Commit
Supporting OpenWISP’s Multi-Tenant Architecture
OpenWISP natively supports multi-tenancy, which means a single instance of OpenWISP can be used by different organizations having their own artifacts. It was to be dealt with utmost care that notifications about an artifact should be delivered only to the users of the parent organization that too having the desired permissions.
During testing with OpenWISP Monitoring, faults emerged which pointed out that there were potential bugs in logic for supporting multi-tenancy. With some iterations, these bugs were fixed and OpenWISP Notifications now supports multi-tenancy natively like any other OpenWISP module.
Related Work: Fixing recipient permissions while sending notifications
Developing Notification Types
Notification types were aimed to revolutionize generating notifications in OpenWISP. By providing a notification configuration only once, the feature embraced DRY — Don’t Repeat Yourself — principle. Adding markdown support for notification messages helped to improve both user and developer experience. Using notification types, it was possible to noticeably reduce the lines of code required to create a notification in other modules.
Related Work: Adding notification types
Adding Notification Widget
One of the most required features of OpenWISP Notifications was to improve the user experience for browsing notifications. Earlier, the user will have to dig down into Django’s Admin menus to find details for notifications. Developing a notification widget was the chosen way to go. We had to strike the right balance to provide enough information without bloating the widget itself, thus harming the one thing it aimed for i.e. user experience.
The development of the notification widget encouraged us to develop API endpoints for CRUD operations. This was required to support the dynamic loading of notifications on user interaction.
Here is a quick comparison between consuming notifications before and after the development of the notification widget.
Supporting Real-Time Notifications
With the inception of the notification widget, we were able to drastically improve user experience, but something still felt missing. It was real-time notifications. The notification widget working on the HTTP simply couldn’t update new notifications without reloading the page. We looked the other way, towards WebSockets. Using WebSockets, it was possible to deliver notification as they were being generated. This also allowed us to display notifications to users without even opening notification widget, i.e. through “notification toasts”.
Introducing Notification Preferences
One of the important aspects of the project was to allow users to define their notification preferences, i.e. let them choose which notification they want to receive and how. OpenWISP Notifications supports both web and email mode of notifications and a user may want to just receive web notifications. After developing this feature, users can select the mode of receiving notification based on notification type(category) and organization.
Not only OpenWISP Notifications allows users to define notification preferences on the basis of notification type and organization but also allow to disable notifications related to a specific object for a desired period of time.
Since the type of object could vary across OpenWISP, an easy to configure generic solution was implemented to make it seamless for developers integrating OpenWISP Notifications in their project.
Multi-tenancy again showed up a challenge as enabling these settings required adhering to different levels of permissions. With a bit of back and forth during reviews, it finally reached the point where it neither breaks permissions nor bloats user interface.
Bringing OpenWISP Notifications to OpenWISP Modules
The notifications module was re-introduced into OpenWISP Monitoring which swapped out the previous implementation with OpenWISP Notifications. OpenWISP Notifications was also added to OpenWISP Controller which makes it vital to OpenWISP’s eco-system.
This was one of the best summers for me, a summer packed with learning, developing and networking. It was a pleasure to work under the guidance of my mentors, Federico Capoano(@nemesisdesign), Noumbissi Valere(@NoumbissiValere) and Vivek Chand(@Vivekrajput20). I would like to extend my humble gratitude to my mentors without whom my project wouldn’t be possible.
Through contributing to OpenWISP, I learned new technologies like Ansible, OpenWRT, and Docker. I would like to share my key learnings from my GSoC journey.
Software Development — An Iterative Process
There is no perfect solution to a software problem. A solution that seems perfect now may become rather useless in the future. Software are desired to be able to adapt to changes, but above all the developers should be able to cope up with those changes.
Database — Keeping It Under Check
During the development of OpenWISP Notifications, we found out the application was hitting databases like crazy due to either poorly written queries or the native behavior of Django’s ORM. Databases are optimized for specific operations, unloading that work from your application will help in further optimization.
Cache — A Dubious Friend
“There are only two hard things in Computer Science: cache invalidation and naming things”
- Phil Karlton
A lot of times, to prevent excessive database queries, I looked forward to caching desired data. A problem that arose with caching is when to invalidate the cache. There were a few instances when bugs were popping up due to fault in cache invalidation. One should use cache responsibly, it can do more harm than good.
TDD — Test, Test And Test!
Automated tests can do so much, yet there are some areas where the developer(yes, not user) testing is required. While introducing changes in a module of the software, make sure those changes play well with other modules — Integration Testing.
Open-source — Contribute and Collaborate
Open-source is more than just code, it is about people. Community plays an important role in open-source. Interacting with the community helps to understand the actual requirements and use-case. It also helps to see different ways to approach a problem. I would like to extend my gratitude towards the incredible community of users and developers of OpenWISP who helped with their feedback and guidance throughout the journey.
We are glad to have early adopters of OpenWISP Notifications even when it is not released. Due to feedback from such users, we are able to find bugs and shortcomings early in the development stage which is helping us making OpenWISP Notifications battle-tested.
Following are things which are in the planned roadmap:
- Releasing OpenWISP Notifications 0.1.0
- Updating Ansible OpenWISP and Dockerize OpenWISP modules to use the newly built OpenWISP Notifications. This will provide ease of installation to future users.
I hope you too had a great summer, keep coding!