Accelerate Domain Learning: Explore Application Dependencies with RailsGraph
An Entity Relationship Diagram (ERD) of your application is a great tool to understand how your models are associated. However, for large applications with complex data model, those diagrams could be hard to visualise.
In addition to your application models, there are many other interesting connections and dependencies within your application, that understanding them could help you improve many aspects of the software and make informed architectural decisions.
In this story, I will share the motivation behind building RailsGraph and my experience utilising the gem to overcome challenges and enable my team to successfully deliver with confidence on a complex data migration project. For different web frameworks, the concepts discussed in this blog are still relevant.
Over the past few months, I have been leading multiple projects to extract data models out of a complex monolith application. The goal was to move those data models to their own domain specific databases using Active Record Multiple Database support.
Data migrations can be complex, demanding careful consideration to ensure data integrity. Moreover, it’s crucial to handle dependencies effectively while performing migrations. While I won’t delve into the intricacies of migrations here, I highly recommend reading the Migrations Done Well blog from The Pragmatic Engineer, by Gergely Orosz.
One of the major challenges of data migrations in large codebases is identifying dependencies on the models being migrated. Lack of comprehensive knowledge about the codebase further complicates this task. Additionally, inadequate definition of foreign key constraints in the database tables adds to the difficulty of identifying these dependencies.
Initially, I relied on schema.rb
and conducted manual searches to identify models that could potentially depend on the ones I was interested in. However, this approach proved to be less than ideal. I often found myself doing repetitive work and manually building dependency graphs.
Then, I attempted to generate an Entity-Relationship Diagram (ERD) for the application. Unfortunately, the resulting diagram was overcrowded and challenging to decipher. To overcome this, I adopted a more selective approach. I focused only on the models of interest and continually updated the configurations as I gained more insights into their dependencies. Although that was much better, it still consumed a lot of time and required knowledge about the codebase.
So, I set out on a mission to find a simpler, more efficient, and less time-consuming approach. I envisioned a tool that would allow me to effortlessly explore dependencies on data models through an interactive diagram. Drawing inspiration from my past experience with graph databases, I realized that leveraging their power would be a great starting point. Fueled by a fresh cup of ☕️, I embarked on the coding journey to create RailsGraph…
What is RailsGraph?
RailsGraph is a Ruby gem that empowers Rails developers to visualise and interact with the intricate connections within their applications, accelerating domain learning and fosters a deeper understanding of application dependencies.
Using RailsGraph, you could generate an interactive and queryable dependency graph for different kind of entities within your Ruby on Rails application.
The gem will parse your application’s Active Record models, Associations, Attributes, Application Databases with support for Rails multiple databases feature, Packwerk packs if your application depends on it, and more… then insert this data into Neo4j database.
RailsGraph depends on Neo4j (a graph Database) and utilities its Neo4j Browser open source product to visualise the graph. That makes it easy to explore and query your application graph using Cypher queries without the need to re-generate the graph every time you want to explore a new domain.
Graph Structure
The graph consists of two main simple components, Nodes and Relationships.
🟢 Nodes represent discrete objects of the entities we are processing and they are labeled to classify which kind of object it is.
RailsGraph labels the nodes according to their kind, so Active Record Models are labeled Model
where database objects are labeled Database
, etc… Visually you can differentiate between nodes types easily as Neo4j Browser automatically assigns a different color to each label. For instance, in the graph above:
- 🔴 represent Active Record Models
- 🟠 represent Abstract Classes
- 🔵 represent a Column
- …
🔗 Relationships represent how those objects are associated with each other. Similar to Nodes, relationships also support labels to differentiate between their types.
One of RailsGraph features is to parse Active Record Associations. For instance, AR model nodes will be connected with BelongsTo
relationship, if they are associated with each other using AR belongs_to
association.
In addition to AR associations relationships, there are many more relationships, e.g the ones that represent the connection between a table and a database, named PersistedIn
. This example project demonstrates more connections types.
Understanding this structure would make it easier to run Cypher queries and discover specific paths within your application based on what you are looking for. Please check this page in the wiki for examples.
What is next?
RailsGraph can be further enhanced to unlock deeper insights and improve usability. By extracting more connections, we can better understand the interdependencies of application components. Also, reducing the need for writing Cypher queries and facilitating common use cases, by creating a simple GUI with pre-set filters, could improve usability.
I would love to hear your thoughts and insights on RailsGraph gem, so please give it a try and share your feedback! And of course, everyone is welcome to contribute on Github ! ⭐