Transforming Layoff into Learning Opportunities
In the eye of a storm of layoffs, my students and I found ourselves facing as all software industry an uncertain future
In the eye of a storm of layoffs, my students and I found ourselves facing as all software industry an uncertain future. However, we saw in this challenging circumstance an opportunity for growth and a chance to utilize our time productively. This, if we can say, adversity is, indeed, the prime motivation behind this article and the project it introduces.
Transforming adversity into opportunity, we pooled our skills and determination to construct a project together. A rule engine designed around the principles of SOLID, KISS and DRY. Our goal was to create a system that could dynamically select algorithm behaviors through effectively crafted patterns.
We believe that sharing our experience could be beneficial to those who find themselves in a similar situation or simply have time to learn something new. This article offers an in-depth look into our process, the obstacles we encountered, and the solutions we created.
By the end of this article, we hope you'll be inspired to explore the complete source code available on our GitHub repository. There, you will also find a detailed Readme explaining our approach. We hope this project provides a beacon of motivation and learning for everyone navigating through their own storm of layoffs or other challenging times.
How Did We Start?
We have reached this by using a design pattern that enables you to set the range of algorithms, individually contain them, and interchange them at will. This allows the application to evolve on its own without needing any help from the client using it. Alternatively, you could use an obvious strategy pattern instead of resorting to involved if-else operations for each job level for each employee.
That is, in lieu of determining each person’s job level via comparatively complex and hard-to-maintain if-else statements, there exists an alternative method in counting upon distinct “strategies” for each job level. Each strategy possesses competent knowledge capable of accurately assessing every employee taking into account the exact additional requirements needed to fulfill its corresponding job level. Therefore, you have the flexibility to introduce new strategies or change existing ones without introducing neither influences nor alterations to the remainder codebase.
Anatomy of a Rule Engine
To illustrate this point, we may use an example from a real life project on which I’m currently working. The project is a rule engine for employee ranking implemented using C#. We have used it, since almost all business applications require some kind of rule engine. It employs the Strategy Pattern to see whether or not an employee meets their job level. It utilizes the skills and experience of one’s employment to achieve that.
The heart of our project is simply Kernel. It is like the brain of the operation. This holds all services and main domain logic altogether. Within this Kernel, we have several key components as well.
Firstly, there is the Domain. Here, we describe our main entities; Employee, EmployeeId, EmployeeSkill, and EmployeeJobLevel. It’s like our DNA of course. It describes those characteristics that form our system. One very important part of the Domain is the EmployeeEvaluationRuleEngine. This engine drives everything.
It calculates the job level of an employee by comparing him with his skills and experiences as well.
Next, we have Services. Here, we define how our system works with other systems. It includes the IEmployeeEvaluationService interface and its implementation. This service works just like our spokesperson in speaking out about our project. Using the EmployeeEvaluationRuleEngine, it evaluates an employee and communicates results.
Then we have the Rules. Here, we define such different ways in which we evaluate each of our different job levels. Each strategy is like a unique game plan for evaluation. They are being implemented as separate classes at that. But they driving by the same playbook.
That being the IEmployeeLevelEvaluationStrategy interface. But each one has driven its own unique approach to evaluating whether an employee will achieve a certain job level.
The Main (read classic console application to feel output) application is where our application starts up obviously. It’s like the conductor of an orchestra that brings together all the different parts on hold to create a harmonious performance. It creates some employees and evaluates them by our services and rules, then displays their job levels.
Finally, let us work on the test project solution. This should check whether every little part of our application runs as expected. It provides unit tests for different parts of the application. To ensure each component both our entities in Domain and our strategies in Rules actually do what is asked of them. You can see in the Readme details what every test is responsible for.
Why do we believe this is useful?
The Strategy Pattern helps us to manage complexity by containing each algorithm (or “strategy”) in its own class. You can implement strategies ad hoc, add new strategies, or change existing ones without disturbing the rest of your code. It eventually leads to simpler and more maintainable coding practices.
Also, one of the SOLID principles of object-oriented design is Single Responsibility. The responsibility of a strategy class lies in its ability to determine whether an employee qualifies for a predefined job level only.
Instead of a Conclusion, Your Moment Has Arrived! Step Forward!
Hopefully, this post and the associated GitHub repository will help you understand what we tried to do and how it could be applicable in real-life scenarios.
Design patterns should never be thought of as one-time fixes applied to all design problems. When well defined, they are very useful building blocks used in creating a project structure and improving readability.
You can obtain the full source code mentioned above on GitHub if interesting or have any thoughts regarding improvement of this student project. Take a look at Demo.SRP.EmployeeEvaluation to see prebuilt models implementations, clean backends, service classes, play around with it and let us know what you think.
And until you find new role, you can try to learn new concept that can help you in next interview, such as building projects in C++, Java, Python or Rust.
Good luck and Happy coding!
This is not mine. I am just a student mentor. Thanks to the students of the Faculty of Information Technologies, University "Džemal Bijedić" in Mostar and Politehnički fakultet Univerziteta u Zenici Department of Software Engineering who have made contributions. Special thanks to student Elma Čomor, who is the orchestrator of this project and Haris Hercegovac, as the co-mentor. ❤️