At work we recently released Elide. We developed this project to solve an incredibly common problem: to build CRUD web services. Though I typically work in the distributed systems side of things (batch data pipelines, real-time systems, etc.), I had the opportunity to work directly in the core development of this library. I want to share some insight about what prompted our decision to build this system and a little bit about my experiences open sourcing a product from within a large company.
What is it?
Succinctly, Elide is a middleware library used to expose your data model as a secure service layer (in our case the data model is JPA-annotated Java classes). In other words, you write and annotate a Java class that describes your data model and we take care of the rest. The backend is taken care of through a set of “managers” so you don’t have to actually worry about your datastore and the interchange format is simply JSON API.
What this means is you can write your data model a single time and use it in many places. For instance, if you are using Hibernate to manage your DAO’s and Java code, you can use the models directly. On your mobile device, you can hit the service which directly exposes (again, with proper access and security concerns) the exact same code you’re using in your Java service layer code. The benefits of a system are vast, but I personally feel the reduction in boilerplate and improved consistency alone make for a large win.
Why write this thing?
As I mentioned, my work at Yahoo! has been primarily focused in data processing. That is, I typically write code that runs quickly and crunches a lot of numbers for us. This entails all of the fun minutiae associated with performance tuning large systems and performing data quality analysis on our results. However, I was fortunately roped in to work on a new feature: Flurry Pulse.
Of course I won’t go in-depth on that architecture, but it was different from typical data processing work and– as you may have guessed– it involved developing REST endpoints. All of us had experience writing these endpoints before, but it became particularly bothersome when we realized the sheer volume of boilerplate code we had to write. In the first version of Pulse, each and every endpoint was written by hand. We were exposing a data model which we had already written and annotated properly; effectively, we were rewriting our model with some added frills (i.e. security, computed fields, etc.). Then the team had a bright idea: why not generate these things?
At first, a common question within the company was, why were we venturing into this space? Wouldn’t we just be recreating Spring or Facebook’s GraphQL? A legitimate question, I might add; even though GraphQL had not yet been released (but was announced) at the start of our endeavor. Arguments against GraphQL aside, the answer is no. We found that there was a fundamental piece missing from these other systems allowing the creation of production systems to be stream-lined: security. In this day and age, it is simply not feasible to let security be an afterthought. In a world where “data is currency,” keeping people’s data safe is and should be a top priority for any software engineer.
We realized that we could reuse the code we were already using in our backends and secure them in a very generic way. Thus, the notion of “Elide” was born.
Designing and Developing the System
The initial stages of designing a system such as this are a little fuzzy. We began with a basic architecture, but had not yet written any code. We contemplated trade-offs of different designs trying to factor in ease-of-use for the library users and flexibility of the system (read: these are often inversely proportional). We were able to make some technology decisions such as using ANTLR4 for grammar processing and other architectural decisions such as using a hierarchical permission enforcement model. However, as software engineers, we all know that the devil is in the details; it’s nearly impossible to catch all of the corner cases until you start getting your hands dirty. We went to work.
As we approached completion of the first “working” system (i.e. it actually generated something but wasn’t necessarily correct or efficient), we stepped back and reevaluated. We reworked our state machines, refactored code structure, redefined the purpose of our
EntityDictionary, etc. Practical bugs aside, we continued to make adjustments to the design (i.e. addition of initializers) as we found more use cases through the code.
Consequently, I suspect that the design phase will never quite be “completed.” The one major takeaway I have from the design of this system is that it is under constant scrutiny which merits appropriate reevaluation. Many times our design copes with challenges posed by others, but sometimes we discover architectural flaws. Similarly, as with any software project, as the use-cases evolve so will its architecture out of necessity. We have designed the system to be prepared for tomorrow, but who knows what will come after that. That being said, public APIs are not moving targets; a refactoring in a public API is taken under deep consideration and– to this point– we have been able to largely avoid an “breaking” API changes.
As an original developer, I had a unique experience in developing the system first-hand from the ground up. Our team was small (usually fluctuating from 2-4 people), but this allowed each developer to be intimately involved with the entire system.
As I mentioned earlier, we realized many design modifications as we wrote code. Similarly, we were constantly finding other practical issues as we wrote the code. In particular, we were implementing a JSON API-compliant service before JSON API was finalized. This provided an interesting set of challenges trying to follow along with the almost-daily updates the JSON API guys were doing and keeping things compatible with our internal code layout. Ultimately, this likely led us to a better model: we decoupled ourselves from the JSON API spec and used it strictly as a serialization format (in theory, you could plug a different serializer in and all would be well). Changes such as these have allowed us to evolve our codebase into a cleaner and more robust system.
Open Sourcing in a Large company
Yahoo! has a lot of employees: approximately 11,000 at time of writing. Personally, I would consider this a large company. Along with large companies typically comes a lot of process and pain to get anything done (aka red-tape). However, in open sourcing Elide, this was relatively minimal. Now, this wasn’t done in a day, of course, but it was pretty fast (with most of the delay on our end). I’m not claiming that it is like this in all large companies, but I must admit that I am impressed with Yahoo! on this.
Naturally, we had to clear all the licensing through the proper channels. Similarly, we needed approvals to use the name Elide and register the elide.io domain name. However, the receptiveness of those at this gate was unprecedented. I mean, the support we had in open sourcing our code was at least (probably exceeded) that of what we receive for many internal products when using other groups. In fact, many of the items were done within a single business day or two (i.e. preparing code for open source, on-boarding a new github repo within Yahoo’s org, on-boarding to maven central within Yahoo’s namespace, etc.).
This was an incredible experience and it really makes me believe that Yahoo! does want to contribute back to the community. They clearly have some of their most excited and top-notch people working with others in this area to represent the company and it is great to see such investment in the open source world.
Elide has been an exciting piece of code to build. Now that is open sourced, we hope that the community will also find it useful and work with us in improving it! I look forward to working with many of you as we continue to grow and expand the features of Elide.comments powered by Disqus