At PayFit, we are revolutionizing how companies run their payroll and manage their human resources. We want to make HR Managers’ daily life a breeze. To achieve this, we developed an internal technology which moves our business logic away from our code. Discover JetLang, our internal programming language! 🚀
🙋️ What we do
Our core business is payroll.
Everyone in our client's companies must be paid as expected by their contract. This means that calculations must be accurate, taxes must be properly filed, local laws must be adhered to, and so much more.
We started in France. Payroll-wise, it's not the easiest of countries: about 7,000 parameters are necessary to calculate a net salary. There are also hundreds of collective agreements that will potentially change all calculations. It is difficult to summarize this in a single mathematical formula. The net salary is just one parameter among many.
We did it, and our system is able to follow-up with the ever-changing French labor laws.
🌍 Multiply that by X countries...
France is just the start of our journey to help companies with payroll and human resources information system management: we're expanding into Europe, with our service now open for Spanish, German, British and soon Italian companies.
Expanding to other countries is no piece of cake: payroll management is extremely different depending on the country. We are not just talking about a configuration for each country, but really a whole new set of labor laws. This means new sets of logic, new formulas, different types of companies, etc.
Because we want to revolutionize payroll, making correct calculations is only part of our job: we also need to offer a simple interface, so that anyone, anywhere, can manage the payroll of its employees.
Imagine translating all this into code, maintained by developers who know nothing about payroll…
📅 Business Logic and Product Features
Building a tool such as PayFit means working head downs on two parallel fronts:
- Making sure our software is always up-to-date with the latest laws of each country,
- Improving our software with new features, impactful improvements and of course bug fixes.
The thing is, to make a great product, developers need to know the codebase well. This means understanding its intricacies and anticipating all the side effects their code change might have on the rest of the application, on the data, on the API, etc.
Add to that designers, lawyers, product managers, and eventually more developers brought on to keep improving the software and expanding to more and more countries. This brings a lot of complexity to the mix, because software development tends to intrinsically link business logic and product features.
To solve this complexity, we have to think ahead. First, we need to be prepared to scale, both country-wise and technically-wise. Second, we need to know right now how we are going to handle some of the tough questions coming up next:
- What do we do when there are very similar logics in multiple places? Should we rewrite everything? Just one part? Only what changed?
- How do we take into account how all of the laws changed each month in each country?
- Does the code remain as simple and readable if you’re managing 2 countries or 50 countries?
- Do developers need to know the formulas for calculating a salary? What about donations or bonuses?
- How do you manage the side effects between different countries?
You can tell that if we want to make it easy for both our users and our team members, we can't focus solely on business logic (implementing labor laws), then solely on product features (updating the codebase): they are equally important, and deserve dedicated teams.
Each team requires a different set of skills. Each must not be able to break what the other does. They must be separate, but walk hand in hand.
💡 The big idea
From the start, we decided to think "long term", and create a dedicated "business logic" language, separate but tied to the system language.
Imagine a simplified language that allows you to do a subset of the operations of mathematics and logic — think Excel operations. It could contain variables, conditions, and functions.
Imagine a powerful engine that can understand this language and run it on a browser or on a server.
System developers would just have to create the skeleton of the application and put the engine in the right place. They would 100% focus on core topics that are not related to business, UI, performance or security without worrying about business logic.
Another team would create the content pages and payroll logic. They would be able to generate lists, modals and make very complex calculations on any platform.
Spoiler alert! That’s what we do at PayFit!
🚀 Introducing JetLang
JetLang is a technology we develop internally, consisting of a programming language, logical components and a development tool.
🗣 The language
The language is very simple. Variables, conditions and mathematical expressions can be used.
The variables can be inputs of the user or calculated automatically from other variables in parameters.
# Example of JetLang code # variable1 -> firstName # variable2 -> lastName # Let's compute the fullName NotIn( null ; variable1 ; variable2) # If the variable is filled Concat( variable1; " " ; variable2) # Let's concat values
🖌+ 🐘 Components and Actions
The principle of Components is quite special. They allow you to manage the interface and also to manage complex logic on a page.
Each component works differently due to having its own configuration. From there, creating complex logic trees becomes child’s play.
The latest concept we have introduced is Actions. It can be seen as a page, or as a script, because we need to run it on any platform including browsers and servers.
We create a really simple Action and its Components. All variables look like
The main idea is simplicity.
Thanks to this kind of system we can develop Payroll Management in several countries in a very fast and extremely efficient way. Because the foundation is already in place and easy to adapt, adding a new country means to simply rewrite the different logic related to the payroll laws of the country in question. The rest is done automatically.
We can create as many JetLang teams, distributed in each country, and keep a single tech team in one place for the underlying codebase.
A programming language does not work alone. It’s usually just a grammar, a parser, an interpreter. It takes a motor and a driver to do the calculations in a specific order. JetLang thus has an Engine and a Runner.
🎼 The Engine
Calculating payroll means solving complex graphs of dependencies between variables, components, and condition trees. A ton of research on graph algorithms exists, and we were able to inspire ourselves and find the right way to do our calculations without reinventing the wheel.
The engine thus uses our parser, generates an AST (abstract syntax tree) and makes sure to calculate the whole graph as quickly as possible to update the variables used. It is fully tested and easily maintainable so that the slightest syntax error is understandable.
🏎 The Runner
Does the engine also need to handle state changes? User inputs? API calls?
We decided to create a complex state manager based on a well-known library: Redux. We will not go into detail here, but the runner is aware of the component tree. It’s the runner that manages the flow of data. It will communicate with the engine only when it needs it. This makes it possible to really separate the calculation logic from the state logic.
It can work with UI libraries like React, React-Native or even Vue and AngularJS. It can also run on a server. We can send the runner precise commands (Redux actions) without necessarily using a UI. It will take care of updating the states of the components and, if it is necessary, ask for the engine to make new calculations.
💪 Let’s talk a little bit about performance
Creating a new layer between the user and the browser can have a huge impact on the performance of an application. Indeed we have to parse, transfer a lot of data, and potentially calculate millions of variables very quickly.
Performance improvement is the number one priority for some teams within PayFit, making sure to be more powerful while remaining as fast as possible for our users.
Thanks to the creation of JetLang, developers can stay focused on this famous performance. They can spend time analyzing and improving algorithms.
Having this existing abstraction also allows us to turn to very advanced technologies like WebAssembly with Rust for example. We'll discuss it in more detail in a future article.
👪 Our dear JetLang Masters
Users of this language and tools are not developers. They are JetLang Masters.
It is important for the development teams working on the Engine and the Runner to know their “users” and especially to understand how they work.
The goal is to find new tools to make their lives easier and more productive. We can imagine tools for deployment, integration tests, debugging, monitoring, and tracing.
All these tools are there so that the JetLang Masters can fix their errors themselves without needing the intervention of the technical team. This lets them stay focused on their logic and product features.
There is still a lot to say about JetLang. That’s why this article will fit into a more global series currently being written. We know that this kind of tool can’t adapt to all the cases of the world and can’t solve all the problems but makes it possible to separate the business logic of the tech code in a very effective way. We wanted to share our experience. 😊
Growing product in a scalable and healthy way is not easy. This requires making choices that are not very obvious upstream of development. The benefits of this kind of architecture are reflected in the daily lives of developers and our ability to evolve product features. 💪
JetLang Masters all over the world: Thank you for making our developer life better and really challenging. 🇫🇷🇬🇧🇪🇸🇩🇪🌍
-- Arthur Mialon, Engineering Manager