How to Integrate Faster with Components

Speed cross-team/project integrations with components in Bit, easily solving testing, data mocking, documentation, and more.

Omer Primor
Bits and Pieces

--

A live webinar and demo session by Bit’s VP Product Itay Mendelawy.

Key takeaways:

  1. Components can be used to own the representation of entities in the architecture, allowing others to use them when integrating with services.
  2. Such ‘Entity Component’ is independent and decoupled with its own release cycle, providing a single source of truth about “what is the entity”.
  3. This approach improves the developer experience for integration, with local feedback as you integrate in the IDE, mock data to test against, usage examples, and documentation.
  4. At scale, integrating with components enables better collaboration by communicating changes with Semantic Versions, and enabling discoverability of all entities in the codebase.
  5. Finally, components can also streamline integration with external services, while reducing the potential impact of breaking changes with abstractions.

Transcript:

So, I think one of the main things that I wanted to get started for these webinars is to start with something very small that actually has a great impact on our ability to deliver fast, and our developer velocity in general.

It is not a specific feature in Bit where we use a different flow that potentially any of you do, it’s just a practice that we’ve designed over the last couple of years. We use components, or a component-driven approach, to have the integration part for application as part of our actual code base.

And I’d like to discuss this practice with you today and also discuss some of the benefits of actually using Bit with this type of approach.

Essentially what we aim to do, or one of the main things that we’re lacking in our ability to integrate, is to get something that feels like Definitely Typed for TypeScript. Imagine you get type inference for different APIs or different entities, so you can get better guarantees for the integrations as you’re driving.

And this is what we build with components in our architecture. Essentially what we’re doing is we’re building a basic component. It’s not a UI component. It doesn’t really have a lot of ‘oomph’ in terms of functionality, however it does own a specific entity in our architecture.

For example, say, we are an e-commerce app. We may want to manage invoices as an entity. We may want to manage a shipment, a user, a product as an entity because this entity is used throughout many areas in the codebase itself, whether this is front-end, backend, automation steps, middleware, databases and so on.

So, what is this Entity Component? It is a very basic, mostly a node-based component. It includes a class, allowing us to have an in-memory representation of that entity. This in-memory representation would later help different developers or consumers that would use this entity throughout their development. If they need to get a different property or user function or any functionality on top of it, it will be in a single standardized place.

This Entity Component can also provide type definitions. These type definitions can be for different APIs that are required for this component. If we have an API, say we deal with invoices and we want to have an API to create a new invoice, then this has a specific interface, a specific contract. And we want that interface to be something we can use and build a dev experience around, not only the entity itself we use.

An Entity Component can also contain mock data. Because often we see different developers on different projects, and they want to start integrating with an external service to their application. So, they’ll need to figure out how to do a network call, what’s the data structure, and they’ll need to start building mock data for their test or for their development.

But if we have mock data already in the same component that owns the entire thing, then they can just quickly import that mock data, get things rendered, and get running because they know this is the type of data they’ll already get from the service itself.

It can also contain from/to JSON functions. This allows us to transfer this entity or this component over the wire. If we need to send invoice information from a backend service to a front-end application, we need to go over the wire and we need a way for to/from JSON for it.

We can also overload that entity with additional functions and methods. And in the example I’m going to show here, we can see how we can even add additional parameters to it without really affecting the entity itself. So, if we find that many developers need a specific functionality, then they can get that in standardized way for all possible consumers that use that entity in their features.

So, I know it’s kind of a very high level abstract description, but that’s why I’d like to quickly go into a demo and show a little bit more.

Here I have a very basic express.js application that deals with users. This express.js application, because everything we do with bit has to do with components. This is actually a Bit component that is running on my workspace and provides me this functionality of that small server.

It has a local database of users, right, something to pull the information from. That service has very basic functionalities. And let’s see how it looks like when we’re on this locally. So, I can hit the service in a specific out and you know we get information now. As a consumer of this workspace, if I want to start building an application, I need to start understanding what is the structure of this JSON that returns for me, and what the capabilities here.

I only have first name and last name, what happens if I want to get a full name functionality? Do I need to go and ask the backend team to add this new parameter? Do I need to implement that myself? What happens if I have multiple apps that I need full name functionality and I’m going to repeat myself and write the same functionality all over again for different cases?

Another approach for solving all of this problem is creating a basic component. This is the user component. It is a Bit component, so it enjoys all the benefits of any Bit component with a dedicated delivery pipeline, independent versioning, complete isolation, the ability to build that component in any project whatsoever even if your backend is .net or java.

You can initialize Bit and build a small types of component for your front-end consumers to use if needed. Obviously, if you’re on a node.js backend, your node.js can actually use that component. And it doesn’t really have much, it has a very basic type for my user.

I can have multiple types if I need it for additional interfaces with different services. A class that represents the user in memory. A very simple toString function to/from JSON objects for me to transfer this when the data is getting shipped over the wire. Mock data is also provided in a standalone file, so consumers can just pull in all of these mock users when they build with users as part of their integration with the user service, and so on.

This is where we can, when we build a new field, when we build a new API or a new service in our architecture, start thinking about the contract. That’s something most teams already do as you have a backend team, front-end team, and an architect discuss what are the needed data points, API entries, signatures, and so on for the service. You write it down, you share it on documentation and each team then goes on to their own way and implement the components according to the decision, the discussion that was made.

So, the first thing we’ll do is build that entity component and align the contract that we just agreed on what is the API signature, what data is being shelled across. We just build a basic component and make sure this is available as a dependency for both teams, both backend and front-end.

And the contract, instead of only documentation, we actually get something in our architecture. This way, if we understand we have additional requirements, we can collaborate on the component and add additional requirements there.

So, for example, I can go and add a new function called ‘full name’, and I can collaborate on this component on the API of this component, and everyone that depends on it for the integration itself will get this functionality. And we find it to be much easier and cleaner than depend on documentation, because as you all know, we tend to upgrade our code rather than upgrade our docs.

As we discussed, the benefits for this approach is that we actually have an independent release cycle for a part of our architecture that really owns the notion of that entity. We provide developer experience for integration as opposed to having people reading complicated documentation.

There is a single source of truth for what is this entity, it’s something that later on, if documentation become outdated, because projects still have this dependency, it’s very easy to add this dependency to another project and things will just work.

You get design-time integration with the local feedback in your IDE as you build, as you work with your components. You don’t have to wait for long feedback loops with remote service calls or integrations or build the application and service.

It requires far less resources from your computer because there’s mock data. There are interfaces and everything is there for you to use. And all of the other features that are available for components, like documentation, usage examples, tests, dependency graphs, component comparing, and so on.

Now when we think about adding Bit to the mix, we start thinking from our side on how this starts scaling and what are our options, really making integration something that is easy and lightweight, as opposed to a very time consuming item in our sprints and delivery pipe.

If there are already existing services and there are already components that facilitate those entities and those services, it becomes easy for developers to reintegrate or reintroduce those entities for new projects.

For example, if we already have a system in place to manage users and registrations, but now we need to build an application or a new page that implements user profile, then we don’t have to reread documentation or reacquaint ourselves with the service signatures.

It’s just about pulling that dependency that is already there through the different search capabilities that Bit provides, we essentially can pull all of these entities and compose them together into a new page.

At the end of the day, a lot of what we do as developers is manipulate that data and we present it in different ways, and if we have a source of truth for this data point, then a lot of our work is already done for us.

Changes are essentially communicated with Semantic Versions. If there are any breaking changes in an API we can build our entire software and see what happened, and really understand in our IDE what exactly was changed. Given that we use typescript , like a strongly typed integration, we can quickly dive in and fix and resolve those new changes that could potentially break.

Another thing here is because there is another layer of abstraction between a service and a consumer through that entity component, there is a chance to reduce impact of breaking changes. If the backend service decides to change how they return data, because they need to restructure different items, there is a chance here to implement a change in the entity component in a way that will abstract that breaking change with a potential minor or patch change.

We also use this to streamline integration with external services. Sometimes we use external service providers but we also want to bring in those service providers and make them a part of our code architecture. So, we will build entity components to facilitate communication with them.

And maybe the most important is it opens up a way for collaboration on different requirements from those entities. As we showed earlier with the user entity and how we can just quickly add a username function, maybe the owner of that entity has a lot of request from various teams saying that “hey, we constantly do this one functionality on invoices, we always want to sort them by date, they never cancel the right date or we always want to have functionality to solve them.”

It’s very easy to add a single place in our architecture for the ability to sort invoices in the place that manages ‘what is an invoice’. And it makes it easier for all developers that use that functionality to just get a standard way of sorting invoices .

So, we even eliminate a lot of duplicated code and different calculations done by different developers and put them in one single place. And we know that if we fix that one single place, everything else will get fixed if we find an issue.

I want to discuss three additional examples to showcase how else we’re using this.

So, first of all, these entity components can be used, and we use them often, in react hooks. Whenever we have a hook that fetches data from a backend service, we’ll try and transform this data back to the entity itself and bring an object as opposed to a JSON for another consumer to then parse, making the flow for data fetching that much easier and that much more standardized.

There are cases in the application that is used here today for showing these slides. We actually manage different slides as entities as well. And this has nothing to do with a back end service, slides is a front-end-only application. But if I want to create a new type of slide for people to use or to share, I can just use the slide entity and build more types of slides.

The last example I show here is something called component descriptor. As you probably know, everything we do in Bit revolves around components. The component is the core thing that we care about the most, it’s in our front-end, backend, in the Bit CLI. Bit CLI also has a front-end of its own and a backend of its own in our databases, indexing providers, everything we do is about the single entity called component. And we need that thing to be standardized and agreed upon by everyone.

So, a core part in our functionality , even this entire UI that tells us which tabs a component has and the different versions, what features each component has, is a single component called Component Descriptor, which contains only for all the possible information on a specific component.

The Component Descriptor, like everything else, has a type, a class, more complex class obviously from two different functions that we want to use, and mock data that represent a component. And as you see, mocking components is hard so this needs to be sorted in a single place for one to integrate and essentially build with that component and build more features into it. And this small component that has not too many lines of code really helps us as a team to align better and build better integration with components.

Whenever there is a new feature that needs data on components and needs to understand how to present it well to find it how to parse it, there is a single source of truth that is already tried and tested, and this is what we use and what really helps us to drive forward and build more features that deal with components. So that’s how we are building and standardizing component structure in Bit.

The last item that I’d like to discuss is how to get started with this. If this is something that is interesting for you, if this is something that you feel can be valuable for your team to experiment with, I suggest just start by building a single component with a class, type, a bunch of functions, mock data, pull it out in Bit, see how integration can be more streamlined for you, how you can build a collaboration flow, how you can build discussions on this entity.

You may find out that there are different stakeholders in the organization that has different ideas and different requirements from this entity and this can help you really build the discussion around that.

You don’t have to boil the ocean and have all entities available as components. If you start with one and this flow makes sense then you can rinse and repeat and go over it over again. You can take any of the examples that we shared and use Bit fork to fork them. There’s going to be a new template to use as well, essentially everything that you need to get started.

Another thing that would be shared with this is this small application that we use to really build slide decks with Bit, will also be shared with the webinar and all the resources. So, if you want to experiment with that and build essentially slides and React it’s also a possibility.

Thank you for very much for your time.

Check out the webinar slides here.

Want to learn more? Get a demo here.

--

--

Digital nomad | Components | Modern development strategies | Love dragons