This Dot Blog
This Dot provides teams with technical leaders who bring deep knowledge of the web platform. We help teams set new standards, and deliver results predictably.
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....
Feb 2, 2024
It's Impossible For This Code to Fail - with Loren Sands-Ramshaw
Loren Sands-Ramshaw, Developer Relations Engineer at Temporal joins Rob Ocel to talk about reliable application development. They introduce the topic of durable execution and talk about reliability in systems, unraveling common issues developers face and showcase the benefits that durable execution can bring to software development. They also talk about the challenges of traditional programming and the complexities of event-driven architecture. Listen to the full podcast here: https://modernweb.podbean.com/e/modern-web-podcast-s11e19-its-impossible-for-this-code-to-fail/...
Jan 24, 2024
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...
Jan 6, 2023
What is a Monorepo and What Are the Advantages for Using It in Your Project?
Monorepos are very popular in the tech industry, and many large companies like Microsoft and Google use them. But what exactly is a monorepo and would it work for your project?...
Sep 23, 2022
Remix Deployment with Architecture
Intro Today’s article, will give a brief overview of the Architect framework and how to deploy a Remix app. I’ll cover a few different topics, such as what Architect is, why it’s good to use, and the issues I ran into while using it. It is a straightforward process, and I recommend using it with the Grunge Stack offered by Remix. So let’s jump on in and start talking about Architect. Prerequisites There are a few prerequisites and also some basic understandings that are expected going into this. The first is to have a GitHub account, then an AWS account, and finally some basic understanding of how to deploy. I also recommend checking out the *Grunge Stack* here if you run into any issues when we progress further. What is Architect? First off, Architect is a simple framework for Functional Web Apps (FWAs) on AWS. Now you might be wondering, "why Architect?" It offers the best developer experience, works locally, has infrastructure as code, is secured to the least privilege by default, and is open-source. Architect prioritizes speed, smart configurable defaults, and flexible infrastructure. It also allows users to test things and debug locally. It defines a high-level manifest, and turns a complex cloud infrastructure into a build artifact. It complies the manifest into AWS CloudFormation and deploys it. Since it’s open-source, Architect prioritizes a regular release schedule, and backwards compatibility. Remix deployment Deploying Remix with Architect is rather straightforward, and I recommend using the Grunge Stack to do it. First, we’re going to head on over to the terminal and run *npx create-remix --template remix-run/grunge-stack*. That will get you a Remix template with almost everything you need. *Generating remix template* For the next couple of steps, you need to add your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to your repo’s secrets. You’ll need to create the secrets on your AWS account, and then add them to your repo. *AWS secrets* *GitHub secrets* The last steps before deploying include giving CloudFormation a SESSION_SECRET of its own for both staging and production environments. Then you need to add an ARC_APP_SECRET. *Adding env variables* ` With all of that out of the way, you need to run *npx arc deploy*, which will deploy your build to the staging environment. You could also do *npx arc deploy —-dry-run* beforehand to verify everything is fine. Issues I Had in My Own Project Now let's cover some issues I had, and my solution for my own project. So, I had a project far into development, and while looking at the Grunge Stack, I was scratching my head, trying to figure out what was necessary to bring over to my existing project. I had several instances of trial and error as I plugged in the Architect related items. For instance: the arc file, which has the app name, HTTP routes, static assets for S3 buckets, and the AWS configuration. I also had to change things like the *remix.config* file, adding a *server.ts* file, and adding Architect related dependencies in the package.json. During this process, I would get errors about missing files or missing certain function dirs(), and I dumped a good chunk of time into it. So while continuing to get those errors, I concluded that I would follow the Grunge Stack, and their instructions for a new project. Then I would merge my old project with the new project; and that resolved my issues. While not the best way, it did get me going, and did not waste any more time. That resolved my immediate issues of trying to get my Remix app deployed to AWS, but then I had to figure out what got pushed. That was easy, since it created a lambda, API gateway, and bucket based on the items in my arc file. Then I realized, while testing it out live, that my environmental variables hadn’t carried over, so I had to tweak those on AWS. My project also used a GitHub OAuth app. So that needed to be tweaked with the new URL. Then it was up and running. Conclusion Today’s article covered a brief overview of what Architect is, why it’s good to use, how to deploy a Remix app and the issues you might have. I hope it was useful and will give others a good starting point....
Aug 30, 2022
Progressive Web Apps and Mobile Apps
Jul 22, 2021
How to Implement an Event Bus in TypeScript
Jul 16, 2021
What Does the Future Hold for PWAs?
Intro We're talking about Progressive Web Applications (PWAs), a hot topic in today's developer community. Many are just realizing what is it, and some have been developing it for a while as it's been slowly gaining a reputation. For many companies today, finding the right starting point for a new application takes time and careful planning, and often the question is "where do we start?" PWAs are worth considering for many businesses, and will likely become the web standard in the near future. To begin, we need to know what a PWA is. After that, we can understand its relevance in today's shifting tech landscape. What is a PWA? A PWA could be described simply as "apps for the web". It is a website disguised as an app without being stuck in the browser. For the developer, this approach reduces the number of architectural headaches in app development. > PWA is a brand for the modern web with a set of standards for creating native app-like experiences. The developer uses the browser to deliver an application, but to the end user, it's just an app. The *progressive* part of this is the on-going engagement from browser with the end user as they continue to use the application. Engagement could look like asking the end user if they'd like to install the wen app locally without the need for the browser. While this is true for the end user, PWAs can be thought of as more than one thing: it's a brand for the modern web, and it's also a movement for creating native app experiences that are installed on devices similarly to native apps. From a technical perspective, it's a set of standards defining information about the app, where and how it launches, with what themes, and a service worker handling network connection. Information about the app comes from a web manifest and can specify where the app launches and its UI, and the service worker can handle a number of tasks including enabling offline capabilities for an app. Whether as a brand, a movement, or a technical standard, all of these parts come together to create an experience that's indistinguishable from native apps. What is a service worker? For PWAs, "installing" an app isn't like your typical install. In fact, you're not actually installing anything. It's a combination of adding an icon to your systems desktop or screen while performing route navigations like typing a url in a web browser. The things that control how the app handles network traffic events is the Service Worker. It's like a proxy that exists between your app and the network. For example, while process network traffic, the app could stop and do something else as a side effect- performing other network calls, fetching more assets, etc- and serving them back to the user. Before there were service workers, there was app cache, but it didn't keep the app synced. Service worker can be extended to do other things as well. It's a process that's not running all the time. If the app is idle, the service worker shuts down after a few seconds of inactivity, but it can launch very quickly. For instance, if a user isn't in the app, but a notification comes in, that will trigger the service worker, perform any checks, and show the notification bringing the user back into the app. > Workbox is a tool that helps with groups of service worker tasks, background syncing, and app refresh, helping developers avoid the pitfalls building these patterns from scratch. One thing to note as a common pitfall of implementing a service worker from scratch, is a PWA opened with multiple tabs. Since the service worker is attached to each instance of the app (that is, every tab that's opened), you have multiples of the same service workers running, so you would have to account for that scenario. Why are PWAs important today? Technologies like HTML5 spec, CSS3, geolocation, just to name a few, help establish the idea for the modern web. But where these tehcnologies failed to meet a company's needs, a new "brand" must step in to take its place. This new brand helps companies re-engaged with the web in an attempt to rebuild trust with the web. > What PWAs bring to the table is a new way of defining how the modern web works, how it's used by the end user, and how companies re-engage with the web under a newer, better brand. Buy-in from a company is a huge factor in an apps success. While some companies can look at examples of great apps, and decide that that experience is, or what they would like, does the web provide all the features needed to succeed now and in the future? Company buy-in is often based in future successes, whether or not today's technology will meet that goal, or if competitors buy into another technology. Any company can choose a product for mobile development, like Flutter, and potentially lose business. Regaining trust in the web also involves comapanies being aware of available features, and roadmapping what technologies that company needs. Some of the trust has been lost in the work because you don't know if technologies will keep up. Where are we now with PWAs? One can say that we're in an early Renaissance. We are just now starting to get the capabilities that we need to be able to build real apps using web tech. However, the awareness for what's available or in development is lacking. So how can we build awareness while we're still in development in the modern web? Build cool stuff with the technology we have available to show off what's possible! Every big company has at least three dev teams, which is detrimental from a business cost perspective, and they're all building the same experience with three different technologies - web, Android, and iOS. Yet, many apps don't need all those variants. > PWAs are a great cost-effective strategy for companies to consolidate web, Android, and iOS apps into one. Additionally, for the end user, they may get a great web expereince, but end up with a poor native mobile app experience. The different sets of work required to make the other experiecnes (Android and iOS) consistent results in wasted effort, especially if the app doesn't work, leaving the user to run back to their laptop, only to see that the web version works as expected. With PWAs, you minimize the cost to create the same product for different platforms because it works independently of the operating system- one of the greatest advantages for PWAs. Companies can begin to develop for a single application with a consistent experience. Caveats for developing PWAs Today, Apple's Safari browser is impacting the web because it doesn't offer the same features as other browsers- which is ok for them to do- but they restrict other apps on their devices as well. Chrome, and any other browser, on iOS devices, is simply a wrapper for Webkit. They're not different browser engines, so they lack the capabilites that other browsers already have. This doesn't mean that we can't built experiences for iOS users that are progressively enhanced as those capabilities become available. What it means for the end user and developer is that the web on this browser will eventually become irrelevant, and both parties will have to move on because they aren't met where they are. Perception is another factor that can hinder progress as well. In the case of Apple products, Apple users may not be aware of what's missing unless they're looking for specific features. A user might need a specific feature that a certain set of hardware can't provide. How do we advance web standards? A side note for those who've experienced roadblocks from unavailable features: it helps to complain or submit requests, even repeatedly, for features to arrive. Big company names will stand out among all of the requests for features on webkit. How can we make the switch to PWAs? Regardless of whether or not a company has a released product, here are a few things to keep in mind for implementing PWAs today: Use HTTPS Websites must be served over HTTPS. Where many APIs can be split and accessed from different domains, all new APIs should come from a single domain or origin, keeping with the good security models for the web. Take for instance a user who clicks a link an it directs them to another domain. That might take them out of your PWA. So you should, in theory, only have one origin. Configure service worker for offline mode Requirements for a service worker have now changed to include offline capailities. It used to be that you just need to have a service worker: it was good to go. Now, you need to have some kind of offline experience. We're moving towards having an offline experience, but it's still in progress. For now, service workers should provide a page or notification to the user that they're offline. Have a manifest for the app Lastly, have a web manifest, typically in JSON, where you describe your app. The manifest determines how the app launches and with what themes. Does versioning matter with PWAs? When it comes to version control, PWAs have the advantage of already being installed. Because they're already installed, you can provide a couple ways to get the user onto the latest version. One solution is to provide an opt-in strategy, or update on navigation, but another is a true analogous experience. This can be accomplished during the first time somebody opens the app, immediately showing them content while in the background, prepare newer content, or experiences. Part of that is achieved by caching assets locally. Then next time when the app boots up, if it already has a service worker installed, it begins serving from the cache immediately. The way the model can be built or designed is to immediately show the old experience on launch, and then perform updates in the background that are prepared for the next launch. Deciding the best approach doesn't come without its pitfalls too. There is a chance of locking a user into an older experience if a rollout strategy isn't implemented correctly. Ultimately, whatever strategy makes the most sense to a business is the correct approach. There are tools for helping with version management, like WordBox, which helps with pre-cache assets. Keeping the app experience consistent App consistency is key to a successful PWA. Unfortunately, there are limitations with them on iOS devices, but with Android devices, there's no telling the difference. Frameworks, like Ionic, the closest to the desired web solutions for distribution, are marketing for usage in PWAs. They have capacitor, a tool for getting an app into a native package, and into the app store quickly. However, that brings up a concern about awareness for PWAs that isn't the standard download from an OS's app store. To keep awareness up for new apps as PWAs, developers take advantage of Google's offerings for wrapping their websites to be displayed in the Google Play store. The same rules of the app store still apply as the do for other apps. There are other services being worked on for assisting app store launch like Cordova. App distribution channels Software distribution is hard. Fundamentally, it's one of the more difficult problems as a developer in general. The web model for publishing new versions of a PWA stays intact. It's as simple as pushing your code to a new server, with some of the work, as part of that effort, goes to generating a service worker that has information about that built. It extremely easy to throw a webpage on the internet, and that's really all that needs to be done while having additional amazing web capabilities. Standard app distribution is difficult because there's all the code form for the specific platforms- signing and buying validation certificates, for example. This is the reason that PWAs are so important and valuable. Best of all, updates can be published at any time. Apps aren't stuck in a review queue, companies aren't losing business, and no middle entity is standing between the company and the user. What makes a successful PWA? Just like any web application, a successful PWA is one that users want, and that works seamlessly between desktop and mobile experiences. Think about what the user is doing, and how they might use an app. That will often guide the design and experience. Over-designing experiences for different platforms becomes a headache when you consider the different platforms and dedicated launguages you have to work with. As in Swift for Apple, you're restricted to what the platform allows, but a PWA opens up the ability to design consistanly across devices. A button remains the same button it was as described in the manifest, and because it all comes from a single code source, there aren't multiple configurations needed. Implement what you need In thinking about what the user is doing, enabling features that aren't needed or not providing features that work similarly to most common native app experiences, will prove an unsuccessful app for the end users. If web capabilites don't exist that an app absolutely needs to succeed, these features that aren't ready can always be enabled when they are. Lower the bar to entry Make it easy for a user to access an app. If a user is on a Starbucks line and sees a notice for a rewards program, but they don't have the app installed, it wouldn't be effective for the user to download the app and have to wait for the download to finish. Once the download is finished, they'd still have to login, whereas, the website remembers their credentials. Companies spend so much money trying to figure out how to get a user to download an app, but the conversions happen when products are made easily accessible. Consistent app experience A successful PWA means that users shouldn't be made aware of differing experiences from a native app to PWA. On that line of thought, the thing that should be different is the security. Again, users shouldn't be able to tell the difference here, but there are differences between native apps and PWAs regarding authentication. In the browser, we can take advantage of Cors to secure a site over https. In native apps though, you can just hit the network without asking for security. This means that PWAs, with a good authentication path, are more secured right away, and without extra configuration. For native apps, the default strategy was to make sure it's safe, and then run the app, but the web default says that it's probably not safe, so let's make sure that the browser protects the user as much as possible. Conclusion PWAs' benefits far outweigh any arguments against them. They are a great cost effective strategy for minimizing codebases across web and mobile platforms. What we've seen, so far, only scratches the surface on what we can do with the web, and there's so much more on the horizon that's being released. Thanks to my guests Kenneth Rhodes, Adriana Salazar, and Henrik Joreteg for their thoughts and experience on PWAs, and for helping to build up awareness in the community with the work....
May 5, 2021
Decomposing a project using Nx - Part 2
Decomposing a project using Nx - Part 2 Large projects come with a set of challenges that we need to remember in order to keep our codebases clean and maintainable. In the previous article, we talked about the horizontal decomposition strategy, and how it can help us manage our application code better. In this article, I would like to focus on the second strategy for splitting the application code - vertical decomposition. Vertical decomposition The more the application grows, the more it becomes important to create, and keep boundaries between certain sections of the application codebase. This is where the concept of vertical decomposition comes in. In most large-scale applications, we should be able to distinguish certain areas that concern different parts of the business value or different parts of user interaction. Let's use the slightly expanded version of the application used in the previous article. In addition to the liking and disliking functionality for photos, we can now see and edit the user's profile. You can find the relevant code on my GitHub repository. As in most cases, the interaction with the user profile here can be considered as a completely separate part of the application. This gives us the clue that this part of the codebase can also be separate. The distinction between modules that concern different scopes of the application is what I call a vertical decomposition. This creates a second axis on which we can split the codebase to minimize the concern that each part of the application needs to be aware of. We can imagine that, if the example application were to grow, we could create separate modules for them. E.g: - photos - photos related features - user - user profile feature - chat - chatting between users feature In the aforementioned example, we can see 3 possible parts of the application that don't have very strong dependencies between each other. Separating them upfront will ensure that we don't end up with too many entangled features. This requires more conceptual work in the beginning, but definitely pays off as the application grows, becomes more complex, and requires additional features to be implemented. Using Nx to implement those boundaries With Nx, and the CLI it comes with, I do recommend creating separate libraries within the monorepo to emphasize the boundaries between modules of the application. In the previous article, I introduced the concept of tags used by Nx to enforce boundaries between different types of libraries. We can use this same set of tools to create the vertical decomposition as well. It is a good practice to create a common prefix for tags that concern the same axis of decomposition. In the case of vertical splitting, I suggest using e.g. scope or domain prefixes. By applying this prefix to the modules defined above, we can create the following tags: - scope:photos - scope:user - scope:chat or - domain:photos - domain:user - domain:chat Similarly to the horizontal type: tags we can not assign the tags defined above to the libraries we've created for specific submodules of the application: ` nx.json And also the boundaries between scopes can be enforced using ESLint or TSLint rules. ` .eslintrc.json I recommend limiting access to only the same scope as a starting point, and enabling access to a different scope only when it is actually necessary. This way we are forced to stop and consider the connection we are about to create, and therefore we can take some time to decide whether that's the best approach. It can lead us to finding and extracting a separate scope that can be used by both current scopes. To verify that the boundaries between libraries are not violated, the following command can be run: ` Of course, the CI process should be set up to make sure that as the codebase evolves the constraints are still met. Conclusion As I have shown in the above sections, the vertical decomposition can greatly benefit the maintainability of the application code. It is especially useful when working with large codebases as they are the ones that probably contain multiple scopes/domains that can be extracted and separated. However, I encourage you to try this approach even on a smaller project as it will be much easier to grasp on a smaller scale. With Nx tools, it is very easy to set up the boundaries between application scopes, and makes sure that those constraints are kept as the application grows. If you want to read more about the architecture in an Nx monorepo, I recommend the following articles: - Semantic Grouping Folders with Nx - Tactical DDD with monorepos In case you have any questions, you can always tweet or DM me @ktrz. I'm always happy to help!...
May 4, 2021
Decomposing a project using Nx - Part 1
Decomposing a project using Nx - Part 1 Working on a large codebase brings multiple challenges that we need to deal with. One of them is how to manage the repository structure and keep it as clean and maintainable as possible. There are multiple different factors that can be considered when talking about project maintainability, and one of them, that is fundamental in my opinion, is how we structure the project. When it comes to managing large scale project which may consist of many modules, or even separate applications, a Nx Workspace based mono-repository is a good candidate for managing such a project. If you don't know what an Nx Workspace is, I encourage you to read my previous article where I introduce it along with monorepo fundamentals. In this article series, I'll show you: - 2 approaches for decomposing a project - How they can help you to better manage your project's codebase - What tools Nx Workspace provides us with that help us enforce boundaries within a project Modules vs libraries It is a well-known good practice, especially when working with a complex Web Application, to divide the functionality into separate, self-contained, and, when possible, reusable modules. This is a great principle and many modern CLIs (ie. Angular, Nest) provide us with tooling for creating such modules with ease, so we don't waste time creating additional module structure by hand. Of course, we could take it a step further, and instead of just creating a separate module, create a whole separate library instead. This seems to be a bit of an overkill at first, but when we consider that Nx CLI provides us with just as easy a way of creating a library as we did for a module, it doesn't feel so daunting anymore. With that in mind, let's consider what the benefits of creating a separate library instead of just a module are: - libs may result in faster builds - nx affected command will run the lint, test, build, or any other target only for the libraries that were affected by a given change - with buildable libs and incremental builds, we can scale our repo even further - libs enable us to enforce stricter boundaries - code sharing and minimizing bundle size is easier with libs - we can extract and publish reusable parts of our codebase - with small and focused libraries we only import small pieces into the application (in the case of multi-app monorepo) Decomposition strategies - horizontal In this article, I want to focus on horizontal decomposition strategy, which is great not only for large, enterprise projects, but for smaller applications as well. Horizontal decomposition focuses on splitting the project into layers that are focused on a single technical functionality aspect of the module. A good example of libraries type in this case is: - application layer - feature layer - business logic layer - api/data access layer - presentational components layer As you may see in this example layering concept, each of the library types has a specific responsibility that can be encapsulated. I have created an example application that demonstrates how the aforementioned decomposition can be applied into even a simple example app. You can find the source code on my repository. Please check out the post/nx-decomposition-p1 branch to get the code related to this post. This application allows a user to see a list of photos and like or dislike them. It is a very simple use case, but even here, we can distinguish few layers of code: - photo-fe - frontend application top layer - photo-feature-list - this is a feature layer. It collects data from data-access layer, and displays it using ui presentational components. - photo-data-access - this is a layer responsible for accessing and storing the data. This is where we include calls to the API and store the received data using NgRx store. - photo-ui - this library contains all the presentational components necessary to display the list of photos - photo-api-model, photo-model - those are libraries that contain data model structure used either in the API (it's shared by FE and BE applications), and the internal frontend model. API and internal models are the same now but this approach gives us the flexibility to, for example, stop API breaking changes from affecting the whole FE application. To achieve this we could just convert from API to internal model, and vice-versa. This application decomposition allows for easier modifications of internal layer implementation. As long as we keep the interface intact, we can add additional levels of necessary logic, and not worry about affecting other layers. This way we can split responsibility between team members or whole teams. Nx workspace comes with a great toolset for managing dependencies between the internal libraries. A great starting point to get a grasp of the repository structure is to visualize the repository structure, and its dependencies. The following command will show us all libraries within a monorepo and dependencies between those libraries: ` It will open a dependency graph in a browser. From the left side menu, you can choose which projects you want to include in the visualization. After clicking Select all, you should see the following graph: You can read more about dependecy graph here: - Analyzing & Visualizing Workspaces - nx dep-graph - documentation Enforce boundaries As you may see in the dependency graph above, our application layer is accessing only certain other parts/libraries. As the project grows, we would probably like to make sure that the code still follows a given structure. I.e. we would not like UI presentational components to access any data access functionality of the application. Their only responsibility should be to display the provided data, and propagate user's interactions via output properties. This is where Nx tags comes in very handy. We can assign each library its own set of predefined tags, and then create boundaries base on those tags. For this example application, let's define the following set of tags: - type:application - type:feature - type:data-access - type:ui - type:model - type:api-model - type:be Now, within the nx.json file, we can assign those tags to specific libraries to reflect its intent: ` Now that we have our tags defined, we can use either an ESLint or TSLint rule provided by Nrwl Nx to restrict access between libraries. Those rules are named @nrwl/nx/enforce-module-boundaries and nx-enforce-module-boundaries for ESLint and TSLint respectively. Let's define our allowed libraries anteriactions as follows: - type:application - can only access type:feature libraries - type:feature - can only access type:data-access, type:model, type:ui libraries - type:data-access - can only access type:api-model, type:model libraries - type:ui - can only access type:ui, type:model libraries - type:model - can not access other libraries - type:api-model - can not access other libraries - type:be - can only access type:api-model libraries To enforce those constraints we can add each of the rules mentioned above to the @nrwl/nx/enforce-module-boundaries, or nx-enforce-module-boundaries configuration. Let's open the top level .eslintrc.json or .tslint.json files, and replace the default configuration with the following one: ` For type:model and type:api-model, we can either not include any configuration, or explicitly add configuration with an empty array of allowed tags: ` Now, you can run the following command to verify that all constraints are met: ` You can set up the CI to run this check for all the PRs to the repository, and therefore, avoid including code that does not follow the architectural pattern that you decided for your project. If any of the aforementioned constrains were violated, the linting process would produce an error like this ` This gives a clear message on what the problem is, and tells the developer that they are trying to do something that should not be done. You can read more about Nx tags & constraints in the documentation. Conclusion When designing a software solution that is expected to grow and be maintained for a long time, it is crucial to create an architecture that will support that goal. Composing an application out of well-defined and separated horizontal layers is a great tool that can be applied to a variety of projects - even the smaller ones. Nx comes with a built-in generic mechanism that allows system architects to impose their architectural decisions on a project and prevent unrestrained access between libraries. Additionally, with a help of Nx CLI, it is just as fast and easy to create new libraries as with creating a new module. So why not take advantage of it? In case you have any questions, you can always tweet or DM me @ktrz. I'm always happy to help!...
Apr 8, 2021
Building a Multi Platform Community Engagement Tool
Intro We’re building a community forum for our consumers to discuss our products here at A Latte Java. This is going to be a new greenfield project that is a companion app to our ecommerce site. Our team has determined that we really need both desktop and mobile presences and need to get a MVP to market in the next 3 months so we’re on a relatively tight timeline. For this, we’re starting with just the basic product idea and are having our first round table discussion to think through the requirements and identify options for creating our solution. The only requirements from the business is to generate a space where people can safely discuss how they use our products and share their how-to guides. Mobile & Desktop When we said we needed both mobile and desktop presences, what are some of the options to get us there? Do we have to build a website and a mobile application? Are there ways to share or reuse code across the different platforms? Hybrid apps and PWAs are a few solutions that can get us to the solution that we're seeking. Hybrid apps let us use tools like React Native or Ionic to use web technology we're familiar with and compile it to native app code. > One of my first thoughts would be to create some kind of a hybrid app so people can comment on the go as they feel like it. Maybe they want to snap a picture of their coffee as they're brewing it in the morning or take a quick video. - Morgan Worrell On the other hand, we have solutions like PWAs that allow us to leverage our existing website code to generate an app-like feeling version of our website that users can use instead. > I think what's popular nowadays is building PWAs. This will basically be an a web app, but it can act as a kind of native app within the mobile device. That would definitely cut us some time to deliver it more quickly, especially in the beginning. - Chris Trzesniewski Going purely native requires us to hire speciality developers in Objective-C and Java and maintain 3 different code bases: web, iOS, and Android. But is it worth going down this path? > The average mobile user installs zero apps per month. - Rob Ocel Mobile Device Differences A key problem with supporting multiple devices is the look and feel of the app on different devices. Users on different devices have expectations of how apps should work on their respective device. Forgetting some of these details can even be detrimental to your overall build and leave your app feeling boring or lackluster. > You can see a picture of the app without seeing the device frame itself and you can go 'that's an Android app' or 'that's an iOS app' and there's a lot of those subtle differences. - Rob Ocel So how do we keep our app engaging? What can we do to drive traffic into the application and keep users active in the community? Gamification Creating feedback driven interactive features can be the major differentiator. Look at how other companies or products in the same or similar space are doing things. On one hand, you could go the social route like Untappd where you can keep a rating of all the different drinks you've tried and share with your friends, which then gives you badges and other little gamey features. On the other, you could try to follow the Yelp model where you become an amateur food critic and others can follow you to get opinions on restaurants to try. You could also go the StackOverflow approach where different actions get you points in some internal "ranking" system. Do we really need both then? For speed, we've decided that a website is the most practical approach. There are certain features of a mobile device, like its constant availability and camera, that make it a must have for our app. Because we decided on a website approach, though, that means our app is accessible from a desktop so it needs to look good here as well. Using CSS responsive design practices, we can easily achieve a site that looks good on both desktop devices and mobile devices. Post MVP Eventually, we might want to have a native app to get some of the other awesome features that the mobile hardware allows that aren't necessarily available through the web version of the app. This will lead us to an eventual migration, but one we can focus on more intentiontally after the initial launch. > All migrations are effort. It's just whether you're going to spend the effort or not. Sometimes there's more mandatory upfront work and other times there's a lot of hidden work that's sort of labeled optional. - Rob Ocel Moderation Our app is allowing arbitrary data from the community and isn't in any way curated. This means we could get some content we don't necessarily want such as expletives, rude or harmful messaging, or inappropriate images. What are strategies we could employ to counter this risk? Are there ways to automate these processes? How can we build these tools and processes in a way that scale with our community growth? Our business doesn't necessarily want to commit dedicates resources full time to this process long-term so how can we work around this problem? Basic Version An early version of the app might do some simple content filtering and moderation. We could have a list of words we don't want to be posted and use a CMS system to keep that list updated. We then can filter out words that are on the list from appearing on the site through algorithms to censor those words or just to change the display settings on the site to hide these words. We could also build some basic moderation tooling to allow admins to delete inappropriate posts and ban users from using the site. These features could be combined with a reporting system where community members can flag certain content as inappropriate. We could also create moderator roles where we give certain figures in the community to purge bad content or users from our system. This comes with the risk of having moderators who fail to do the role or go on a power trip and delete a bunch of content or ban a bunch of users because they can. The system will need some checks and balances and some data security features like shallow deletes where content isn't actually purged but filtered from appearing on the UI. Negative Side Effects of Moderation We have to be careful about our implementation of moderation as it could lead to a subpar community where there is snobbery or other forms of toxicity that we don't want. If we choose an AI or the wrong moderators, this could lead to a down turn in community sentiment. We maybe want to run experiments with tools like IBM Watson's sentiment analysis or other AIs to see what would happen. We also have to be wary of what happens when our moderation mode of choice stops operating at optimal capacity. Do we have a fall back plan that works? Is there any redundancy in our system to prevent any outages in moderation tooling? Positive Moderation We also want to encourage people for contributing positively. We could build quick and simple features of awarding a user a point in a commendation category where they prove to be an expert in certain areas. It encourages them to engage more and let's them become a community leader chosen by the community. Where does the moderation tooling live? We can build the moderation tooling in its own separate admin application. Alternatively, we could follow the YouTube model where everything lives inside the main user interface. Given our goal to have a single app for users and desire to leverage the community, it probably makes the most sense for our application to have the tooling live alongside the main application. > Let's say performance. Yes, there are things like code splitting, but how many additional bytes over the wire are you going to send down for, to in-service of an admin portal that maybe 99% of your users will never see? And again, there are ways to mitigate that, but you know, that's another thing to consider: do you really want to ship two completely orthogonal experiences in one bundle? That being said, we should absolutely evaluate how large this additional tooling is and how memory-costly is it going to be to send that to every user. Conclusion I want to thank my guests Rob Ocel, Morgan Worrell, and Chris Trzesniewski with This Dot for joining me on Build IT Better. It was an amazing conversation and knowledge share. This article would not be possible without their time and insight. Thank you....
Apr 8, 2021
Plugin Architecture for Angular Libraries using Dependency Injection
The plugin architecture is a well-known software design pattern used for its flexibility, extensibility, and isolation. We will cover how to create a plugin-based architecture in Angular using its Dependency Injection system....
Mar 31, 2021