The Copy/Paste Conundrum

We’re covering just a quick bit of refactoring today on the Devblog.  Next week we’ll be back to longer, rambling posting!

In our Angular application (which version?  remember- now It’s Just Angular!) we have a ‘setup’ module.  It allows an admin to edit certain values in the database (payment types, exchange rates, active states, etc).  Views in this module also include some reporting (charts, total items, etc).  In order to ensure everything updates when a change is made, we used a shared ‘setup.service’ class, stored the data as Behavior Subjects (each an array of objects that can be converted into an Observable with .asObservable()), then subscribe to the resulting observable in the components themselves.

I know Observables are usually though of as being used with ‘live’ data- coming from a database like Firebase, that can broadcast out updates in real time.  We don’t do that (we are using SqlServer), but found that Observables can still be useful in a single page application.  When data is saved in the ‘edit form’ area of the page, we can manually fire the Behavior Subject’s .next() function to get the latest data updated ‘live’ into the reporting area.

Anyway- that long intro was just to provide background.  The actual refactoring was in the setup.service class.  We have a whole bunch of Behavior Subject/Observable pairs initialized here (for all the types of data we want to update and subscribe to in this Setup section).  We also had multiple people adding methods for updating data to this class.  So, developer A creates a method for ‘getAuditTypes’ – to get a Json response with all the possible audit log types from the database.  It looked a little like this:

getTypes() {
    this._backendService.getData(CONFIG.auditTypesApiUrlBase)
        .subscribe(fetchedTypes => {
            this._activityTypes.next(fetchedTypes);
            this.getAuditCharts();
            this.getSetupBarCharts();
        },
        error => {
            this._notificationService.showNotification({ message: 'Error Getting Activity Types', type: 'error' });
    });
}

It uses a backendService method (which is just a helper to make sure the right authentication and headers are set on http requests) to call out, get the data, subscribe to the response, call the .next method with the new data and update any charts.  Works great- but as more views were added and data was being fetched, more of these methods were being added to the setup.service class (each person who worked with this file would just add a new method to get the data they needed).  In the end, we had almost 20 methods that were almost identical to the one above (with the exception of the api route and behavior subject name being called.  Great to get things working quickly (just a bit of copy/paste), but terrible for maintainability (edits or updates to the logic would have to be repeated almost 20 times).

So, we just refactored the method to receive a couple arguments.  Now there is one shared method to get data for the setup section (instead of 20).  It looks very similar:

getSetupData(apiUrl: string, nextTitle: string) {
    this._backendService.getData(apiUrl)
        .subscribe(response => {
            this[nextTitle].next(response);
            this.getAuditCharts();
            this.getSetupBarCharts();
        },
        error => {
            this._notificationService.showNotification({ message: 'Error Getting Activity Types', type: 'error' });
    });
}

Almost identical- except for a couple new arguments.  In the component (class) that uses this shared service, we pass parameters specific to the data being retrieved and the array being updated:

this.setupService.getSetupData('http://yourdomain.com/api/apiendpoint', '_behaviorSubjectName');

This way, we get the specific data we need to the component, but don’t have a whole bunch of unnecessary copied methods on the service.  Oh, and did I say this would be short and not rambling?  Too late… Sorry.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s