Life Codecs @ NamingCrisis.net

Ruminations. Reflections. Refractions. Code.

Feb 3, 2019 - Software dev

CSS Classes Driven Architecture + JQuery (CSSCDA+JQ™)

CSSCDA+JQ™ – an acronym that is nearly as bad as what you think it means.

I’ll keep this rant short, and mention no names to protect both guilty and innocent. I even deferred writing this so my trauma could heal in the interim.

If you wish, skip over to the “why” of this rant.

Anyway, here’s the essence of CSSCDA+JQ™ “pattern”.

The “Pattern”

Rationale

Add dynamic behaviour to a website, that is actually a web application, but refuses to acknowledge this identity. Essentially, manage the site’s identity crisis.

Approach

First, we have many — reasonably modularised (no sarcasm) — HTML templates like so:

 1<!-- template foo -->  
 2<div class="chupacabra-button">
 3  ...
 4</div>
 5
 6<!-- template bar -->  
 7<div class="spaghetti-monster-magic">
 8  ...
 9</div>
10
11<!-- template baz -->  
12<div class="yeti-lord-magic">
13  ...
14</div>
15
16<!-- template meow -->  
17<div class="pastafarian-magic">
18  ...
19</div>


Next we have a top-level site template, with 30 million conditional statements (I exaggerate, but it sure feels that way, don’t invalidate my feelings, yo):

 1<html>
 2 ...
 3 <!-- if $foo -->
 4 #include bar.js
 5 #include baz.js
 6 <!-- fi -->
 7 <!-- if $baz -->
 8 #include foo.js
 9 #include baz.js
10 <!-- fi -->
11 <!-- if $bar -->
12 #include meow.js
13 #include baz.js
14 <!-- fi -->
15 <!-- if $meow -->
16 #include woof.js
17 #include kapow.js
18 <!-- fi -->
19 <!-- if $dingding -->
20 #include urgh.js
21 #include baz.js
22 <!-- fi -->
23 <!-- if $woof -->
24 #include lala.js
25 <!-- fi -->
26 ... to 30 million 
27 ...
28</html>


Then, we have individual JS files referenced above, using plenty of JQuery to attach behaviour, like so:

1// woof.js
2$('.pastafarian-magic').on('...', function magic() {...})
3
4// ditto: (bar|baz|foo|kapow|urgh|lala..30million).js
5$('.yeti-lord-magic-ohgno-typo-in-css-class').on('...', function magic() {...});
6


Finally, you have — reasonably well-modularised (again, no sarcasm here) — controllers, setting the conditional variables referenced in the site template, and including in their relevant specific templates.

1class PastaController {
2  def foo() {
3    // ...
4    ctx.set('dingding', true);
5    ctx.template('woof');
6    // ...
7  }
8}


Ah, this marvellous application of Stringly-Typed Programming when so much behaviour is hooked in via includes, CSS classes, and many, many snippets of all-over-the-place jQuery (some containing direct DOM mark-up in — you guessed it — JS strings).

Complexity

So our potential Big-O complexity, most rigorously calculated by yours truly, is:

1O(
2  Controller Count * 
3  Template Count * 
4  JS Files Count * 
5  Magic CSS Classes Count
6)
7


In other words, we have reached O(HGNO) + O(MG) complexity. I’d say very, very close to O(KMN) complexity.

At this point, when project leads still think that bringing in a framework to manage the complexity is too much overhead, and they like that the CSSCDA+JQ™ approach is lightweight, well… it is best to find another project and/or project lead.

Simplicity, Complexity, and Cognitive Weight

I’m all for using the right tool for the job. I have biases towards those tools, but my rant above is based on very real problems: brittle, hard to follow code, with every small change taking much more time than it ideally should. And let’s not forget refactoring (and thus testing) concerns.

It’s important to understand complexity and cognitive weight:

A method with a long switch statement, but where each branch does very simple, exact tasks, e.g. a very common pattern used in simple parsers, may be long, and look ugly, but inherently, it is flat, and does not impose an excess cognitive load on the reader. Ignore for the moment using polymorphism or similar approaches for scaling better.

With CSSCDA+JQ™, on the other hand:

  • Yes, JQuery is simple
  • Yes, inherently attaching behaviour to CSS-marked elements is a common, simple pattern (yes, simple until you consider scoping, take that this).

However, it has a reached a point where, taken as a whole, the individual, simpler ideas, no longer show that simplicity. The sum of the parts is far more complex than the parts.

At this point, a newer abstraction like an MVC framework ala Vue or Angular, one that may indeed be — by itself — more complex than the individual parts that make up CSSCDA+JQ™ becomes justified because it unifies the overall concepts that CSSCDA+JQ™ was attempting to achieve, but could not scale to when used as-is.

We have (at least) two possibilities:

  1. Restructure our code, modifying the parts used in CSSCDA+JQ™ in a more scaleable way — essentially, we are creating a framework of our own.
  2. Migrate towards an external, hopefully better-maintained framework.

Essentially, we have a buy-off-the-shelf or build-your-own problem with their own tradeoffs — such is the nature of software.

Where I refuse to concede is that CSSCDA+JQ™ is okay, in the context of the scale of said project’s codebase. It is not.

Unfortunately, people develop Stockholm syndrome with software, too.

That, however, is the topic of another rant.