DEV Community

Juan José Bermúdez
Juan José Bermúdez

Posted on

Creating declarative UI-rich apps without learning any declarative framework like React or Vue.js

Apparently, I am obsolete. After 15+ years of experience as Software Engineer, turns out that the market demands new skills for which I am apparently not prepared. This is the result of me having been working all my life in startups in which I was the founder and therefore not needing to adapt to any trend but just make decisions based on the goals of the company and my engineering experience. My philosophy has always been: DO NOT USE FRAMEWORKS unless you are locked in a small room and a silver back gorilla forces you to. I don't even need a rationale for justifying that. It's just something that pops up to my mind every time (and there have been many times) in which I had considered making an exception. Now, my brain just tells me: "Don't even try. You know how it's going to end."

But now all my startups have failed (for reasons having nothing to do with the quality of the software) and I'd like to work for a company. I see the list of available jobs and a high percentage of jobs require experience in React JS or Vue.JS. I am not sure if I am going to be refused just because of my age, my nationality, my ethnicity, my profile picture, my exclusive experience in own-funded startups, or my ideas (like this post), and therefore I should just focus on working as a freelance contractor, but I decided to give it a try and learn these tech stacks (React JS and Vue.JS).

Therefore, I spent a few weeks learning React. I passed some online tests and got some certificates (the first one took me 3 minutes to complete it). Even a certificate of advanced level in React JS. I also developed a simple app to test my knowledge. Everything seemed under control. But then I tried the definitive test that would bring me access to opportunities in a list of remote jobs in American companies... and I didn't pass it. Blocked for some months to even trying again. Because I am obsolete... and I can't do what the small kids can do. That's the theory.

So I made an experiment. Let's develop a not so simple app in React JS 16.8++ (for my surprise turned out that even knowing React JS you are already obsolete if you are not a master in React JS 16.8++). And let's see how much I am blocked because of my lack of experience in React JS 16.8++. I started this experiment just after failing the test. The result is here.

Poker game in React JS 16.8++
A Poker Game developed in React JS 16.8

Turned out that for a project taking me around 48 hours in total, I only spent about 2 hours blocked because of my lack of experience with React JS 16.8++. A project that took me 48 hours (6 journeys) and I bet it would have taken more time to 90% of engineers having experience with React JS 16.8++++ (maybe there are too many pluses here).

The result didn't surprise me at all, as I have found something similar happening many times with many other technologies that I had to use in the past. But for confirmation, I decided to go a step beyond in my experiment. Let's now develop the exact same project in Vue.js without even having written a single line of code in this stack ever in my life and not having passed any test. The result is also here. It took me three days to adapt the code from React JS to Vue.JS and get the exact same final application running. Again, I very much doubt an experienced Vue.js developer would have done it in less time. Why I doubt that? Because I have hired developers many times in the past.

Now I was triggered. Could I even go a step beyond on my challenge to the establishment? Could I even develop the same exact project in Vanilla JavaScript, reusing 95% of the code from previous projects, and in a shorter time than what took me to adapt from React JS to Vue.js? And the answer is yes, I could. It took me about two and a half journeys to do that. The result is here.

So, after the rant from the old guy, let's go to the grain and see how I did develop a declarative UI-rich app just with Vanilla JavaScript (or Typescript to be more precise).

This is one of my React JS components:

type HandProps = {
    cards: Array<string>
}

export const Hand = (props: HandProps) => {

    const listCards=props.cards.map( card =>{        
        return <Card key={card} card={card}/>
    }

    );
    return <div className="Hand">
                {listCards}
           </div>
}
Enter fullscreen mode Exit fullscreen mode

This is the equivalent component in Vue.js:

<script lang="ts">
    export default {
      data() {
        return {

        }
      },
      components: {
        Card
      },
      props: {
        cards: {type: Array<String>}
      }
    }
</script>

<template>
    <div class="Hand">
            <Card v-for="card in cards" :card="card">
            </Card>
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

And this is my component in Vanilla JS:

export class Hand extends RenderableType{

    constructor(id: string){
        super(id)
    }

    render(state: logic.GameState){

        let s:string=`<div class="Hand" id="hand">`
        for(let i:number=0;i<state.hand_cards.length;i++)
        {
            let id:string = "handcard"+i
            s+=`<div id="${id}"></div>`
            let h:Card = new Card(id, -1, state.hand_cards[i])
            this.add_sub("",h)
        }
        s+=`</div>`
        if(s!=this.prev)
        {
            document.querySelector<HTMLDivElement>('#'+this.id)!.outerHTML = s
            super.render(state)
        }
        else
            super.render(state)
        this.prev = s
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, in all three cases there are three elements present in the component:

  1. A declarative part with the HTML code that is basically the same in all three components.
  2. Code for controlling when to render based on the parameters (or props) received by the component.
  3. Code for making a loop for sub-components nested to the parent component. The sub-components are rendered independently by their own code in all cases, without we needing to take care here of how they will do that.

The rest of code, in all three cases, is just an standard structure that you just copy-paste from any other component.

And voilà, you have done exactly the same with Vanilla JS without needing to learn any new syntax, without having to install any new tool, without reading any tutorial, without having to decipher syntax errors that are new to you... Just doing what you already have been doing all your life.

You get all the advantages claimed by these tools in the exact same way:

  • Easy development of interfaces
  • Boosts productivity
  • Faster rendering (they claim that falsely but in our case it is true)
  • Excellent cross-platform
  • It guarantees stable code (modifications in one component do not affect the rest)
  • SEO friendly
  • Template designing
  • UI focused design
  • Easy to adopt

And, in addition, you have other advantages:

  • You need to understand what your philosophy is instead of remembering what someone else's philosophy is and how he coded that
  • Flexibility to break barriers between component communication the way you want as nothing limits you
  • Flexibility to impose barriers on how components communicate as you set the rules and nobody else

And you will be wondering, what magic is necessary to replace a tool with hundreds of hours of development and still having the exact same advantages? What is the deal if you need to replace their work yourself?

Turns out, you only need 30 lines of code to replace React JS and Vue.js. Then, you can code with the exact same philosophy and almost identical coding style.

export class RenderableType {
    private subs: Array<[string, RenderableType]>
    id:string
    prev:string
    constructor(id: string){
        this.id=id
        this.subs= []
        this.prev=""
    }
    render_subs(state: logic.GameState){
        for(let i:number=0; i<this.subs.length; i++){
            let e=this.subs[i]
            e[1].render(state)
        }
    }
    clear_subs(type:string){
        let newsubs:Array<[string, RenderableType]>=[]
        for(let i:number=0;i<this.subs.length;i++)
        {
            if(this.subs[i][0]!=type)
                newsubs.push(this.subs[i])
        }
        this.subs=newsubs
    }
    add_sub(type:string, e:RenderableType)
    {
        this.subs.push([type,e])
    }
    render(state: logic.GameState): void {
        this.render_subs(state)
    }
}
Enter fullscreen mode Exit fullscreen mode

And this is just a naïve try made in a few days. You can easily improve that class according to your needs and philosophy. It will likely be worth it if you are going to work in a project for years.

There are only a few disadvantages. In case you hire poorly-skilled developers, they won't intuitively understand this code as they will be used to memorize how to do things in a framework, without understanding what there is behind. But why would it be a problem being forced to discard poorly-skilled developers? And finally - should not be neglected - the part that will likely unfairly decline the balance to reject this idea is that in case you follow this approach, you are going to be considered obsolete by other companies, even if you are likely making your actual company save a lot of money.

Top comments (2)

Collapse
 
joesoeph profile image
Yusuf Fazeri

I think, the way you do this is the way that other programmers should also do it. Knowing the basics will help us in understanding the basic concepts well. before using a mature system such as a framework or library. I like your philosophy and you inspire me. thanks

Collapse
 
juanjo75es profile image
Juan José Bermúdez

Thanks Yusuf! Nice to inspire something positive sometimes. Doesn't happen too often in online discussions.