Question

I am building my own JS library;
The idea is that the library should be comprised of small, independent modules, and some slightly larger utilities, that serve mainly to iron out browser differences.
I am having trouble getting anything done, because I am not being able to decide between staying dry or being loosely coupled.

An example? Given:

  • A small library that takes care of generating dom elements from a template
  • Another one that takes care of duck-typing issues (is_function, is_array...)
  • And a last one that creates modal boxes. That last one needs:
    • some type checking
    • will be creating the modals using only one function from the templating library

My options for the modal box library:

  1. Be 100% dry, and dependant on the two other libraries. But that means if you are a user wanting to download only the modal box lib, you'll have to make with the two others
  2. Allow users to pass an object of options on initiation that would allow them to specify the functions needed; defaulting to the ones of the libraries. This is better, but in practice, it still means, in 90% cases, using the provided libraries, as creating functions with the same signature might be cumbersome. Furthermore, it adds complexity to the modal box code.
  3. Be 100% loose, and reproduce the functions needed in my modal box library; possibly more efficient because more targeted and there is no need to check for edge cases; but: any bug will have to be fixed in two places, and my download size increases.

So I am wasting time oscillating between the two extremes, refactoring a million times and never being satisfied.
I was going for a more generic question, but then I realized it is really pertaining to JS, because of the size & performance concern as well as the widespread usage.

Is there any known pattern to follow in such cases? What's the accepted way to go about this? Any thoughts are welcome.

[edit:]
This is the only article I found that spells out my concerns. Like the article says,

DRY is important, but so are [...] low coupling and high cohesion. [...] You have to take all [principles] into account and weigh their relative value in each situation

I guess I am not able to weigh their value in this situation.

Was it helpful?

Solution

I like the concept of DRY, but your right it has a couple of problems.

  1. Your end-user-developers will need to know that they need to download the dependencies of components.

  2. Your end-user-developers will need to know that they need to configure the dependencies (i.e. the options to pass in).

To help solve 1. your project website could customise the download on the fly, so the core code is downloaded along with optional components. Like the modernizer download page.

To help solve 2. Rather than allowing users to pass in options, use sensible defaults to detect what parts of your packages have been loaded in the browser and automatically tie them up. This loose coupling could also give you the great advantage that could also rely on 3rd party frameworks if the user already has them installed. For example selectivizr allows you to use jquery or dojo etc etc depending on what the browser has already loaded.

Perhaps you could use requirejs to help solve dependency management. I get the impression it's not really meant for libraries to use directly, but instead the end-user-developer... but it could be a nice fit.

I realise my answer doesn't answer your question directly, but perhaps it could help balance out some of the negative points of DRY.

OTHER TIPS

Personally, I've always taken the view that Loose Coupling refers to creating seams in your code. In classical languages, such as Java, this is achieved by creating Interfaces which hide the concrete implementation. This is a powerful concept as it allows developers to 'unpick the seams' in your application and replace the concrete implementations with mocks and test doubles (or indeed, their own implementation). As JavaScript is a dynamic language developers rely on duck-typing instead of Interfaces: as nothing is frozen, every object becomes a seam in your code and can be replaced.

In direct answer to your question I think it pays dividends to always aim to decompose and modularize your code into smaller libraries. Not only do your avoid repeating code (not a good idea for a host of reasons) but you encourage re-use by other developers who only want to re-use parts of your library.

Instead of re-inventing the wheel, why not leverage some of the more popular JavaScript libraries that are out there; for example, underscore.js is a lightweight library which provides a rich toolkit for duck-type checks and Mustache.js may well take care of your templating needs.

Many existing projects already use this approach, for example, Backbone.js depends on underscore.js and jQuery Mobile depends on jQuery. Tools such as RequireJS make it easy to list and resolve your application's javascript dependencies and can even be used to combine all the separate.js files into a single, minified resource.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top