Although this is not entirely false, using a single language for backend and frontend eases a lot the workflow of the team:
- Better testing,
- Less code redundancy
- Easier workflow for the developers
I developed web apps using Ruby on Rails at my previous company, and earlier, I used Python with Django or Zope for a few websites. I have really enjoyed, working with those two languages, even if they also had their own issues.
The benefits of sharing a single language between backend and frontend
- The backend endpoint had been updated, but we had forgotten to apply the changes to the frontend. If the endpoint is not tested with the full stack, this problem will not be caught by the CI. Worse yet, if frontend tests use mocks for the backend, we can get incorrect positive results indicating everything is fine.
- “Misunderstanding between frontend and backend teams on exchanged data.”
Alternative solutions include contract testing, using protobuf or JSON schema to format the data, and others.
But I find it definitely easier to deal with this issue without needing an external library to handle formatting the data.
Although the frontend and backend generally do not have the same scope of responsibilities, there is often some code that needs to be shared between the two.
The first in mind would be (de)serializing data, but some treatments on those data could also be shared. In Gravity, for example, the language used to query sessions must be available in both stacks: in the frontend to define the scope of sessions and in the backend to query the sessions.
Those utilities are generally simple, but you still have to write them twice when you have a different language for frontend and backend. And when changes are made to those treatments, they must be applied to both stacks.
Ease the team’s workflow
The Gravity team is composed of 5 developers, and although everyone has their own preferences (for example, I prefer spending time in the backend than in the frontend), any developer in the team can work at any level of the application, without having to learn two languages. So frontend bugs can be addressed by any developer, not just those dedicated to frontend.
Another advantage of being able to write code in both frontend and backend is that, when a developer (or two when we are pairing) starts a new feature, the same person(s) will develop the feature from the beginning to its delivery.
As a developer, I find this more motivating to work on the whole feature instead of focusing on just a subset of it.
To be honest, those examples are more tied to the team organization than to the fact we use the same language for backend and frontend. In my previous company, we started with the same kind of organization, although the backend was written in Ruby. In the future, when the team will grow, we will certainly have to change our processes. We might have dedicated teams for frontend and backend, or we might have features teams that work on both stacks, or we might end up with another solution.
Single language development
That being said, I am still convinced that having a single language to work with, eases a lot, having this kind of team organization. It should also prove to be pretty useful when we integrate new junior developers or interns, as they should also face one learning curve and not two.
And one last advantage for the developers, is no more context switching (well, in an ideal world… Having a single language does not magically protect you from meetings, bugs, and production incidents). When you are developing in parallel in two languages, you are often facing those little moments trying to recall the correct syntax: “is
`map` taking a callback argument or using a block ? Ah yes, it’s Ruby, it’s a block !”.
Those are obviously not real blockers, but being able to focus on what you want to do, and not how to do it, eases the development workflow.
One of the main reasons (added to all the previously mentioned) I really enjoy working with a single language is that we have the possibility to simply write acceptance tests that can be executed at multiple levels of the application:
- against the backend core functions
- against the HTTP server
- against the components
- Against the full application.
To achieve this, we write the acceptance scenario in Gherkin (the Given/When/Then language behind Cucumber). During the execution, the glue code will hit the system under test at different levels depending on the configuration.
This enables us to write our code incrementally:
- We first focus on the business rules.
- Then we expose it through HTTP.
- We write components that will communicate with the HTTP endpoints.
- Finally, we integrate those components into the application pages.
This can be achieved too when having a different language for the backend, but it is more tedious (some tools that were written for
Cucumber-js have not been ported to the other Cucumber implementation). The glue code also has to be written twice: once for the backend, once for the frontend. It also doubles the maintenance of the said glue code (any change in one implementation will have to be ported to the other one).
A few words of conclusion
The same goes for languages. They all serve the same goal: telling the computer what to do. The business field served by the application might be a deciding factor in the choice of the backend language. For example, Python is often praised for Machine Learning, and sometimes a Java connector is necessary for certain tools. The team and its organization are also a determining factor. Forcing a Ruby on Rails team to switch to TypeScript backend could be a waste.
If you want to learn more about the features offered by our tool Gravity, book a demo with our team here