Last active
August 29, 2015 14:14
-
-
Save toddbranch/fde6f7a156daebf97963 to your computer and use it in GitHub Desktop.
Hiding Implementation Details in Javascript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Code snippets from 8facd2c613eee0c81581e840c33b1d5a4770d935 | |
| // No need to understand how they work, just need to know that: | |
| // removeArticle is the interface that client-side code uses | |
| // removeArticleFromTemplate and getTemplateFromProduct are internal helper functions | |
| /** | |
| * Remove an article at the specified index | |
| * | |
| * @param index | |
| * @returns {*} | |
| */ | |
| removeArticle: function (index) { | |
| var metaData = this.get('metaData'); | |
| var article = metaData.articles[index]; | |
| if (article) { | |
| this.removeArticleFromTemplate(article); | |
| metaData.articles.splice(index, 1); | |
| this.set({metaData: metaData}); | |
| } | |
| return this; | |
| }, | |
| removeArticleFromTemplate: function (article) { | |
| var product = this.getTemplateFromProduct(article.product); | |
| var templates = this.get('templates'); | |
| var articles = templates[product].articles; | |
| var index = _.indexOf(articles, article); | |
| if (index > -1) { | |
| articles.splice(index, 1); | |
| this.set({templates: templates}); | |
| } | |
| }, | |
| getTemplateFromProduct: function (product) { | |
| return product === 'honeymoons' ? 'honeymoon' : product; | |
| }, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Code snippets from 8facd2c613eee0c81581e840c33b1d5a4770d935 | |
| // Since all of the functions (removeArticle, removeArticleFromTemplate, and | |
| // getTemplateFromProduct) are attached to the view, they are all publicly accessible. | |
| // This leads me toward attempting to test them. But testing the removeArticleFromTemplate | |
| // and getTemplateFromProduct makes any refactor attempt on removeArticle onerous. | |
| describe('getTemplateFromProduct', function() { | |
| it('should return honeymoon for honeymoons', function() { | |
| expect(model.getTemplateFromProduct('honeymoons')).toBe('honeymoon'); | |
| }); | |
| it('should return product for everything else', function() { | |
| expect(model.getTemplateFromProduct('destination')).toBe('destination'); | |
| expect(model.getTemplateFromProduct('local')).toBe('local'); | |
| }); | |
| }); | |
| describe('removeArticle', function() { | |
| var article; | |
| beforeEach(function() { | |
| article = {}; | |
| }); | |
| it('should remove local articles from metaData', function() { | |
| article.product = 'local'; | |
| model.addArticle('local', article); | |
| expect(model.get('metaData').articles.length).toBe(1); | |
| model.removeArticle(0); | |
| expect(model.get('metaData').articles.length).toBe(0); | |
| }); | |
| it('should remove honeymoon articles from metaData and honeymoon', function() { | |
| article.product = 'honeymoons'; | |
| model.addArticle('honeymoons', article); | |
| expect(model.get('metaData').articles.length).toBe(1); | |
| expect(model.get('templates').honeymoon.articles.length).toBe(1); | |
| model.removeArticle(0); | |
| expect(model.get('metaData').articles.length).toBe(0); | |
| expect(model.get('templates').honeymoon.articles.length).toBe(0); | |
| }); | |
| it('should remove destination articles from metaData and destination', function() { | |
| article.product = 'destination'; | |
| model.addArticle('destination', article); | |
| expect(model.get('metaData').articles.length).toBe(1); | |
| expect(model.get('templates').destination.articles.length).toBe(1); | |
| model.removeArticle(0); | |
| expect(model.get('metaData').articles.length).toBe(0); | |
| expect(model.get('templates').destination.articles.length).toBe(0); | |
| }); | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // How can we fix this? | |
| // The removeArticle tests are comprehensive, so we can eliminate testing the | |
| // getTemplateFromProduct helper function. But we still have the problem of it | |
| // being publicly accessible. How do we fix that? | |
| // We can extract the helper functions out of the view and put them at the top | |
| // of the define block. That way, they are accessible in the functions via closure | |
| // but can't be accessed elsewhere. | |
| // These changes implemented in 0a38520f1651fce67162c5e50e5c9397e336e64c | |
| function removeArticleFromTemplate(model, article) { | |
| var product = getTemplateFromProduct(article.product); | |
| var templates = model.get('templates'); | |
| var articles = templates[product].articles; | |
| var index = _.indexOf(articles, article); | |
| if (index > -1) { | |
| articles.splice(index, 1); | |
| model.set({templates: templates}); | |
| } | |
| } | |
| function getTemplateFromProduct(product) { | |
| return product === 'honeymoons' ? 'honeymoon' : product; | |
| } | |
| return Backbone.View.extend({ | |
| /** | |
| * Remove an article at the specified index | |
| * | |
| * @param index | |
| * @returns {*} | |
| */ | |
| removeArticle: function (index) { | |
| var metaData = this.get('metaData'); | |
| var article = metaData.articles[index]; | |
| if (article) { | |
| removeArticleFromTemplate(this, article); | |
| metaData.articles.splice(index, 1); | |
| this.set({metaData: metaData}); | |
| } | |
| return this; | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment