A Deep Dive into the 'Follow' Verb: Improving Data Consistency and Scalability
In the world of software development, some of the most common features are deceptively complex. Take the simple "Follow" button. It’s a cornerstone of social networks, marketplaces, and content platforms. A user clicks a button, and they are now "following" another user, brand, or topic. Simple, right?
On the surface, yes. But beneath the UI, a cascade of operations is triggered. A database record is created, a notification is sent, an activity feed is updated, and an analytics event is logged. As your application grows, this "simple" action's logic becomes scattered across different services, API endpoints, and codebases. What happens when a developer adds a new entry point for following but forgets to fire the analytics event? You get data inconsistency. What happens when you need to change the logic? You embark on a perilous journey through distributed code, hoping you find every instance.
This is where a shift in thinking is required. We need to stop seeing these actions as a series of disparate function calls and start treating them as first-class citizens in our architecture. This is the core principle behind Verbs.do: defining business actions as code.
Let's do a deep dive into the 'Follow' action to see how this Business-as-Code approach transforms a brittle process into a consistent, scalable, and manageable asset.
The Traditional 'Follow': A Trail of Scattered Logic
Without a centralized action management system, implementing the 'Follow' functionality typically looks like this:
- API Endpoint: You create an endpoint, say POST /api/v1/users/{id}/follow.
- Controller Logic: A controller handles the request. It validates the user's authentication and authorization, then calls a service.
- Service Logic: The UserService contains a followUser method. This method:
- Writes a new row to a followers table in your primary database.
- Makes an HTTP call to your NotificationService to send a push notification.
- Publishes an event to a message queue (like RabbitMQ or Kafka) for the AnalyticsService to consume.
- Maybe it calls yet another service to update a search index.
The business logic defining "what it means to follow" is not in one place; it's an implicit process distributed across your entire stack. This architecture creates significant problems:
- Inconsistency: If a new feature—say, a "Follow All Recommended Users" button—calls the database directly but forgets to call the notification service, your system's behavior becomes inconsistent.
- Brittleness: If the NotificationService API changes, you have to hunt down every place it's called and update it.
- Poor Visibility: It’s difficult for a new developer (or even the original one six months later) to understand the full impact of a 'Follow' action without reading code across multiple repositories.
The 'Follow' Verb: Centralized, Declarative, and Powerful
Now, let's redefine the 'Follow' action using Verbs.do. Instead of writing imperative code spread across services, we create a single, declarative definition of the action itself.
import { Verb } from 'verbs.do';
// Define a 'Follow' action in your system
const follow = new Verb({
name: 'Follow',
subject: { type: 'User', description: 'The user who is following.' },
object: { type: 'User', description: 'The user being followed.' },
effects: [
{ type: 'createEdge', from: 'subject', to: 'object', label: 'follows' },
{ type: 'notify', user: 'object.id', message: '`{subject.name}` started following you.' }
]
});
// Now, any part of your system can execute this action
await follow.execute({ subjectId: 'user-123', objectId: 'user-456' });
This code snippet is not just a function; it's the single source of truth for the 'Follow' action in your entire business.
Let's break it down:
- name: A clear, human-readable name for the action.
- subject & object: These define the "nouns" of the action. A User (the subject) performs the action on another User (the object). This structure forms the basis for permissions, validation, and context.
- effects: This is the magic. It's a declarative array of every side effect that constitutes the action. Here, we've defined that a 'Follow' action has two effects:
- createEdge: Create a "follows" relationship between the subject and object. This is an abstract data operation, not a raw SQL query.
- notify: Send a specific notification to the user being followed.
When follow.execute() is called from anywhere—your web frontend, mobile app, or a backend microservice—the Verbs.do engine guarantees that all of these effects are orchestrated correctly.
Gaining Unshakeable Data Consistency
By codifying the action, you eliminate the possibility of partial execution. There is only one way to "follow" a user: by executing the Follow Verb.
- Single Source of Truth: The Verb definition is the canonical source for your Business Logic. If you want to know what happens when a user follows another, you look at one declarative object, not ten different files in five different microservices.
- Atomic Execution: The Verbs.do runtime ensures that the chain of effects is executed as a single transaction. You no longer have to worry about a database write succeeding but a notification failing, leaving your system in an inconsistent state.
- Auditable by Design: Every execution of a Verb is a structured event that can be logged and audited. You have a perfect, immutable record of every who, what, when, and why for every action taken in your system.
Achieving True Scalability and Composability
This approach doesn't just fix consistency issues; it fundamentally changes how you scale your systems and your teams.
- Decoupling Services: Your frontend no longer needs to know about the existence of a notification service. It just needs to execute the Follow Verb. The Verbs.do engine handles the routing and orchestration. If you decide to swap out your notification provider, you update the effect handler in one place, and no client code needs to change. This is the power of true API Automation.
- Effortless Maintenance: Imagine your Product Manager wants to award 5 points to a user every time they follow someone. With the traditional approach, you’d be digging through code. With Verbs.do, you simply add a new effect to the Follow Verb's definition:
{ "type": "awardPoints", "user": "subject.id", "points": 5 }
Every single implementation of the 'Follow' action across your entire platform instantly inherits this new logic.
- Composable Workflows: Verbs are building blocks. The effects of one Verb can trigger another, allowing you to create a powerful Agentic Workflow. For example, a new CompleteOnboarding Verb could have an effect that executes the Follow Verb, automatically making the new user follow the company's official account.
From Scattered Functions to Strategic Assets
The 'Follow' button is a simple example, but it perfectly illustrates a universal challenge. Your business is defined by its actions: PurchaseProduct, PostComment, ApproveExpense, AssignTicket.
By treating these actions as code with Verbs.do, you transform scattered, implicit logic into centralized, manageable, and scalable assets. You improve data consistency, accelerate development, and create a clear, auditable record of your entire business operation.
Stop chasing logic through your codebase. It's time to define your business, one Verb at a time.