I'm trying to make a large (~10K lines) javascript code base more maintainable. Pretty much all of the code is contained in one massive class. I want to do some refactoring, but I don't want to completely rewrite the code.
I have two ideas for how to re-organize the code, but I'm not sure which one is best. (I'm very open to other ideas too) What do you think about each of these approaches? How would you decide which is best?
Idea 1 – Decouple markup from business logic.
We have a somewhat complicated set of rules for what and how things should be displayed to users. This approach would split that into "What do we display?" and "How do we display it?"
Idea 2 – Break apart separate components into their own class.
There are several somewhat disjoint components in this code. If this code base were Facebook's – this approach would involve pulling apart the code for photos and the newsfeed.
If we are talking about Javascript, chances are you are using it in a browser. That being the case, most of your code is about views. A MVC pattern won't help you that much because most of your code will handle views.
Remember Javascript is not class based but prototype based. It is also functional. Functional programming excels in manipulating data. Try using the functional aspects of Javascript when doing so.
I suggest you try to split your project into a common framework for retrieving, manipulating and pushing data for all your views; and then splitting your view code into components.
If we are talking about 10k lines, you had to develop some sort of backbone to handle common tasks. If you don't use jQuery, after reorganizing your code, compare your implementation to jQuery's solutions and if you see an improvement, you can start refactoring inside your code.
If you have a chance take a look at Ext JS source code: http://www.sencha.com/products/extjs/download/ext-js-4.0.2a/213
To answer your question: Yes.
I'm not sure what you mean by 'refactor, but not rewrite'. Refactoring code shouldn't change external behaviour, but refactoring will certainly involve some sort of moving code around and whatnot.
Generally, separating the markup from the business logic is a good idea: it's following the model-view-controller pattern, effectively making your markup code 'view' code, and your business logic 'controller' code.
Breaking your code apart into separate components is likewise a good idea. Breaking your code into individual classes supports the idea of having classes with high cohesion and low coupling, and generally moves you towards more SOLID object-oriented design.
If you're asking which one will be more beneficial, that's something that can't be evaluated by the SO community, that's something you have to decide.
Oversimplified, you need to first figure out, in technical terms, what your desired architecture definition is. What is your main file (high-level) responsible for, what your low-scale modules are, and how they will be communicating (directly or vicariously). Should you abstract away the external frameworks at this stage? I am a fan of EDA's (Event-Driven Architectures), Fractal Hierarchies, and Mediation (Mediator Pattern), but many other definitions exist. Choose one that suits the scale of your project and can scale out.
Derive a blueprint and procedure for how you'll get your architecture from A to B. You may want an Abstract Procedure to entail a convention. For instance, "Redundancies: use Decorators" and so on. Do you favor composition over inheritance? However, you should have a Concrete Procedure for how to execute your game plan. E.g: "Replace references to 'X' with Mediator", "Let Save() dispatch a signal on the 'validation' channel", etc.
Make sure you're reflecting your views precisely with your JavaScript compositions. Because it's always a pain to balance unparallel hierarchies -- this ALWAYS leads to entropy. And try to embrace the (noted above) SOLID principles.
I wished to elaborate more, but I hope this is a good start for you.
Related
Its common knowledge that DOM manipulations should not be performed in AngularJS Controller, its very hard however to find why exactly is it a bad thing. All the sources say its difficult to test and because controller should be used for communication between directives, but fail to illustrate with code why this is a bad thing.
From my understanding I would think that controller, unlike directive, is not associated with any specific HTML, hence all the DOM modifications controller would do would very possibly fail. This would sure complicate development and testing.
Controller in directives being executed before link functions of child directives would also fail as the controller might not be aware of what the actual HTML of the child directives is. Link is executed after controller function and might modify HTML structure.
I hope I make sense here and if someone could clarify why manipulating DOM from controller is a bad thing, maybe some code exampleor link that explains it well that would be great.
The reason it is more difficult to prove their point with a code sample is that the reason can't really be represented by a short code snippet (short enough for Stack Overflow). It is really a maintainability precaution. Over the long term, you want to be able to independently alter the logic behind controllers and views independently, because otherwise a coupled controller and view pair tend to stay that way and limit each other in their ability to change their functionality without breaking the other. As soon as you decide to change anything about the view, you have the chance of making your controller code break without even touching it.
Testing becomes easier over time because the more tests you have, the more you wish that things were more modular and dependent on as little variables and parameters as possible.
Again, it is maintenance that drives this suggestion. The problems listed above might not be that bad starting out. But imagine adopting a project that you didn't build from the ground up and know all the intricacies behind the coupling between controller and view that hold this application together. What if your application reaches so many thousands of lines of code that it would be impossible for you to know all these intricacies even if you DID build it from the ground up?
For a more general understanding of why design patterns like the one you have alluded to are necessary, you can refer to this google search that will take you on a journey as long as you are willing to take. And for a general understanding of why design patterns even exist and why many people end up suggesting the same thing over and over again, you can refer to one of the catalysts to the introduction of design patterns, Christopher Alexander. He shows us that patterns are what they are because they work well and people repeat what works well.
If you look at the ever so popular question "Thinking in AngularJS" if I have a jQuery background? you will get some hints.
One of the biggest factor that i think DOM manipulation is neither needs nor done is because Angular uses declarative approach when it comes to DOM linking as against the imperative approach that you would use with direct DOM manipulation. Some of the answers detail this difference between declarative and imperative approach.
With jQuery you tell the DOM what needs to happen, step by step. With
AngularJS you describe what results you want but not how to do it.
More on this here. Also, check out Mark Rajcok's answer.
A more comprehensive treatment of this topic is also available here What is the difference between declarative and imperative programming
With such an approach the controller implementation is simplified, and we start to get real value as code base size grows and complexity increases.
My perspective is bit different and covers more than testing. It is the ability of the designer to have control over the HTML layout that otherwise would be taken over by writing code inside of the Angular Controller. Consider the following snippet (it is just a simple example)
<div ng-repeat="article in articles">
<p class="article-body">{{article.text}}</p>
</div>
This example just iterates over a collection and prints article in a separate paragraph tag. While it is certainly possible to loop over the collection in an Angular Controller and dynamically generate paragraph tags with text inside it. It will take away designer's capability to modify look & feel. Hence, If there is a requirement to show the article title, instead of doing this
<div ng-repeat="article in articles">
<span class="article-title">{{article.title}}</span>
<p class="article-body">{{article.text}}</p>
</div>
the designer will now have to locate Angular Controller code to modify DOM manipulation. Just compare above two approaches and guess which one will provide more flexibility.
I come from a background in Haskell. I'm very used to getting things done with recursive functions and the typical higher-order functions (folds, maps, filters, etc) and composing functions together. I'm developing in node.js now, and I'm seriously tempted to write my own modules implementing these functions so I can use them in my code in a way that makes sense to me.
My question is, basically: is Javascript set up to handle this type of burden? I understand that the aforementioned recursive functions can be easily refactored into iterative ones, but often times I find myself calling a lot of functions within functions, and I don't know if Javascript can handle this type of thing well. I know that things like Underscore exist and implement some FP principles, but my question basically boils down to: is it good practice to program functionally in Javascript? If not, why not?
I also apologize if this question is a little too soft for SO, but I don't want to start putting together my own tool set if it's just going to break everything once it gets too large.
In my opinion, the short answer to your question is yes -- applying functional programming principles is viable in Javascript! (I believe that this is also true for most other languages -- there's usually something to be gained from applying FP principles).
Here's an example of a functional parser combinator library I built in Javascript. (And here it is in action). It was important to be functional because: 1) it allows me to build parsers by composition, which means I can build and test small parsers independently, then put them together and have confidence that the behavior will be the same, and 2) it makes backtracking super easy to get right (which is important because the choice operator backtracks when an alternative fails).
So these are FP principles (note the absence of recursion, folds, maps, and filters from this list) that I found extremely useful in building my library:
avoiding mutable state
pure functions (i.e. output depends only on input)
composition: building complex apps by gluing together simple pieces
It's usually quite easy and pleasant to apply these in Javascript because of Javascript's support for:
first-class functions
anonymous functions
lexical closures
but here are some things to watch out for:
lack of popular library of efficient functional data structures
lack of tail-call optimization (at least at the moment)
partial application is more syntax-heavy than in Haskell
lots of popular libraries are not especially functional
the DOM is not functional (by design)
However, your last comment -- "I don't want to start putting together my own tool set if it's just going to break everything once it gets too large" -- is a good one. This is basically a problem for every approach, and I can't tell you whether FP in Javascript will be more problematic than "mainstream" techniques when things get too large. But I can tell you that in my experience, FP in Javascript helps me to prevent things from getting too large.
I have some procedural javascript code that I have written for an open-source application and I'd Like to refactor it into OOP and since I have very little experience with javascript frameworks I have trouble finding a one suitable for my needs, though I haven't tried anything yet, I just read about AngularJS, Backbone.js and Knockout.
I want to structure the code, because, at the moment, there's a mess, global variables and functions scattered around.
I have to mention that all the business logic is handled at the server level, so the client-side code handles just the UI using the data it receives or requests from the server.
The code can be found here:
https://github.com/paullik/webchat/blob/asp.net/webchat/Static/Js/chat.js
Do you have any suggestions?
Object-Oriented JavaScript is not necessarily the answer to all your
problems.
My advice is to be careful the choice you pick on this topic.
In practice, OO-JS can add more complexity to your code for the sake of trying to be more like traditional object-oriented languages. As you probably know, JS is unique.
It is important to know that there are Design Patterns that will structure your code and keep implementation light and flexible.
It is Design Patterns that I see structuring advanced JS
implementations, not OO. To paraphrase Axel Rauchmeyer - "Object
Oriented methodology does not fit into basic JavaScript syntax, it is
a twisted and contorted implementation, and JS is far more expressive
with out it."
The root of this analysis boils down to the fact that JS has no class. In essence, since everything is an object, you already have object-oriented variables and functions. Thus the problem is slightly different than the one found in compiled languages (C/Java).
What Design Patterns are there for JavaScript?
An excellent resource to check is Addy O' Somani and Essential Design Patterns.
He wrote this book on Design Patterns in JavaScript.
But there is more... much more.
A. require.js - There is a way to load modules of JS code in a very impressive way.
These are generally called a module loaders, and are widely considered the future of loading js files since they optimize performance at runtime. yepnope and others exist. Keep this in mind if you are loading more than a few js files. (moved to top by request).
B. MVC - There are dozens of Model View Controller frameworks to help you structure code.
It is a Pattern, but may be unreasonable for your purposes. You mentioned backbone, knockout and angular... Yes. These can do the trick for you, but I would be concerned that they might be 1) high learning-curve, and 2) overkill for your environment.
C. Namespace or Module Pattern. Are probably the most important for your needs.
To solve global variables just wrap them in a namespace and reference that.
These are very good patterns that give rise to module loaders.
D. Closure - You mentioned OO JS. On piece of this that is useful is the notion of closures to provide yourself with... private members. At first this is a cryptic idea, but after you recognize the pattern, it is trivial practice.
E. Custom Events - It becomes very important to not use hard references between objects. Example: AnotherObject.member; This is because it will tightly couple the two objects together and make both of them inflexible to change. To solve this, trigger and listen to events. In traditional Design Patterns this is the Observer. In JS it is called PubSub.
F. The Callback - The callback pattern is what enabled AJAX and it is revolutionizing development in terms of Window 8, Firefox OS, and Node.js - because of something called non-blocking-io. Very important.
Do not be afraid. This is the direction to go for long-term and advanced JavaScript implementations.
Once you recognize the patterns, it is down hill from there.
Hope this helps.
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.
I'm seeing a rise in the number of projects online that require additional "short" syntax to generate underlying code (commonly HTML and JS), and every time I see another pop up I wonder if I'm missing something.
Surely the additional time taken to learn and remember these shortcodes is lost when passing projects between different team members (designers et al) who then have to relearn basic languages such as HTML and JS?
Point in question: YAML being used for generating templates, and projects (such as) CoffeeScript used to generate Javascript. I'm just wondering if other Stackoverflow folk think that there's major benefits to this granular level of abstraction, or if there's a feeling that these types of projects have any lifespan, considering the improvements in the base technologies (I'm thinking HTML5 / CSS / JQuery) here. Have markup languages not evolved enough to really warrant these?
Realise this isn't really a question as such, but would be interested to hear the community viewpoint. I'm sure there are genuinely good reasons for these types of projects when creating self generating code, but outside of that, I'm puzzled - with many folks using them day to day. Is this a bandwagon worth jumping on?
Personally I don't think that it's worth it as most things you can do in javascript are already simplified by libraries such as jQuery. As far as their lifespan goes it's hard to tell. However, as long as you know javascript, and you understand the code output, moving to a new project that isn't using CoffeeScript for example is a simple matter of taking the output code with you.
Any sufficiently complicated program contains an implementation of Lisp.
This is the ideology that Lisp and friends promote over many years. Basically, you're discouraged to code any application logic in a "raw" language. Raw languages are universal and low level, so your logic quickly gets verbose and contaminated with lots of code needed to support the language itself.
Instead, create a DSL that suits your application best and code your logic, and nothing but the logic, in this DSL. Hide all nasty language details behind the DSL. This makes the logic much easier to improve and support.
On the other side, things like Coffescript, Groovy etc are IMO the wrong way to go. They are basically trying to create new universal languages but with a "better" syntax, however, this doesn't solve the fundamental problem - these languages still describe abstract calculations rather than your problem domain. A more productive way is to have a very basic underlying language and a well-developed macro facility that would simplify creating DLSs. This is how lisp itself works, another example of this approach is Haxe/Neko.
In my opinion I prefer jQuery for writing short JS instructions and prevent everyone from bloating the final product. I don't like css frameworks because we are building huge portals and you don't always need all of the stuff hidden inside these. I prefer writing modular css based on some common rules like using clearfix for clearing an using a css reset. :)