Refactoring front end code by minimizing dependancies - javascript

Large web applications tend to accrue a huge array of libraries that support both front-end and back-end functionality. I want to reduce the number of dependencies in order to increase stability and ease of maintenance. I'm looking for a good path to reducing dependencies in a web app that includes libraries such as:
Bootstrap
CKEditor
Chosen/Select2
jQuery plus various plugins
d3/Raphael
SlickGrid
Handlebars
Underscore
I'm looking for techniques, languages, or frameworks that combine as many of those dependencies as possible.
Here's what I've explored so far:
Refactoring small dependencies and removing unused parts could go a long way.
React would impose discipline on the jQuery spaghetti code and reduce the need for a few of the dependencies.
Elm would go farther towards imposing discipline with its type safety.
ClojureScript would also impose discipline through a functional programming paradigm.
Except for refactoring, all of these potential solutions would introduce some additional complexity of their own in order to integrate with the Ruby on Rails back-end. React seems to have the most replacements for the current dependencies.
The safest path forward seems to be to start with refactoring and gradually introduce one of the functional languages or libraries. How would I refactor with this goal in mind? Would first refactoring to plain JS (i.e. removing jQuery) be useful?

Libraries/dependencies
Usually when I inherit a large project to refactor, the first thing to do is determine the core dependency e.g. what's the main library most of your custom code uses? From your list I can already tell underscore and jQuery are basically trying to do the same thing. Which one is the most optimized and fastest has been gradually leveled during the years. Let's assume for a second Underscore is still the fastest, you're still depending on jQuery for traversing and what not. Are you willing to include an extra library to gain micro speeds? The extra payload for each page is not worth it in my opinion.
Then Bootstrap is most likely your main CSS driver, however, it has some JavaScript abilities which might be used. Carousel, date-picker, drop-down, toggle some other widgets ... See if they are used (probably yes), if not, get rid of the Bootstrap js library. Keep in mind Bootstrap is still depending on jQuery.
Chosen/select are optional plugins. They're goal is most likely covered in Bootstrap/jQuery. Try to refactor them out.
Slickgrid is also a grid system. What's the benefit over the Bootstrap grid? Sounds like they refactored out Bootstrap. If it's used, refactor to a bootstrap grid to increase the common knowledge of the team.
Handlebars for templating. If you use the logic operators it's useful, otherwise you can easily find a small replacement function.
function renderTemplate(obj, template) {
var tempKey, reg, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
tempKey = String("{{" + key + "}}");
reg = new RegExp(tempKey, "g");
template = template.replace(reg, obj[key]);
}
}
return template;
}
CKEditor/Raphael are libraries with one specific goal in mind => wysiwyg/vector. Best to keep those but lazy loading sounds ideal. Only include them on the page when they are needed.
// after the additional library was loaded ...
cacheObj1.on('focus', this.initCKE);
cacheObj2.on('click', this.initVector);
If you're server language handles <script> includes into the <head> tag, you can choose to keep simple script references, required by the specific page in mind. Don't end up with twenty DOM ready events inline, try to end up with just one ready event to initialize everything your project needs.
jQuery plus various plugins
Bootstrap
Handlebars
CKEditor refactor to lazy loading
Chosen/Select2 refactor to core lib
d3/Raphael refactor to lazy loading
SlickGrid refactor to core lib
Underscore refactor to core lib
Application/custom JS
Now the tricky part begins. How good are your JavaScript skills and how decent was the previous programmer? If you find a lot of jQuery selectors all over the place, chances are high it's not programmed in a modular approach. The hard task of refactoring every peace of code to something configurable begins.
The idea here is to have an instance or loader file which talks to your libraries. Perhaps a custom function file (which can hold underscore functions if you prefer) to use throughout your code. Prototypes or "classes" and singletons to finish it off. A nice post about refactoring if I may add with links on how to set this up. Then a grunt/gulp setup is nothing too fancy these days. Automation for JS(npm, bower) and CSS(compass, less) can be covered on the fly.
Conclusion
jQuery is most likely your main dependency. So you will start from scratch if you take it out. All the plugins you talk about is the extra fat on page load. The less the better, but sometimes it pays off just to RE-USE other functionalities like cookie scripts, json support, polyfills, ... the list goes on and on. Try to stick with one or two core libraries and clearly separate dependencies and application code.
Don't forget to bundle and minify ^^
Happy refactoring!

Related

Downsides of using two UI libraries in the same react project?

I'm sure this is a bad idea for technical reasons but haven't found any source explaining if it is or why.
Let's say I'm building a React website and want to use two component frameworks, like ant.design and material-ui because I love 90% of what ant.design does but I just slightly prefer the modal dialogues in material-ui more and want to use those in conjunction with ant.design components.
They both seem to play quite nicely with each other.
Why is this a bad idea? Is there potential for conflict in future? Does this increase bloat somehow?
You may want to refer to this question asked yesterday for a little pointer:
How to make Bootstrap 3 and Ant Design 3 live together
As pointed out above:
Bloat - the unnecessary inclusion of code you do not need, which can be avoided through custom builds.
Duplication/Overwrite - code included by duplicate existing or merely serve to overwrite existing rules making the code 50% pointless.
Conflict - issues may arise from conflicting JS code, not least from the potential to have conflicting version dependencies.
Namespacing - as identified in the linked question, it is impossible to namespace the antd css to avoid collision with bootstrap.
Code Styles - No two libraries will be implemented in exactly the same way and you will find yourself having to navigate issues that arise from this.
In my own experience I have never found a single library/suite that delivers everything, but the closest I have found to this is Ant Design.
Visually it may not be the best, and there may be implementation/pattern issues that some developers do not like, but the reality is that the less you have to build, the quicker you can deliver, and end users will care more for functionality than they will the way your app looks. The priorities you place on these things will differ from them for sure.
I personally love the look of Material UI and others, as highlighted here:
https://hackernoon.com/23-best-react-ui-component-libraries-and-frameworks-250a81b2ac42
But the reality is, you need to look to which single framework and set of components provides the best and most complete functionality you actually require.
In my case, as mentioned, this was Ant Design; being the only one with a strong set of UI components including Date Pickers etc, without having to add more and more components into my codebase via NPM.

Wrap jQuery, dojo with custom library?

Coming from Java, I'm wondering if a Java best practice applies to JavaScript.
In Java, there's a separation of interface and implementation, and mixing them up is considered a bad practice. By the same token, it is recommended to hide implementation details of your library from end developers.
For example, log4J is one of the most popular logging libraries out there but it is recommended to write code to the slf4j library or the Commons Logging library that "wraps" log4j. This way, if you choose to switch to another logging framework such as logback, you can do so without changing your code. Another reason is that you, as a user of a logging library, how logging is done is none of your concern, as long as you know what logging does.
So back to JavaScript, most non-trivial web applications have their own custom JavaScript libraries, many of which use open source libraries such as jQuery and dojo. If a custom library depends on, say jQuery, not as an extension, but as implementation, do you see the need to add another layer that wraps jQuery and makes it transparent to the rest of JavaScript code?
For example, if you have the foo library that contains all your custom, front-end logic, you'd introduce the bar library that just wraps jQuery. This way, your foo library would use the bar library for jQuery functions, but it is totally oblivious to jQuery. In theory, you could switch to other libraries such as dojo and google web toolkit without having a big impact on the foo library.
Do you see any practical value in this? Overkill?
Although it makes sense from a theoretical standpoint, in practice I'd say it's overkill. If nothing else for these two reasons:
Anything that adds to the size of
the request (or adds more requests)
is bad - in web world, less is more.
If you're using say jQuery, the
chances of you switching to
something like Mootools is (imho) slim to none. From what I've seen, the top libraries each aim to solve different problems (at least in the case of Mootools and jQuery - see this great doc for more info on that). I'd assume that you'd incur a tremendous amount of headache if you were to try to implement a middleware library that could easily switch between the two.
In my experience and being a Java developer myself, sometimes we tend to take the whole "abstraction" layer pattern too far, I've seen implementations where someone decided to completely abstract a certain framework just for the sake of "flexibility" but it ends up making things more complicated and creating more code to maintain.
Bottom line is you should look at it on a case by case basis, for example you wouldn't try to create an abstraction layer on top of struts, or on top of JPA, just in case you then go to a different framework (which I've rarely seen done).
My suggestion is, regardless of the framework you are using, create objects and components that use the framework internally, they should model your problem and be able to interact between them without the need of any specific framework.
Hope this helps.
There are a lot of good answers here, but one thing I don't see mentioned is feature sets. If you try to write a library to wrap the functionality provided by, say, jQuery, but you want to be able to easily swap out for something like prototype, you have a problem. The jQuery library doesn't provide all the features prototype provides, and prototype doesn't provide all the features jQuery provides. On top of that, they both provide their features in radically different ways (prototype extends base objects -- that's damn near impossible to wrap).
In the end, if you tried to wrap these libraries in some code that adds 'abstraction' to try to make them more flexible, you're going to lose 80% of what the frameworks provided. You'll lose the fancy interfaces they provide (jQuery provides an awesome $('selector') function, prototype extends base objects), and you'll also have to decide if you want to leave out features. If a given feature is not provided by both frameworks, you have to either ditch it or reimplement it for the other framework. This is a big can of worms.
The whole problem stems from the fact that Java is a very inflexible language. A library provides functionality, and that's it. In JavaScript, the language itself is insanely flexible, and lets you do lots of crazy things (like writing a library, and assigning it to the $ variable). The ability to do crazy things lets developers of javascript libraries provide some really creative functionality, but it means you can't just find commonalities in libraries and write an abstraction. I think writing javascript well requires a significant change in perspective for a Java developer.
Someone wise once said "premature optimization is the root of all evil." I believe that applies in this case.
As others have expressed, you don't want to abstract for the sake of flexibility until you have an actual need for the abstraction. Otherwise you end up doing more work than necessary, and introducing unnecessary complexity before it is required. This costs money and actually makes your code more brittle.
Also, if your code is well organized and well tested, you should not be afraid of major changes. Code is always changing, and trying to anticipate and optimize for a change that may or may not come will almost always get you in more trouble than it saves you.
Acknowledgement: I should give credit to Agile programming and my practice and readings on the topic. What I've said comes directly from my understanding of Agile, and I've found it to be an extremely good razor to cut out the extra fat of my work and get lots done. Also none of what I've said is actually JavaScript specific... I'd apply those principles in any language.
There are good arguments calling this development practice - wrapping in order to switch later - into question in any language.
A good quote by Oren Eini, from his writeup on wrapping ORMs:
Trying to encapsulate to make things
easier to work with, great. Trying to
encapsulate so that you can switch
OR/Ms? Won’t work, will be costly and
painful.
This is definitely something that is done in enterprise environments.
Take for example a company that has their own custom javascript framework that is used on all of their projects. Each of the projects decide to use their own framework (jQuery, Dojo, Prototype) to add functionality to the underlying modules of the company framework. Employees that move between projects can now easily do so because their API with working the project's codebase is still the same, even though the underlying implementation could be different for each project. Abstraction is helpful in these situations.
It is overkill. Javascript is not Java and is not in any way related to Java. It is a completely different language that got J-a-v-a in the name for marketing reasons.
If you are concerned with availability of add-on libraries, then choose a framework with a large ecosystem. In an enterprise environment you will be further ahead by standardising on a vanilla off-the-shelf uncustomised web framework that you can upgrade every year or so tracking the rest of the world. And then supplement that with a SMALL in-house add-on library which you will, of course, have to maintain yourself, not to mention training any new programmers that you hire.
Since you are talking about Javascript in the client (web browser) it is more important that you limit the complexity of the things that people do with it. Don't build huge amounts of client side code, and don't make stuff that is so brittle that another programmer can't maintain it. A web framework helps you both keep the linecount down, and keep your own code reasonably simple.
It is not a question of Javascript best practice, because that would be different for server-side JS such as Rhino or node.js.
Adapter pattern is not a common solution in this case. The only example I know to use this pattern is extjs. Javascript projects are usually too small and they aren't worth the effort you would make by creating such an abstraction layer.
The common solution for this problem is that you try to use multiple frameworks together for example with jquery.noConflict.
I've done this before, and can talk a bit about the experience of writing a library/toolkit wrapper.
The plan was to move from Prototype to some other library. Dojo was the first choice, but at the time I wasn't sure whether that's the library to move everything to (and by everything I mean ~5MB of Prototype-happy JS). So coming from a world of clean interfaces, I was set to write one around Prototype and Dojo; an awesome interface that would make switching out from dojo a breeze, if that was in fact necessary.
That was a mistake that cost a lot of time and effort for a few reasons. The first one is that although two libraries can provide the same functionality, (a) their API will almost always be different, and most importantly (b) the way you program with one library will be different.
To demonstrate, let's take something as common as adding a class-name:
// Prototype
$("target").addClassName('highlighted');
// Dojo
dojo.addClass("target", "highlighted");
// jQuery
$("target").addClass("highlighted");
// MooTools
$('target').set('class', 'highlighted');
Pretty straight-forward so far. Let's complicate it a bit:
// Prototype
Element.addClassName('target', 'highlighted selected');
// Dojo
dojo.addClass("target", ["highlighted", "selected"]);
// jQuery
$("target").addClass(function() {
return 'highlighted selected';
});
// MooTools
$("target").set({
"class": "highlighted selected"
});
Now after choosing an interface for your version of the addClass you have two options: (1) code to the lowest common denominator, or (2) implement all of the non-intersecting features of the libraries.
If you go with the 1st -- you'll loose the "personality" / best qualities of each of the library. If you go with #2 -- your addClass' code will be at 4 times larger than the ones provided by any of the libraries, since for example when Dojo is included, you'll have to write the code for the function as the first param (jQuery) and the Object as the first param (MooTools).
Therefore, although it is theoretically possible, it isn't practical, but is a very nice way to understand the intricacies of the libraries out there.

jQuery Javascript large scale application development

I have just been asked to describe the architecture for a large scale dashbaord style project that i will be working on.
I have bever worked on a application of this size and am a bit lost as to what to say.
Could i be pointed in the direction of any articles that may help me get started and hopefully finished.
I have gleaned the following information thus far but i am not really sure that it describes the architecture.
1) Use classes instead of seperate functions and each class or group should be contained within their own JS file
2) Prior to production there should be a compile step where said JS files are compiled and minified
3) Step2 does not have to contain all the files. Jsut the common ones to start
4) Use a classloader to load classes, plugins etc when they are needed. On research could jQuery's getScript function be used for this or even a jQuery plugin loader:
http://api.jquery.com/jQuery.getScript/
http://www.unwrongest.com/projects/lazy/
Am feeling way out of my depth at the mo so any help would be massively appreciated. Be honest, if the above is competely irrelevant then i guess i am in the wrong job :(
Everything you need to know can be found here:
http://addyosmani.com/largescalejavascript/
Create a library of loosely couple components that communicate through an application controller (e.g. event bus).
I would recommend looking at using ExtJS 4 for this. Its APIs and development methodology closely track what you would expect from .NET or Java for developing a large-scale desktop app.
Version four answers all four of your points. It has...
1) A system for defining Java/C#-like classes in Javascript that work almost exactly the way a Java or C# developer would expect.
2) Dynamic resource loading.
3) The ability to create a final product from the SDK which is a neat, compressed version which contains just what you need.
If you are to do this with pure Javascript, ensure you use some reference architecture in the job. What HDave pointed above is really good material. If you want a ready-made reference architecture as a project startup code, have a look at BoilerplateJS:
http://boilerplatejs.org
After some large-scale projects, I have compiled some of the learnings in to this framework. Look at the samples too. Some of the concerns you raised are already addressed in this codebase such as use of OO concepts, minification and optimizations, decoupled moduler design and many more too.

rails best practices where to place unobtrusive javascript

my rails applications (all 2.3.5) use a total mix of inline javascript, rjs, prototype and jquery. Let's call it learning or growing pains. Lately i have been more and more infatuated with unobtrusive javascript. It makes your html clean, in the same way css cleaned it up.
But most examples i have seen are small examples, and they put all javascript(jquery) inside application.js
Now i have a pretty big application, and i am thinking up ways to structure my js. I like somehow that my script is still close to the view, so i am thinking something like
orders.html.erb
orders.js
where orders.js contains the unobtrusive javascript specific to that view. But maybe that's just me being too conservative :)
I have read some posts by Yehuda Katz about this very problem here and here, where he tackles this problem. It will go through your js-files and only load those relevant to your view. But alas i can't find a current implementation.
So my questions:
how do you best structure your unobtrusive javascript; manage your code, how do you make sure that it is obvious from the html what something is supposed to do. I guess good class names go a long way :)
how do you arrange your files, load them all in? just a few? do you use content_for :script or javascript_include_tag in your view to load the relevant scripts. Or ... ?
do you write very generic functions (like a delete), with parameters (add extra attributes?), or do you write very specific functions (DRY?). I know in Rails 3 there is a standard set, and everything is unobtrusive there. But how to start in Rails 2.3.5?
In short: what are the best practices for doing unobtrusive javascript in rails? :)
I do not think there is one best practice, but I'll let you know what I do.
I have a series of js files each for with their own purpose in the public/javascripts/ directory. Some examples could be utility.js chat.js shopping_basket.js and so on.
I use asset packager and define one big fat collection for all my general use functionality and another for admin only functionality. Round trips to the server cost way too much. I basically include all the js in on first page load minified into one blob (in general)
I allow basic $(document).ready hooks inline in the pages, and keep them really short.
Data that my js files needs to access is rendered inline with the page. (Usually in the DOM, sometimes as vars - Eg. var xyz = 100)
I will usually develop my controllers with javascript off (and make sure it all works), then I turn it on and sprinkle a few if request.xhr? where needed.
Keep in mind, Rail 3.1 introduces a built-in best practice, see: http://guides.rubyonrails.org/asset_pipeline.html - on a personal note I have had performance and configuration issues with the new pipeline, however many others have had great success with it.
I recently documented how I have been managing javascript in Ruby on Rails. I basically break things down into many small, granular files, each with an appropriate namespace and then merge them all into a single file for production using asset_packager.
I found this post while trying to solve the same problem, but none of the existing solutions struck me as the right one. I wrote up my approach here. I love Rails' convention over configuration, so I wanted the same approach to including Javascripts that are applicable only to a particular action page. If nothing else, it's at least another approach to add to your options.

How do you manage your DojoX code?

How are you managing your usage of DojoX code or widgets in a production application?
The Dojo Toolkit is comprised of Core, Dijit, and DojoX. As an incubator for new ideas to extend the toolkit, DojoX code and widgets are functional with varying degrees of instability.
DojoX Code like QueryReadStore (for fetching batches of data from the server) or widgets like Grid (for utilizing a user interface grid component) are not included in Core or Dijit. But they are functional enough to utilize in some cases, with the caveat "developer beware", because in future Toolkit versions the API or the component location in the source tree might change. Another catch is that you may have to tweak the DojoX component you are using for it to function properly in your environment, as there's not yet a high degree of robustness in the code.
So, how are you ensuring that as the DojoX components you use evolve, your application stays on a smooth track?
This may be an obvious, but much more involved, solution ... but: Get involved! It actually is one of the best ways to familiarize yourself with the overall power of Dojo in one sitting, teaches a lot of good JS-foo, and ensures you have inside information as to the future of a particular module. Most of DojoX is community contributed, and aiming for stability and usefulness. The more people reviewing, testing, hacking on the code -- the more likely it is to succeed and become stable.
Regards,
Peter Higgins
There are several ways to do it:
Stick to one version of Dojo and use it consistently.
Move modified code to your own namespace and include it from there.
Effectively it is a forking of an existing DojoX module. All code syncing and back porting is your responsibility.
Pay attention to the rest of Dojo — if it changes in such a way that it breaks your forked version, be ready to patch your module as well.
Copy modified files somewhere and include/require them before the original file is required.
To illustrate the latter technique imagine that there is one file I want to patch located in dojox/charting/abc.js:
dojo.provide("dojox.charting.abc");
// the rest of the file
...
I can copy it to my directory as, say, my/patched_abc.js, and make it look like that:
dojo.provide("my.patched_abc");
// now I include the rest of the file with my modifications
dojo.provide("dojox.charting.abc");
// the rest of the file
...
In my code that uses dojox.charting I include it like that:
dojo.require("my.patched_abc");
// now I can include dojox.charting,
// which will use my patched dojox.charting.abc module
dojo.require("dojox.charting.Chart2D");
// the rest of the file
...
Just be careful to avoid circular "require" statements.
This technique works very well for backports and minor customizations. If your changes are more extensive than that, you should consider writing your own module.

Categories