Skip to content

Progressive Web Apps and Mobile Apps

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Introduction

In a talk by Alex Russell titled, "The Mobile Web: MIA", Alex discussed a number of issues facing the expansion of the web platform on mobile devices. He noted that, "People don't use the web the way they lean on it, and rely on it, and come to depend on it on desktop." In his talk, he noted that people use the web about 4% of the time they are using phones, and dropping. The rest of the time, users are typically interacting with mobile apps, rather than the browser.

Much of this is driven by the fact that companies that own the platforms (Google and Apple, in particular) are primarily focused on native app developments. This focus on mobile app development pushes the market to accept the importance of a mobile app, and drive users to leave the web for a native experience. Mobile app development locks experiences to devices and operating systems, which increases the cost of development. Users, in turn, grow to expect mobile applications, even for simple tasks such as viewing bus routes or filling out a form.

As web developers, we know there is another option for app development. Progressive Web Apps (PWAs) are built with standard web technologies - HTML, CSS, JavaScript, and modern browser APIs - to provide an enhanced experience when using them on supported platforms. By utilizing the latest browser features, web developers can construct the same experiences users expect of native applications. These features include: accessing the camera, notifications, Bluetooth and network information- even augmented/virtual reality and payments. Browsers have been working to support these features for years, and some companies (such as Twitter) have been building PWAs to provide an improved experience for their platforms.

Let's say that we have a company, BetterX, which is looking to build a new app for their users. The primary goal is to provide an excellent experience for mobile users, including offline support and hardware features such as notifications and payments. We will explore and compare the benefits of native mobile applications and PWAs, and discuss why each platform may be the better choice.

Progressive Web Apps - The Open Web

One of the key benefits when considering a progressive web app is that we are utilizing modern web development tools to build our application. As web developers, we are already familiar with a number of complex tasks, such as state management, caching, and performance optimization. To build a PWA, we need to take these concepts to their natural conclusions. By utilizing a service worker to cache assets and IndexedDB or other methods to store local data, we can build a system that is capable of working fully offline. By using network detection, our application can determine whether an internet connection is available, and provide that information to the user.

Another benefit of building with web technologies is that we have a better chance of achieving the goal of, "write once, run anywhere". By utilizing standard architecture patterns in our application, and relying on progressive enhancement as the browser/platform we are running on allows, our PWA can run on both mobile devices (as an installed app) or on browsers. Most developers are already familiar with responsive design, which allows a website to change its appearance depending on the viewport or device. The same concepts can be applied to a PWA, incrementing our functionality as the device allows it, and providing a fallback for when certain features are not available.

Web development also has the benefit of traditionally being cheaper than mobile app development. Smaller companies don't always have the time or money to invest in a mobile development team. Most of them, however, do have a website. By utilizing some of the APIs available to progressive web applications, these shops and companies can provide a mobile experience. Also, if a website/web app is built with mobile devices in mind, the time it takes to build a fully functional PWA could be weeks, compared to a brand new mobile application taking months.

PWAs can also be significantly smaller than their native alternatives. In a report by Google, the Twitter PWA "requires less than 3% of the device storage space compared to Twitter for Android". As fewer mobile devices have ports for expanded storage space, the size of applications becomes increasingly more important.

Drawbacks

However, there are some drawbacks to choosing a progressive web app. Users expect to find mobile applications in the app store, not on a website. In his talk, Alex Russell shares a screen of an Android device with a Google search bar at the time, and a row of icons at the bottom, including the Google Play Store. He explains that people click on the search bar when they are looking for "answers", and click on the store when they are looking for "experiences". For PWAs, the way to install them is to visit the URL, and click on the install button when prompted. This is not how users have been trained to find apps for their smartphones.

It's also not clear to a user what installing a PWA achieves. On an Android device where a user installs a PWA, an icon for that app appears on their desktop as any other app would. However, depending on the app, this could be a complete experience, including offline support, or it could simply be a wrapper to load a website. In many cases, a PWA is little more than an enhanced bookmark on a mobile phone.

Mobile Applications - Platform Builders

Mobile apps are the standard established by Google and Apple for delivering user experiences on phones and tablets. Apps are an expected feature of any new platform - it's rare to see a new service thrive without a presence in the Google Play Store, or Apple App Store. Keystone applications, like Facebook or Twitter, are regularly highlighted by these platforms as a way to bring new users into their walled gardens.

Users are trained to search for, and install, mobile applications. Often, websites will guide users directly to the respective app store. On iPhones and iPads, the app store is the only way for apps to be installed on a phone, making the store even more crucial to a product's success on the platform. Since Apple does not support PWAs in Safari, this makes mobile development a requirement to reach customers within their ecosystems.

Mobile development has first-class support from both Apple and Google, providing access to APIs and features as new hardware is released. Apps being developed for newer devices can do more, and utilize more resources than ever before. Resource-intensive apps like Adobe Photoshop or Procreate can leverage these resources to achieve results previously held only on desktops and laptops.

Modern mobile development frameworks, such as Flutter and React Native, allow developers to target these devices in a cross-platform way. They provide access to the APIs and features of the hardware, and a streamlined way to write a majority of your app once, while targeting multiple platforms. Other frameworks such as Cordova or Capacitor even allow for using modern web technologies, and having a fully bundled app that can be released on the app store.

Downsides

Mobile development provides amazing functionality and allows for powerful applications to be built. However, it comes at a cost. These applications can only run on the latest and greatest hardware and OS version. Most mobile users do not have access to the hardware we, as developers, are using to build our applications. What takes a few seconds to load on 5G using an iPhone 12 Max could take nearly a minute to load on phones common in most of the world. Also, final application sizes are going to impact how many users can actually download our app in the first place.

In many cases, a mobile application in the app store could become more of a burden than a benefit. Consider that you're visiting a foreign country. Because you are roaming, your internet speed is significantly slower than you are used to. While traveling in a city, you want to check for bus routes and schedules. You go to the website for the municipal bus system, and are directed to download an app to view schedules. This app is not too large (my local bus system's app is 8.6 MB), but on your slower connection still takes a long time to download. Also, you may only need this app once or twice, before you travel to your next destination. A website (or PWA) would provide a much smoother experience than requiring a mobile app be downloaded.

Considerations

Regardless of which architecture you decide to use for building out your mobile application, there are some considerations to keep in mind. First, your developers are going to have better hardware and internet connection than many of your users. Most users do not have a high-end iPhone or Android device, and are not on 5G or gigabit internet. Whether you're building a PWA or a native app, remember that every megabyte will take substantially longer to download and initialize, and your application will run slower. If able, you should test your applications on slower or ittermitant internet speeds, or on lower end hardware.

In general, if you are going to build a mobile application, it has to be lean, loadable, and support offline use. Many companies, (and some end users), will try to push for new features or content without regard for the experience of all users. Setting up a truly performant and offline-friendly experience is complicated, but it truly is worth taking into account all potential users as you work to build and deploy it.

If you decide that building a progressive web app is the way to go for your app or company, it is important to remember that PWAs are not supported in Safari or on iOS/iPadOS. On both iPhones and iPads, the only browser engine is WebKit, regardless of which browser you are using. This means that users will not be able to install your PWA on Apple mobile devices, and the browser APIs may not be available. Take this into account while building your app, and allow for graceful degredation when features are not available. This is not to say that you shouldn't build a PWA if you want to target Apple's ecosystem - much the opposite! The more PWAs that exist, and have a large number of users on Apple's devices, the better chance that Apple will support the standardized browser features that enable PWAs.

At the end of the day, choose the architecture that best supports your users, and build with them in mind. Your app should help your users and customers in some way, and should not be a burden to them. It may be fun to try out a new mobile framework, or build a PWA with enhanced features, but not if it does not serve the end user.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Demystifying React Server Components cover image

Demystifying React Server Components

React Server Components (RSCs) are the latest addition to the React ecosystem, and they've caused a bit of a disruption to how we think about React. Dan Abramov recently wrote an article titled "The Two Reacts" that explores the paradigms of client component and server component mental models and leaves us with the thought on how we can cohesively combine these concepts in a meaningful way. It took me a while to finally give RSCs the proper exploration to truly understand the "new" model and grasp where React is heading. First off, the new model isn't really new so much as it introduces a few new concepts for us to consider when architecting our applications. Once I understood the pattern, I found an appreciation for the model and what it's trying to help us accomplish. In this post, I hope I can show you the progression of the React architecture in applications as I've experienced them and how I think RSCs help us improve this model and our apps. A "Brief" History of React Rendering and Data-Fetching Patterns One of the biggest challenges in React since its early days is "how do we server render pages?" Server-side rendering (SSR) is one of the techniques we can use to ensure users see data on initial load and helps with our site's SEO. Without SSR, users would see blank screens or loading spinners, and then a bunch of content would appear shortly after. An excellent graphic on Remix's website demonstrates this behavior from the end user's perspective and it's a problem we generally try to avoid as developers. This problem is so vast and difficult that we've been trying to solve it since 2015. Rick Hanlon from the React Core Team reminded us just how complicated this problem was recently. If you think react is complicated now, go back to 2015 when you had to configure babel and webpack yourself, you had to do SSR and routing yourself, you had to decide between flow and typescript, you had to learn flux and immutable.js, and you had to choose 1 of 100 boilerplates— Ricky (@rickhanlonii) January 28, 2024 But SSR has its issues too. Sometimes SSR is slow because we need to do a lot of data fetching for our page. Because of these large payloads, we'll defer their rendering using lazy loading patterns. All of a sudden we have spinners again! How we've managed these components has changed too. Over the years, we've seen a variety of patterns emerge for managing these problems. We had server-side pre-fetching where we had to hydrate our frontends application state. Then we tried controller-view patterned components for our lazily loaded client-side components. With the evolution of React, we were able to simplify the controller-view patterns to leverage hooks. Now, we're in a new era of multi-server entry points on a page with RSCs. The Benefits of React Server Components RSCs give us this new paradigm that allows us to have multiple entries into our server on a single page. Leveraging features like Next.js' streaming mode and caching, we can limit what our pages block on for SSR and optimize their performance. To illustrate this, let's look at this small block of PHP for something we might have done in the 2000s: index.php ` For simplicity, the blocks indicate server boundaries where we can execute PHP functionality. Once we exit that block, we can no longer leverage or communicate with the server. In this example, we're displaying a welcome message to a user and a list of posts. If we look at Next.js' page router leveraging getServerSideProps, we would maybe write this same page as follows: pages/posts.jsx ` In this case, we're having our server do a lot to fetch the data we need to render this page and all its components. This also makes the line between server and client much clearer as getServerSideProps runs before our client renders, and we're unable to go back to that function without an API route and client-side fetch. Now, let's look at Next.js' app router with server components. This same component could be rendered as follows: app/posts/page.tsx ` This moves us a bit closer back to our PHP version as we don't have to split our server and client functionality as explicitly. This example is relatively simple and only renders a few components that could be easily rendered as static content. This page also probably requires all the content to be rendered upfront. But, from this, we can see that we're able to simplify how server data fetching is done. If nothing else, we could use this pattern to make our SSR patterns better and client render the rest of our apps, but then we'd lose out on some of the additional benefits that we can get when we combine this with streaming. Let's look at a post page that probably has the content and a comments section. We don't need to render the comments immediately on page load or block on it because it's a secondary feature on the page. This is where we can pull in Suspense and make our page shine. Our code might look as follows: app/posts/[slug]/page.jsx ` Our PostComments are a server component that renders static content again, but we don't want its render to block our page from being served to the client. What we've done here is moved the fetch operation into the comments component and wrapped it in a Suspense boundary in our page to defer its render until its content has been fetched and then stream it onto the page into its render location. We could also add a fallback to our suspense boundary if we wanted to put a skeleton loader or other indication UI. With these changes, we're writing components similarly to how we've written them on the client historically but simplified our data fetch. What happens when we start to progressively enhance our features with client-side JavaScript? Client Components with RSCs All our examples focused on staying in the server context which is great for simple applications, but what happens when we want to add interactivity? If you were to put a useState, useEffect, onClick, or other client-side React feature into a server component, you'd find some error messages because you can't run client code from a server context. If we think back to our PHP example, that makes a lot of sense why this is the case, but how do we work around this? For me, this is where my first really mental challenge with RSCs started. Let's use our PostComments as an example to enhance by in-place sorting the section from the server. ` In this example, we're using a server component the same way as our previous example to do the initial data fetch and stream when ready. However, we're immediately passing the results to a client component that renders the elements and enhances our code with a list of sort options. When we select the sort we want, our code makes a request to the server at a predefined route and gets the new data that we re-render in the new order on screen. This is how we might have done things without RSCs before but without a useEffect for our initial rendering. If you're familiar with the old controller-view pattern, this is relatively similar to that pattern, but we have to relegate client re-fetching to the view (client) component, where we might have had all fetch and re-fetch patterns in the controller (server) component Another way to solve this same problem is leveraging server actions, but that would cause the page to re-render. Given the caching mechanisms in Next.js, this is probably fine, but it's not the user experience people are expecting. Server actions are a topic of their own, so I won't cover them in this post, but they're important for the holistic ecosystem experience in the new mindset. Interleaving Nested Server & Client Components These examples have shown a clean approach where we keep our server components at the top of our rendering tree and have a clear line where we move from server mode to client mode. But one of the advantages of RSCs is that we can interleave where our server component entry points may exist. Let's think about a product carousel on a storefront page for example. We may have built this as follows before: ` Here we're rendering carousels that render their cards and our tree goes server -> client -> server. This is not allowed in the new paradigm because the React compiler cannot detect that we moved back into a server component when we called ProductCards from a client component. Instead, we would need to refactor this to be: ` Here, we've changed ProductCarousel to accept children that are our ProductCards server component. This allows the compiler to detect the boundary and render it appropriately. I'd also recommend adding Suspense boundaries to these carousels but I omitted it for the sake of brevity in this example. Some Suggested Best Practices Our team has been using these new patterns for some time and have developed some patterns we've identified as best practices for us to help keep some of these boundaries clear that I thought worth sharing. 1. Be explicit with component types We've found that being explicit with component types is essential to expressing intent. Some components are strictly server, some are strictly client, and others can be used in both contexts. Our team likes using the server-only package to express this intent but we found we needed more. We've opted for the following naming conventions: Server only components: component-name.server.(jsx|tsx) Client only components: component-name.client.(jsx|tsx) Universal components: component-name.(jsx|tsx) This does not apply to special framework file names but we've found this helps us delineate where we are and to help with interleaving. 2. Defer Fetch when Cache is Available If we're trying to render a component that is a collection of other components, we've found deferring the fetch to the child allows our cache to do more for us in rendering in cases where the same element may exist in different locations. This is similar to how GraphQL's data loaders works and can ideally boost the performance of cached server components. So, in our product example above, we may only fetch the IDs of the products we need for the ProductCards and then fetch all the data per card. Yes, this is an extra fetch and causes an N+1, but if our cache is in play, end users will feel a performance gain. 3. Colocate loaders and queries If you're using GraphQL or need loading states for components for Suspense fallback, we recommend colocating those elements in the same file or directory. This makes it easier to modify and manage related elements for your components in a more meaningful way. 4. Use Suspense to defer non-essential content This will depend on your website and needs. Still, we recommend deferring as many non-essential elements to Suspense as possible. We define non-essential to be anything you could consider secondary to the page. On a blog post, this could be recommended posts or comments. On a product page, this could be reviews and related products. So long as the primary focus of your page is outside a Suspense boundary, your usage is probably acceptable. Conclusion RSCs represent a significant evolution in the React ecosystem, offering new paradigms and opportunities for improving the architecture of web applications. They enable multiple server entry points on a single page, optimizing server-side rendering, and simplifying data fetching. RSCs allow for a clearer separation between server and client functionality, enhancing both performance and maintainability. To make the most of RSCs, developers should consider best practices such as being explicit with component types, deferring fetch when caching is available, colocating loaders and queries, and using Suspense to defer non-essential content. Embracing these practices can help harness the potential of React Server Components and pave the way for more efficient and interactive web applications. We're excited about this development in the React ecosystem and the developments happening across teams and frameworks that are opting into using them. While Next.js offers a great solution, we're excited to see similar enhancements to Remix and RedwoodJS....

Leveling Up Your Work Through Architecture Design and Time Estimation cover image

Leveling Up Your Work Through Architecture Design and Time Estimation

> This post can be useful for developers at any level! However, it is written mostly for entry-level developers who are starting to transition into a more intermediate role. You’re rocking your first development job. You’re completing tasks, the team loves you, you still have tons of questions but you can get answers and build what you’re asked to build. But you want to keep improving your skills and giving yourself more options. Some of that skill can only come from actually building things over time. But surely there’s something you can do to level up besides that, right? There is! One way to help deepen your understanding of the software you’re writing and make yourself look more impressive is by improving your ability to estimate your time, and how you talk about your work. That’s what we’re going to dig into today! Some terminology You might have heard of, or have read terms like “software architecture” and “quality attributes” and, upon trying to look into them, been met with a LOT of jargon and dense terminology. So before we get too far into this, let’s go over a few terms we’ll use. (This is by no means meant to be a complete description of these terms. The aim is to be clear enough to continue our discussion here, and let you get started.) - Software architecture: This term means how your system is organized. It’s like the blueprint for the application or website you’re building. How do all the pieces we build fit together and interact with each other? What’s the main goal we’re trying to achieve with this codebase? That’s what this term is talking about. - Software design: Once we have the blueprint, we need to figure out how to build the pieces to make that structure come to life. This is where the design comes in. It’s more code-specific and focuses more on the specifics of what we need to build and how. What languages are we using? How do we get this component to be interactive or usable like we want? This is all the design. - Software quality attributes: Sometimes referred to as “ilities” because a lot of them end with those letters, these are words we use to describe the software we write. Common ones would be accessibility, reliability, or performance. These are words used to describe some of the key qualities we want our software to have. You can start with this list of quality attributes or do a search for “software quality attributes”, and find all sorts of articles covering a lot of the common ones. - Time estimation: This is the skill of being able to consider a task and estimate how long it would take you to complete the task. Time can be a funny thing, and it’s pretty common to think something will be easy and have it take way longer, or think something will be complex, and it turns out to be straightforward. - Trade-offs: This is the idea that two things can’t be equally balanced and/or important. There’s a joke about how people want things fast, cheap, and good and you can’t have all three. This is the same idea. Very often, by increasing one quality, you have to decrease another. The balance of those, and the choice to focus on one quality more than another, is called a trade-off. You’re trading the strength of one quality for another. When we’re using the phrase “architecture design” in this article, we’re combining all these concepts together. How do we get started? Ok, so we’ve got some terms now. But what do we do with them? How do we get better at designing software, and estimating our time? I’ve got two templates to share with you that can help you start to develop these skills. Both will involve writing, but I’ve tried to make them as straightforward to fill out as possible so it’s not a chore to use them. I’ll share links for the templates later on. But first, we’ll go over the actual contents of both of them and talk about how to use them. These templates can be useful for any task, no matter how complex. However, super simple tasks like fixing a broken link on a page, or adjusting a color value to improve its contrast may not be the best choice for it. It is useful to use this template on a task that you fully understand, so you get some practice with thinking about the tradeoffs you’re making, and get used to some of the terminology and how to talk about the software you build. But this can really help when you start getting larger tasks or features- ones that might contain multiple parts working together or some complex logic to get the task working properly. The architecture design template For this template, the goal is to complete this first before you do any work on your task. Use this as a tool to help you think through your work before you get started on it so you can have a better understanding of what the task is asking of you, and let you start thinking about the attributes you’re building for. There are 7 sections for this document, each with a title and description. Let’s go over each piece to see how they work. Big picture: What’s the ask? *What’s the ticket/task trying to solve? What’s the end goal of this body of work? Describe the problem in the most ELI5 way you can.* Use this section to describe the task you’re working on. Act like you’re talking to someone with very little understanding of the situation, like a project manager on another team or to a friend of yours that doesn’t work with you. This section helps you make sure you have a strong handle on the work you’re being asked to do, and what the end result should be. Requirements *Is there acceptance criteria? A specific way it needs to work? What makes this ticket / task count as complete? Steps to reproduce and/or screenshots are helpful here too, if available.* Some of this can often be copied over from the ticket you’re working on. Make note of how you can tell that this task is complete, and any specifics that you need to make sure work as expected when you’re ready to have someone review it. Constraints *Are there specific things you can / can’t use? Something you have to make sure doesn’t break? Tools you have to use because of where you have to work in the codebase?* Making note of constraints can be super helpful. Maybe you have to use a specific UI library to complete this because the rest of the project uses it. Or perhaps this task has been attempted before, and you don’t want to repeat a version that didn’t work. Getting used to thinking about the constraints you’re working within can help prep your brain to think around these concepts. Architecture and Tradeoffs *Where does this code live? (login, ui, db, etc) What software quality attributes are we focused on for this task? List out the primary and secondary attributes (maybe a third if it feels necessary).* In this section, we’re focusing on developing our architecture and design skills in detail. Talk a little about how the codebase is structured, and where the work for this task will be located. Also, pick one or two software quality attributes that you think fit this task. Does the work you’re doing help improve the site’s overall accessibility? Does it make the application more reliable for end users? Does it help to keep our codebase’s maintainability within a reasonable level? Use one of the lists above or your own searches to build out a list of the attributes you might build for regularly, and pick out one or two of them that relate the most to this task. Then, talk a little about why you picked those traits and your thoughts about why they’re applicable. Being able to explain your reasoning here will both help you gain more understanding of the work you’re doing, and the words you’re using to describe it, and give whoever reads this document a better glimpse into the work you do and how you think about it! Initial Gameplan *Considering all the above, what seems like the path forward? What are the steps for how you think it can be solved/completed? Where are you starting?* Now that you’ve spent a little time thinking through the task, and some of the things you should remember about it (like how it’s structured, the tools you have to use, and what’s important to keep in mind while you’re solving it) - write out the steps you think you should take to accomplish the task. It’s perfectly okay to not fully follow this plan as you start to build! We can never fully predict everything that might happen as we start to work in a codebase. The goal here is to give yourself a solid place to start, with all the details we’ve listed fresh in your mind. Process Notes *As you solve this - keep this area updated with rough notes. What did you try that didn’t work? Why not? If you have to pivot, what did you switch to and why? Maybe something worked but you still pivoted - what tradeoffs were made, and what’s the reasoning behind it?* As the description implies, this space is all for you. Try to keep notes as you go. If you do have to change course from your game plan, why and what did you change? Did you find another problem you didn’t even know existed? Or maybe you were able to try a new concept out and it worked! Celebrate your process here. None of this needs to be in complete sentences or easy for anyone but you to understand. This space is all yours to help you keep thinking through the work as you’re doing it! Final Solution *You did it! Form a narrative. Now that you’ve got the issue solved, what does it look like? How did you do it? What did you learn along the way? Is the final solution the same as what you thought, or did the ask pivot along the way? Share screenshots if available.* The final wrap-up! Try to write this similarly to how you started with the big picture. Did your initial plan end up working, and if not why? Were there any interesting plot twists throughout the process? Share the wins, the struggles, and the end result here. Screenshots can be perfect here to see a visual of your work! I also typically leave a little space at the bottom to wrap up any lessons I learned for myself, and leave a little room to talk about my time estimate and reasonings behind how it turned out the way it did. But those are completely optional. --- Because I use a Notion database to help me keep track of these documents, I also have a few properties I can fill out related to the project this document is for, what my time estimate and result were, and the quality attributes I selected. Having those visible at a glance is super helpful for me. The biggest thing I’d recommend to track with this is the date you filled it out. Having that date to help you organize and find your documents is super helpful as your collection grows. I typically title mine based on the project it’s for and the name of the task, but you can name yours whatever you’d like! Now let’s talk about how to track our time for this task. The time estimate template This one is a lot less detailed, but just as important! Being able to improve your knowledge of how long different tasks take you will be a super handy skill as your career continues. The main idea with this template is to keep track of two sections: how long you think something will take you (the estimate), and how long it truly takes you. Our goal is to get those two sections to be as close to the same number as possible. Remember that our goal here is NOT perfection. That’s impossible to reach. Our goal is simply to get them to be close to each other. Most people (even managers) understand that an estimate is not a guarantee. But the closer you can get your estimates to the true time it takes you, the more reliable you seem and the more accurately your team can make progress. There are three main sections to this template. The actual numbers Most importantly, we want an estimated total time and an actual total time, as well as a calculation of the difference between those two numbers. Is our estimate higher, or is the actual total time higher? That difference is what we’re trying to keep as close to zero as possible. I like to break my time tracking down into categories, so I can also see if particular parts of my work take me longer (or shorter) than I think. For each of these, I do the same thing: make an estimate, and record the actual value. The categories I like to track are: Investigation: time to fill out my architecture design, do a little looking into the task, make sure I understand fully what I’m being asked to do, and that I have all the information I need to complete it. Coding: time to do the actual work. Most of my time calculation goes into this category. Testing: I use this for either writing actual unit or end-to-end tests, or for manual testing. This is where I double-check to make sure I didn’t break anything or track time spent on that one last piece of functionality that doesn’t quite work right. Review: any feedback I get on my Pull Requests or code reviews that require me to make changes go into this category. Space to record the numbers as I go The Pomodoro technique works really well for me with time tracking, though I change up my “working time” numbers to make them easier for me to calculate. I’ve found the most straight forward way for me to do this is to have a title for each section of time that I’m tracking, with space underneath each one. Then, I have a legend of colored dot emojis related to a different amount of time: 15 minutes, 30 minutes, and 60 minutes. Then, as I do my rounds of working time, each time I’m done with a round, I select the right colored dot for the amount of time I did, copy it, and paste it under the section the work I did belongs to. Keep repeating this until the work is complete! Once your task is done, all you need to do is count your dots, and record the total number they represent in your actual time section from above. Here’s a screenshot of what one of my completed sections look like, so you can better see what I mean. From this tracking section, I can quickly see that I spent 15 minutes on both testing and review, and an hour and 45 minutes on coding. If I don’t happen to spend any time on a section (in this instance, I’d done some investigating in a separate ticket, so I already knew the work that needed to be done), I just leave it blank. I have a section at the top of my page for tracking the total number for each category. So I use this area to keep track as I’m doing small rounds of work. Then, when I’m done, I add up each number and put it in the section at the top of the page for that category. Notes I also have a section for notes at the bottom of my document. I keep this area for anything relating to my time tracking. Did something break unexpectedly, causing my estimate to be off? Did I not need a section for some reason? Or did something work way better than I thought it would? Those are the kinds of things worth keeping notes of here. Can you tell why your estimate and actual times were off? Sometimes we simply don’t know, but being able to keep notes on the things we can realize as we’re doing them helps us get better the next time! Tying these together and talking about it with others You can use both of these templates together or on their own, and you’ll gain a great amount of knowledge about your skill level and your growth over time from them! But they can also really shine using them together. While these are great tools for your own personal knowledge and growth, I also highly recommend sharing them with someone else. It’s a great idea to set a goal to be better with estimating your time, and sharing that goal with your manager. Then, you can use the time estimation template to build up some estimates, and share those with your manager. Maybe you have a senior developer on your team that you really respect, and you’d like to get their opinion on the task you’re working on. If you’ve filled out the architecture design for that task, you can share it with them and have a conversation about it. They can potentially provide you with things to consider for your next task, or get you thinking more deeply about the quality attributes you selected, and why they may or may not have been the best fit for your work. The design documents are also great to share with your manager! It’s a great way to show that you’re starting to think about your work on a deeper level and starting to consider the quality and complexity of your work. It can also be helpful reference material for them when promotions and new work becomes available. They’re more likely to think you might be a good pick for the next big thing if you’re already showing them you’re starting to think about things at a higher level! The Notion template links The links for both of these documents as Notion templates are below. Please feel free to duplicate a copy for yourself if you like using Notion, or just take a peek at them to see the actual layout of them and adapt that for whatever tool works best for you. These documents are set up to be used within a Notion database. We won’t cover that in detail here, but the Notion documentation should be able to take care of those details for you (and we have a link to get you started below as well). In general, you can create a database within Notion, and then set a template to use for each new entry. That way, when you go to create a new item, it will automatically pull up these templates for you, so you don’t have to copy and paste them every time! And the fields at the top will be visible when you go to look at your database, which makes it a little nicer to get a quick overview of your documents and the progress you’re making. Now go forth and deepen your knowledge! - Time estimation template - Architecture design template - Notion database templates documentation...

TC39 - How Changes are Made to JavaScript cover image

TC39 - How Changes are Made to JavaScript

Introduction The JavaScript ecosystem is constantly changing. As developers, we are very familiar with the ever-shifting landscape of frameworks, libraries, and tooling required to write our applications. In addition, there are other runtimes for Javascript beyond the browser, including Node, Deno, Cloudflare Workers, with more being released all the time. All of this - the tooling, the frameworks, the runtimes, even the language - are based on standards developed by a group of individuals and companies know as TC39. TC39 (Technical Committee 39) is a committee organized by Ecma International, a nonprofit standards organization for information and communication systems. In 1996, Netscape (the original creators of JavaScript) began meeting with Ecma to discuss standardizing the language. The first standard edition of JavaScript (called ECMAScript) was adopted in 1997, with further releases of the standard happening since then. The JavaScript we use today is an implementation of these standards, and each runtime of JavaScript works to implement them for use by developers. This standardization across runtimes was not always a guarantee, however. For a long time, the Node project tended to go its own way, implementing Node-specific APIs and methods of accomplishing development work. Many within Node originally felt that TC39 was forcing their standards on the Node project, despite Node havings its own needs and solutions. There are a number of examples where Node went one way, and the JavaScript standards went the other - Promises and imports are two good examples. However, the Node steering committee today is much more open to adopting standards, any many of its members participate in discussions with TC39 regarding new features and changes to JavaScript. This is in part because developers want the same language and APIs in both the browser and their Node environments, but also, because there are other runtimes to consider when developing JavaScript code. This standardization has brought about a number of changes to the language and the JS ecosystem, as more voices are coming together to work on new solution to existing problems. What does TC39 do? As I mentioned, TC39 is a committee focused on developing and ensuring the JavaScript standard. From their website, "Ecma International's TC39 is a group of JavaScript developers, implementers, academics, and more, collaborating with the community to maintain and evolve the definition of JavaScript." The committee takes proposals from the community, and determines which are going to be worked on to be implemented in the JavaScript standard. A number of major companies are directly involved with TC39, with members representing Microsoft, Google, Apple, Intel, Mozilla, eBay, and more. Some are connected to universities, while others participate as individuals. In addition to voting members, many people participate in discussions regarding the various proposals that have been submitted. While the committee itself only meets every two months, these discussions on the proposals and specifications are taking place publicly, and anyone can participate in the conversation. Proposals are hosted on GitHub, and so discussions are as simple as creating an issue or pull request. A TC39 Discourse page is another way for the JavaScript community to discuss any current proposals or new ideas that haven't been formalized yet. When the committee votes to approve a new standard, this change is then implemented in the runtime authors (such as Google's V8). But how does a new standard get added to JavaScript? The Stages of Proposal There are 5 stages to adding a new standard to JavaScript, starting at Stage 0. Each of these stages has different requirements for completion. There is no time limit on moving a proposal from one stage to the next, and no guarantee that a given proposal will be completed. TC39's website hosts a process document that explains in detail what a given stage means, and how a proposal advances to the next stage. Let's walk through the stages, and look at some of the proposals currently at each stage. Stage 0 The first stage for any proposal is stage 0. This stage is the first step in adding a feature to JavaScript. Anyone can make a proposal. You don't have to be a member of TC39. A detailed document outlines the process for submitting a new proposal into stage 0. The pain purpose of this stage is to start a conversation and begin formalizing the proposal in order for future work to be done with it. The first thing that needs to be done when a proposal is stage 0 is to find a champion. A champion is someone from TC39 who will take the lead on moving a proposal forward. In addition, work will need to go into the documentation for the proposal, such as an outline of the problem that is being addressed and a high-level API design. Once these requirements are met, the committee can vote to move the proposal to Stage 1. An interesting Stage 0 proposal is to add a deprecated global or directive to the language, so that it's easier to alert a developer when a given API has been deprecated. Example: ` Stage 1 The purpose of Stage 1 is to make the case for changing the JavaScript standard, describing the proposed solution, and any potential problems that it could cause or could be impacted by. The main goal of the committee for a Stage 1 proposal is to devote time to examining the problem, and ensuring the proposal resolves it. Typically, browser/runtimes won't make any changes to implement a Stage 1 proposal, because the API could still change pretty drastically. However, polyfills or demos may be created in order to get additional feedback on a given API. These features should not be considered production ready. Once the initial spec has been developed, the committee can vote to move the proposal to Stage 2. The pipeline operator is a great example of a Stage 1 proposal. Its goal is to add a pipeline operator (|>) to JavaScript, in order to pipe function returns or values from one function to the next. There has been some discussion around how it should pass arguments into the second function ` Another Stage 1 proposal is the compartments proposal, which helps resolve a number of issues regarding global scope of a JS file or application. Check it out! Stage 2 When a proposal reaches Stage 2, the committee is focused on writing a precise syntax using formal language. This still doesn't mean that a feature is going to make it to JavaScript, but some experimental implementations will start appearing. This process to create a defined syntax could take from months to a year, with some proposals sitting in Stage 2 for much longer than that. However, when a feature leaves Stage 2, it typically means that the proposal will eventually make it to the final spec. Changes may still happen, but typically only limited changes will happen once a proposal moves out of Stage 2. There are a number of interesting proposals in Stage 2 at the moment, including decorators and iterator helpers. Often, proposals may get stalled in Stage 2. Decorators are a good example of that. According to the TC39 proposals repository, Decorators haven't been presented since September 2020, and were originally discussed back in 2018. Sometimes, the problem being solved has multiple solutions, or there are multiple competing solutions that could be adopted. Other times, the problem turns out to be less urgent or important than previously thought. While it can be frustrating to have a proposal stall out, it's important to remember that any change to JavaScript is permanent - no standardized feature in JavaScript is removed from the spec. Better to move slowly than to end up with half-finished APIs that don't actually solve anything. Stage 3 Stage 3 is the final stage for changes to be made to the specification. Spec compliant implementations will start to roll out, typically behind feature flags, in order to get developers to start using the feature and provide feedback. Changes are still possible, but they are expected to be limited in nature. The new Temporal object is a Stage 3 proposal that's pretty exciting for the JS ecosystem. Temporal will act as an upgrade from the Date object and support additional feature such as time zones. A prototype polyfill can be found on NPM, although keep in mind that it doesn't create a global Temporal object like the finished spec would do. And again, remember that this is still a proposal, and should not be treated as production ready. Another great example of a Stage 3 proposal is Realms, which provides a way to create distinct global environments. Stage 4 When a proposal reaches Stage 4, it is considered complete and ready for implementation by the different runtime vendors. Browsers will start to ship the feature, and other runtimes like Node and Deno will also work to include it in upcoming versions. A features is ready for Stage 4 when it passes all the agreed upon tests, and there has been sufficient testing by developers to ensure that the API is sound. Once a feature is in Stage 4, its spec is not intended to be changed. This is to ensure that the web platform is stable into the future - it's important to not break the web with changes to JavaScript. Two good examples of recent Stage 4 proposals are nullish coalescing and Promise.any. These features have been released into major browsers, and are available to be used today in modern JavaScript applications. Conclusion It's pretty amazing that the JavaScript language is developed in the open like this, for all interested parties to add a voice to the discussion. Not every standard or programming language is developed like this. However, this level of openness can also be difficult, especially if a specific feature gets stalled or a proposed API ends up not being accepted. If you submit your own proposal to TC39, remember that you are trying to solve a specific problem, not simply create a feature in JavaScript. Your proposal may be adjusted or replaced as other voices are added to the discussion. Also, keep in mind that it could take a long time for a proposal to make it into the language, if ever (looking at you, decorators). Also, while I've highlighted mostly good things about this process, it's also possible for a single member to hold back a feature from advancing into the next stage. This can be frustrating, but as noted above, it's important for JavaScript to be developed methodically. Having multiple standards or multiple interpretations of those standards wouldn't benefit anyone, after all. At the end of the day, remember that TC39 is made up of indivduals who are invested in the JavaScript ecosystem, and want to work together with developers to improve the language. They have a lot of context and understanding for how features are implemented that developers may not have. Proposals that don't make it into the language may not make it for valid reasons. Does any of this interest you? Do you want to contribute to the discussion? You can find ways to participate on TC39's website, including links to their Github and Discourse....

What does it actually look like to build software with AI today? Not in theory, but in practice. cover image

What does it actually look like to build software with AI today? Not in theory, but in practice.

What does it actually look like to build software with AI today? Not in theory, but in practice. At the Leadership Exchange, this was the question at the center of the Developer Panel, where leaders from across the industry unpacked what’s really changing inside engineering teams and what organizations need to do right now to keep up. The Developer Panel at the Leadership Exchange explored the cutting edge of AI in software engineering and examined what organizations should focus on today to prepare for the future. Moderated by Jeff Cross, Co-Founder & CEO at Nx, the panel featured Victor Savkin, Cofounder & CTO at Nx, Alex Sover, Vice President of Engineering at OpenAP, Brent Zucker, Senior Director of Engineering at Visa, and Jonathan Fontanez, AI Engineering Lead at This Dot Labs. Panelists shared insights into how AI is transforming the software development lifecycle and how teams can adopt tools effectively while preparing for organizational change. Panelists discussed emerging workflows, including CI-in-the-loop, agentic healing, and context engineering. They examined how validation, code reviews, and PRDs are evolving alongside AI capabilities and how teams are integrating external sources such as production traces to improve quality and reliability. The discussion also covered what the next generation of agentic tools might look like and how these capabilities will shape engineering practices in the near future. Adoption of AI comes with challenges. Teams often rely on plugins or extensions without foundational understanding, and individual contributors may fear displacement. Panelists emphasized that education, governance, and skill-building are essential for teams to manage AI agents effectively while maintaining quality. They also highlighted the need to standardize workflows and ensure organizational alignment to fully leverage AI capabilities. The conversation extended beyond technical challenges to organizational implications. Panelists discussed how teams can avoid issues like Conway’s Law, manage distributed teams effectively, and evolve engineering practices alongside AI adoption. Leadership and management strategies play a crucial role in ensuring that AI integration delivers meaningful outcomes while maintaining efficiency and alignment with business objectives. Key Takeaways - AI workflows require both technical and organizational preparation. - Education, governance, and skill development are essential for successful implementation. - Forward-looking teams are rethinking validation, CI pipelines, and context management to fully leverage agentic AI. The discussion highlighted that adopting AI at the cutting edge is not just about new tools - it is about rethinking processes, workflows, and organizational culture. Companies that embrace this holistic approach are most likely to succeed in leveraging AI to its full potential. Are you interested in more conversations like this? Message us for an invite to the next, or for a private discussion around these topics. Tracy can be reached at tlee@thisdot.co....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co