Are you a “before React” or “after React” dev? I raise the question because modern front-end development closely relates to React. At least the notion is. I like React a lot, but it’s not the type of beginner library with which we should start our journey early in our career.
That doesn’t mean you cannot be part of a React project as a Junior Developer. Still, you should understand why React, Svelte, Vue, or Angular are doing what they do and why it’s different from the actual vanilla or other approaches.
In short, learn the basics before you tackle to understand advanced patterns like the declarative one. If this little mini-example of a selector isn’t familiar to you, but you are working already in a React environment, you should re-think:
const el = document.querySelector("input");
...
el.value = "Hello World"
This week, I will come back to the question “Beyond React – Or Before React?” since this is very polarising.
History of Web Development I was part of
Starting with a bit of history: When I first dipped my toes into web technologies over two decades ago, 𝗳𝗿𝗼𝗻𝘁𝗲𝗻𝗱 𝗱𝗲𝘃𝗲𝗹𝗼𝗽𝗺𝗲𝗻𝘁 𝘄𝗮𝘀 𝗮 𝗰𝗼𝗺𝗽𝗹𝗲𝘁𝗲𝗹𝘆 𝗱𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝘁 𝗯𝗲𝗮𝘀𝘁. The term "Frontend Developer," as we know it today, wasn't commonplace. Back then, frontend tasks were just a portion of the overall effort in building applications, solutions, or products—a role we now associate with full-stack developers.
In those early days, my tools of choice 𝘄𝗲𝗿𝗲 𝗽𝗿𝗶𝗺𝗮𝗿𝗶𝗹𝘆 𝘁𝗵𝗲 𝘃𝗮𝗻𝗶𝗹𝗹𝗮 𝗛𝗧𝗠𝗟 𝘀𝘁𝗮𝗰𝗸, augmented by prototype.js to manage the quirks between different browsers.
(We still maintain these apps today :)
As the digital world evolved, jQuery emerged and quickly took center stage, beloved for its simplicity and the robustness of its UI components.
Personally 𝗜 𝗮𝗹𝗺𝗼𝘀𝘁 𝗲𝗻𝘁𝗶𝗿𝗲𝗹𝘆 𝗯𝘆𝗽𝗮𝘀𝘀𝗲𝗱 𝘁𝗵𝗲 𝗷𝗤𝘂𝗲𝗿𝘆 𝗲𝗿𝗮, I was not a fan of its approach. However, it's undeniable that jQuery played a pivotal role in making web development more accessible and less complex.
Bootstrap, Angular, and React
The development landscape continued to evolve with the introduction of frameworks like Bootstrap, Angular, and React. Although jQuery had just announced its fourth iteration, these technologies steered the community towards new directions. React, in particular, has advocated a declarative, component-driven approach to front-end development.
The Wind Of Change: Tailwind
⛈️ Following React, Tailwind CSS emerged, sparking developers' debates with its innovative styling approach. Tailwind fundamentally altered how CSS is applied, making it a polarizing yet transformative presence in the development toolkit.
As we look beyond individual libraries and frameworks, 𝗶𝘁'𝘀 𝗰𝗿𝘂𝗰𝗶𝗮𝗹 𝘁𝗼 𝗰𝗼𝗻𝘀𝗶𝗱𝗲𝗿 𝘁𝗵𝗲 𝗲𝘃𝗼𝗹𝘃𝗶𝗻𝗴 𝗺𝗲𝘁𝗵𝗼𝗱𝗼𝗹𝗼𝗴𝗶𝗲𝘀 𝗶𝗻 𝗳𝗿𝗼𝗻𝘁𝗲𝗻𝗱 𝗱𝗲𝘃𝗲𝗹𝗼𝗽𝗺𝗲𝗻𝘁. Today, the roles of testing, DevOps, and Continuous Delivery are integral to modern practices.
🍪 This Wednesday, we will stream about this topic together with
and Bryan Finster: LinkCaveats of the New World – All That Glitters Is Not Gold
Mastery of React does not equate to a mastery of all front-end development.
In front-end engineering, the allure of modern frameworks and their purported simplicity can often be misleading. React, for instance, is frequently marketed as beginner-friendly, but this portrayal glosses over the intricate realities newcomers face when trying to master it.
The declarative pattern, a cornerstone of React's approach, epitomizes this issue. While it simplifies some aspects of UI development by abstracting away direct DOM manipulation, it introduces its own set of complexities. Properly leveraging the declarative nature requires a deep understanding of underlying design principles, which isn't instinctive to beginners. Without this foundational knowledge, developers might shift complexity around rather than reduce it.
The hidden gap between, or shall we call it, the Junior Dev React trap?
Furthermore, React's ecosystem suggests a low entry barrier, yet it demands a strong grasp of advanced JavaScript concepts and functional programming. This can lead to a significant gap between what it means to use React and what it takes to be a proficient front-end engineer.
Newcomers may quickly create components and manage state, but without a broader understanding of performance optimization, accessibility, and scalable architecture, they fall short of being comprehensive developers.
Misconceptions About Being a 'React Developer'
The term "React Developer" is a misnomer that needs addressing. Mastery of React does not equate to a mastery of all front-end development. React is just a tool—albeit a powerful one—that sits atop a much larger ecosystem of technologies and principles necessary for high-level development work. This misunderstanding leads many to underestimate the breadth of skills required to excel in front-end engineering.
Advanced Patterns Misrepresented as Novice-Friendly
Many advanced patterns in React, such as higher-order components, hooks, and context, are often introduced to beginners without adequate context or prerequisites. This premature introduction can overwhelm those new to the field, leading to frustration and a shaky grasp of basic concepts.
🍪 The problem here with the frustration is that the developer might not realize the root cause and instead blames react, JavaScript, NPM, etc. Early on, we should understand that the nature of being a Frontend Engineer is the entire general ecosystem, the Basics of HTML, JS and CSS, Browser & Network. Start with those first!
Long-Term Maintenance Overlooked
The excitement around launching new features often overshadows the mundane yet crucial aspect of maintenance. Modern development tools and frameworks are excellent for quickly getting projects off the ground, but they can also lead to highly abstracted and tightly coupled code. This makes future debugging, updates, and scalability efforts more cumbersome than they need to be, particularly if initial development did not adhere to best practices.
Tooling Overload and Analysis Paralysis
The modern frontend landscape is rife with tools and libraries, each promising to be the silver bullet for development woes. This abundance can lead to analysis paralysis among developers, particularly those new to the field. Choosing the right tool for the right job is a skill developed through experience and often through making the wrong choices first.
How to (safely) NPM
🍪 NPM packages are a great idea and are an important part of the foundation for the current scale of our industry. But act with care and only use what you really need.
Here are some general rule-of-thumbs:
Don't Use Packages for Very Small Functions You Could Write Yourself
Using npm packages for trivial functionality can unnecessarily bloat your application and increase its attack surface. For instance, importing a package to pad a string or capitalize the first letter of a word could be overkill when you could easily write these few lines of code yourself. This not only keeps your project lighter but also reduces dependencies, lowering the chance of introducing bugs or vulnerabilities from external code.
Example:
Instead of using a library like Capitalize, you could write a simple function like this:
function capitalizeFirstLetter(string: string): string {
return string.charAt(0).toUpperCase() + string.slice(1);
}
Avoid With Too Many External Dependencies If You Have Another Choice
Packages with extensive dependencies can complicate your build process, slow down your application, and open up multiple avenues for security vulnerabilities. Reviewing a package's dependency tree before including it in your project is prudent. If a package pulls in many other packages, consider looking for simpler alternatives or writing the needed functionality yourself if feasible.
Example:
Use npm's built-in command to view a package's dependency tree:
npm list <package-name>
# Example – 😀 A good example for many dependecies
npm list lodash
Don't Introduce Packages That Don't Have Multiple Active Contributors
Packages maintained by a robust community or a dedicated team are generally more secure and receive regular updates than those managed by a single individual. Before adopting a package, check its repository for recent commits, active issues, and pull requests to gauge its activity. A well-maintained package is less likely to contain critical bugs or security flaws and more likely to be quickly updated when issues are found.
Additional Guidelines Using NPM
Check for License Compatibility:
Ensure the package’s license is compatible with your project's licensing. Incompatibilities can lead to legal issues, particularly for proprietary software.
Prioritize Well-documented Packages:
Good documentation not only makes it easier to use the package but also indicates the maintainers’ commitment to its quality and longevity.
Evaluate the Package's Popularity and Community Feedback:
Look at metrics like download counts and star ratings on GitHub or npm, but also read through user comments and issues to see how the maintainers handle problems. High popularity can be a proxy for reliability and robustness.
Audit regularly
Regular auditing of your npm packages is crucial to maintaining the security and integrity of your projects. The npm audit
command is a valuable tool that scans your project's dependencies for known vulnerabilities and provides detailed reports on any identified issues.
Ideally, implement this into your CI/CD pipeline.
Use Husky to enforce being below a specific threshold, such as critical or high.
Alternatively, you can use Github Dependabot.
Consider the Package’s Impact on Your Project's Size and Performance:
Use tools that analyze the impact of adding a new package to your project. Packages might add to the load time of your application, especially if they are not properly tree-shakable or include redundant code.
Example: https://bundlephobia.com/package/lodash@4.17.21
The Illusion of Immediate Expertise
Easy access to comprehensive frameworks and their associated toolchains can create an illusion of immediate expertise. However, true proficiency in frontend engineering involves understanding how to implement features using a framework and why certain approaches are preferable depending on the context. This depth of understanding typically only comes with time, patience, and much coding.
In conclusion, while modern development tools and methodologies offer tremendous benefits, they require a level of sophistication and understanding that may not be immediately apparent. It's crucial for those entering the field to temper their expectations and commit to continuous learning and exploration beyond the confines of any single framework or tool.
Declarative vs. Imperative Programming in Frontend Development
In traditional JavaScript development, the approach was largely imperative, which means the code explicitly instructs the browser how to perform each step to achieve the desired outcome. This often involves manually manipulating the DOM, explicitly specifying the creation, addition, or modification of HTML elements based on certain events or conditions. For example, to hide an element when a user clicks a button, an imperative approach would directly find the element and alter its style or attributes.
// Imperative approach using TypeScript
const button: HTMLElement | null = document.getElementById('hideButton');
const elementToHide: HTMLElement | null = document.getElementById('content');
button?.addEventListener('click', function() {
if (elementToHide) {
elementToHide.style.display = 'none';
}
});
This method, while straightforward, can lead to verbose and repetitive code, making complex applications harder to manage and understand. It requires developers to manage state changes manually and synchronize them with the DOM, leading to potential inefficiencies and errors in state handling.
Contrastingly, modern frameworks like React adopt a declarative programming model. Declarative programming involves telling the computer what to do rather than how to do it. The framework takes care of the how—managing DOM updates, state changes, and re-rendering—based on the state described in the code. React allows developers to define components in terms of their desired states, and React handles translating those state changes into DOM updates.
import React, { useState } from 'react';
const ContentToggle: React.FC = () => {
const [isVisible, setIsVisible] = useState<boolean>(true);
const toggleVisibility = (): void => {
setIsVisible(!isVisible);
};
return (
<div>
<button onClick={toggleVisibility}>
{isVisible ? 'Hide' : 'Show'}
</button>
{isVisible && <div id="content">Content goes here</div>}
</div>
);
}
export default ContentToggle;
In this example, the developer only specifies what the UI should look like in each state (isVisible true or false), and React updates the UI accordingly when the state changes. This approach minimizes boilerplate, improves readability, and enhances maintainability.
It abstracts away direct DOM manipulation, allowing developers to focus on the application's high-level logic. Moreover, this paradigm shift significantly reduces the likelihood of bugs that arise from manual DOM handling and state synchronization, providing a robust foundation for building complex user interfaces.
By shifting from imperative to declarative, frontend development has become more about designing the state and interactions of UI components rather than micromanaging DOM changes. This aligns with broader software engineering principles of abstraction and encapsulation, vital for creating scalable and manageable codebases.
Wrapping Up
In wrapping up, this article introduces my upcoming content track focused on mastering modern front-end engineering. The goal is to deepen your understanding of the tools and frameworks defining today’s development landscape and to enhance your ability to apply them effectively.
Now more than ever, front-end development involves a complex blend of HTML, JavaScript, CSS, and various frameworks and libraries. This complexity often surpasses that of backend development, reflecting the common higher ratio of frontend to backend developers in many teams. (I personally see an average of 2:1 here).
It’s about engineering.
As we explore this content track, we will emphasize robust engineering practices that ensure our applications are maintainable, scalable, and secure. From mastering the basics to applying advanced patterns, this journey is designed to equip you to navigate the dynamic field of front-end development, making you proficient in using the tools and understanding the strategic ‘why’ and ‘how’ behind them.
This approach aims to elevate your skills beyond mere implementation, preparing you to create rich, efficient user experiences and set a standard for true frontend engineering excellence.
🍪 You aren’t a React Dev but need to become a Frontend Engineer. You have a lot to learn. It took me 24 years to reach this point, and I won’t stop learning.
Adrian