Avoiding Vendor Lock-In

Avoiding Vendor Lock-In

What is the Vendor Lock-In?

Vendor lock-in is state of (not only) software lifecycle when the development team can’t change third-party technology without additional cost.

Let’s explain this concept by life example. I suppose that you like to drink coffee with sugar. You can’t imagine drinking coffee without sugar. In fact, you are addicted to sugar. But that’s still a normal situation and it’s not vendor lock-in. Why?

Because you can change sugar vendor whenever you wish, especially replace white sugar with brown sugar. Nay, you can replace sugar with sweetener! I know that the sweetener doesn’t taste like sugar but you have such opportunity. Simply, you can change your sweet taste for a coffee vendor at any moment of your life and the only one cost of the change is when you go to the shop to buy another sweet taste package.

So when we can speak about vendor lock-in? For example when you bought an ink-jet printer. It’s obvious that you must buy cartridge designed for your printer model. Usually, the price of cartridges is improperly hight, comparing to the printer value. That’s the classic sample of vendor lock-in direct from life away from a keyboard. So you are constrained to bear switching costs because you can’t change cartridge type without the printer model replacement.

Vendors in Software Project

We know now what the vendor lock-in problem is in general. But what vendors we can identify in a software project? It depends what kind of software you are developing. In general, it’s each piece of code developed independently of your development team. Probably you have contact with 3rd party software types, described below.

  • a database
  • an MVC framework
  • a library

Wrong Way

Each developer resists to the temptation of too fast coding. When he must introduce new functionality with brand new library into the project sometimes he uses the library directly in the code.

Let’s analyze internationalization of an React Native application case to show the issue.

import { Component } from 'react';
import { Image } from 'react-native';
import { FormLabel, FormInput } from 'react-native-elements';
import i18next from 'i18next';

export default class PasswordInput extends Component {
  render() {
    return (
      <View>
        <FormLabel>{i18next.t('login.password')}</FormLabel>
        <FormInput
          secureTextEntry returnKeyType={'go'}
          onChangeText={(password) => this.setState({ password })}
          value={this.state.password}
        />
      </View>
    )
  }
}

The issue is in line 4 where we’re importing i18next library directly. That’s very good internationalization library available here. But let’s suppose we used i18next in many files in our project and in future somehow we will want to change internationalization library to another. In such situation we would have to change each import and each use of i18next in our codebase. That’ll be a lot unnecessary work.

Good Direction

So let’s introduce our own internationalization class named I18n! It will be simple Adapter design pattern implementation.

import i18next from 'i18next';

export default class I18n {
  /**
   * @public
   * @param {string|string[]} keys
   * @param {object} [options]
   * @returns {string}
   */
  static t(keys, options) {
    return i18next.t(keys, options);
  }
}

Please note that above I18n class is only real adapter stub for simplifying the example. There are needed dictionary initialization, language change, and many more abilities.

We can use out little adapter everywhere in the codebase. Code sample after above refactor:

import { Component } from 'react';
import { Image } from 'react-native';
import { FormLabel, FormInput } from 'react-native-elements';
import I18n from '../locales/I18n';

export default class PasswordInput extends Component {
  render() {
    return (
      <View>
        <FormLabel>{I18n.t('login.password')}</FormLabel>
        <FormInput
          secureTextEntry returnKeyType={'go'}
          onChangeText={(password) => this.setState({ password })}
          value={this.state.password}
        />
      </View>
    )
  }
}

It’s a bit more of work. But believe me, some day you will be happy that migration to another library will be easy. One thing to do is reimplement the adapter class.

Changes Everywhere

The point of avoiding vendor lock-in is readiness for fast and low-cost changes. Doesn’t matter what part of your application needs the change.

Sometimes will be an addition next file format at reports generation module. Here you would just implement specific code for each format and use common code.

Another time will be a more tricky task, ie. replacement database by brand new cloud-friendly technology supporting big data ideas. In this case, probably you have an essential layer of abstraction. ORM-like technologies are used in many projects. DAO, Repository, Active Record patterns are used also often.

What about MVC framework, ie. in a web application? Framework migration request isn’t possible, is it? Well, not really. Imagine that your framework support was dropped. The only one solution will be… project migration to another constantly developed framework to ensure at least security fixes for your application. It’s possible! You should only move your logic code from controllers to services, if you didn’t this yet.

Be Ready

Whatever you do, keep in mind that technical debt of your project shouldn’t be too hight if you want that your application will be elastic for future changes. No debt isn’t also solution because it’s a waste of time. So optimal solution will be technical dept monitoring at a moderate level.

To sum it up, please remember one rule: Be ready for changes.

One thought on “Avoiding Vendor Lock-In

  1. Pingback: react-native-firebase vs react-native-fcm - Borsuque Squad

Post a comment