Developer Insights
Join millions of viewers! Our engineers craft human-written articles solving real-world problems weekly. Enjoy fresh technical content and numerous interviews featuring modern web advancements with industry leaders and open-source authors.
Common Patterns and Nuances Using React Query
React Query is easy to use and can be tricky to master. Thankfully there are a few useful patterns to common problems to help develop better stateful apps....
Dec 19, 2022
5 mins
Angular vs React Comparing Route Prefetching
Angular vs React Comparing Route Prefetching At times during the development lifecycle, we need to perform specific strategies that accomplish a desired UX. A user may need to perform a task in the near future where the data is needed so we establish a browser cache for the necessary resources. Whether at the beginning of the app's initialization or during navigation, we can provide everything upfront or lazily as needed. A number of frameworks and libraries allow for pre-fetching strategies as part of its packaging and they perform those tasks fluidly or require a few handshakes to make it possible. We'll compare how this can be done in Angular and React as well as some others like Remix and Vue. Before we go too much further, let's understand the advantages of pre-fetching and when we should perform them. What is Prefetching? As mentioned briefly, data prefetching accomplishes two objectives: * data storage by caching in the browser * seemingly on-time retrieval by the user When a user performs navigation whether initializing a web app or navigating within the app, the app either loads all or a portion of data. However, this isn't without cost or impact. This data still requires network bandwidth for the transfer, processing time, and the cache. If a user decides to not use a portion of a web app but this data has been made available to them, performance is diminished. When is Prefetching Useful? While we know about the browser's limited caching resources and overall performance considerations for prefetching, the decision still needs to be made about whether or not to perform pre-fetching. A question to keep in mind is: "does enabling prefetch increase or decrease the utility of the app?" Determining the strategy to use will make an app sink under load times or swim with the right balance of load time and page rendering. Angular Prefetch with Route Resolver Angular has a relatively simple setup with its loading strategy. The resolver pattern binds data loading to a route where any navigation to the guarded route or its branches first loads the resolver and uses a snapshot of the route's data for use during the lifecycle of any components within that route. However this has limitations because the data isn't globally available to other routes. Take, for instance, a User service and route that had a resolve guard. In order to access a user's data, some pre-requisites need to be available first. First a basic example resolver takes this shape. *user-resolver.service.ts* ` And it called on the route guarded route *user-route.ts* ` Accessing the data in user now looks like this in the component where we look at the currently activated route for a hydrated data['user'] property: ` This approach to prefetching doesn't take into account Server-Side Rendering and is purely client side. Projects like Angular Universal make it possible to perform some controlled data flows and setup than the client-side fetching would allow. Considerations for Global State We can overcome ths issue of limited app-wide or global state with a couple techniques: 1. A data service layer that utilizes caching 2. Lifting state to parent routes within the route tree 3. Use state management libraries While each of these strategies has advantages over the other, most developers tend to consider libraries like NgRx and Akita for Angular before thinking about the performance and overall impact these mechanisms add to the application. Prefetching in React If you did a Google search for prefetching in React, you'd probably get a number of developer posts on either React's experimental feature or you'll find resources on running flavoured extensions of React like NextJS and Remix. This is to say, due to React's "choose your adventure" ecosystem, it doesn't have its own implementation readily available thus needing to create your own. As mentioned, you could choose a flavour that best suites your needs. We'll briefly discuss the similarities and differences between Angular and NextJS versions of prefetching in making an architectural decision. Client-side Prefetching A combination of react-router and useContext is a way to emulate what Angular does with its protected routes. An example comparable to the earlier resolver pattern looks like setting up a protected route: *protected-route.tsx* ` Applying the new "route guard": *app.tsx* ` Add CurrentUserContext to act as the activated route's data handler: *app.tsx* ` Then use the context in a child component: *login-button.tsx* ` When the user performs a click to "Log in", they be set with a user that's provided throughout the app. In this instance, we set it up globally because it recommended to have all providers as high up the component tree as possible. Considering Server-side Rendering (SSR) SSR is a great way to increase the performance of applications by making sure dynamic data is always up-to-date and hydrated. It makes the page interactive by rendering content, and with a bit a JavaScript, to make it dynamic. This impact is two-fold as it improves SEO and performance in page load times. Regardless of the applications, utilizing this mechanism, we know the outcome is the same. SSR is a great way to extend the capabilities of the client-fetch strategies addressed earlier as they leverage the same content, but just make rendering requests at a controlled server level. Ideally, one could load authorization, headers, localizations for languages, perform caching, and load data from a CMS. Angular Universal Angular Universal is an extension to a base Angular project by including an extra level of control. This involves adding the ability to perform server rendering capabilities to an Angular app via an express server extension. It shares similar context to NextJS's implementation of SSR although the pattern is a bit more verbose in a server.ts file generated with the following commands: ` ` Routes specified within the server.ts file can perform a number of server-related tasks standard to writing an express app. This also includes limitations like using browser API because server code doesn't run in the browser context. Therefore, window, document, navigator, and location is not available *directly*. Angular provides these as injectable. Lastly, Angular Universal can handle Statically-Generated routes as well. However, an argument can be made for the effectiveness of this in Angular given how heavy a framework it is compared to other, smaller applications that handle this more efficiently. NextJS NextJS is a great tool compared to bare React when determining the cost-effectiveness of setup and ease. While one could use this framework to justify a client-side fetching strategy, it's unnecessary if all the performant features aren't used like its version "prefetching". Before embarking on prefetching, consider that NextJS provides pre-rendering in two contexts: Static Generation and Server-side Rendering similarly to Angular Universal. While each one has a specific use, the most effective one for this concept is Server-side Rendering because most scalable, enterprise applications rely on fresh, dynamic data....
Dec 9, 2022
5 mins
Angular vs React Change Detection
As we begin a new project, we often encounter the question of which framework can best solve an immediate set of problems. Typically that decision comes down to understanding different languages, frameworks, and architectural patterns. With React constantly growing in popularity, it's imperative that those looking to refresh their understanding of certain tools, or learn a new library, be able to transpose concepts between tools towards a similar outcome. We'll be taking a look at how we can reap the benefits of better performance by comparing Angular and React Change Detection strategies. _The following concepts and examples assumes familiarity with Angular or React._ - What is Change Detection? - Angular Change Detection - React - React Hooks What is Change Detection? Change Detection (CD) is the mechanism used to track and update changes in an application's state. The changes happen under the hood but effectively align the UI with the state of the app. At its base, simple data structures are represented in the DOM and represent something to the user. By introducing different event types and enacting them with JavaScript, we can perform updates to these objects. A simple counter track that takes a click to increase a value by one is an example of modifying an app's state via an event. ` Angular Change Detection One of the features of the popular Angular framework is its Change Detection which, if not utilized effectively, can create performance hits on enterprise applications. Angular Change Detection works by using Zone.js and activating after every async action performed. CD traversal starts at the root component (usually App) and works its way down the component tree updating the DOM as needed. ` What makes Angular's CD beneficial is the ability to either omit components from re-rendering partially or entirely. What's happening under the hood is that browser events are registered into Zone.js - Angular's mechanism for orchestrating async events - which emits changes after initial template bindings are created. While Angular CD can be triggered manually, we can rely on it to trigger automatically. ` React React's CD is different in implementation than Angular primarily due to its use of Virtual DOM (VDOM). React CD is always updated whenever state updates occur whether in class-based components or function components. The render function of a class component or the return of function components is triggered with every state update. In every run of render, there is a "snapshot" of the VDOM. The new version of a snapshot is compared to the previous version, and patch-updated accordingly. ` React Hooks In the latest implementation of React with function components, leveraging hooks like useState and useEffect make function components stateful, and allow for control when the app state is updated. Conclusion Learning to switch between app libraries and frameworks comes with a learning curve for each one. However, understanding core concepts about them helps in not only determining which is most effective for the task at hand, but the history of these changes as they impact our long-term development goals. Angular and React have been big players in the field for many years. But as newer toolsets like Svelte, Vue, and Remix enter the arena, these concepts can be translated more fluidly....
Oct 10, 2022
3 mins
Using Notion as a CMS
Unlike most note-taking applications, Notion features a full suite of notation-like tools, from tools to track tasks to ones that help with journaling, all in one place. If you're an experienced user, you may have used some of their advanced concepts like tables as databases, custom templates, and table functions. As of May 13, 2021, Notion released a beta version of their API client, opening up another range of possibilities for the app. Users of the client can query databases, create pages, update blocks, perform searches, and much more. We'll look at how easy it is to get started with the client today. _Note: For this simple demonstration, we won't use authentication, but it's highly recommended no matter what type of app you decide to create._ Project Setup We have a few options for building a scalable blog site. For this stack, we'll be using NextJS because it's relatively lightweight compared to most frameworks, and has several readily available features for a standard React app. But Remix works just as well. In a folder of your choice, create the NextJS app with: ` or ` _Note: add --typescript at the end to generate a TypeScript project._ I'm using the TypeScript project for this demo. If you're unfamiliar with NextJS, I recommend their Getting Started Guide. In this new project folder, we have all the necessary things to run the app. Install the necessary dependencies: ` Create the Notion Database For this next step and the next, you'll need a Notion account to create databases, and an integration key. Now, create a table for your blog posts in Notion. This will become the database for referencing posts for the site. I'm making this generic developer blog database, but feel free to make your database specific to a target audience or subjects. Notion Setup and Integration Before using Notion's API to query any data, we need access via an integration key. Head over to the Notion's authorization guide and follow the instructions to create your key. I'm using the most basic setup for reading from my database. Continue with the integration key guide up to Step 2 which references how to grant the intergration key rights to the database. With the integration key and database ID handy, let's configure the app to use them. Querying the database In your favourite code editor, create an .env.local file with the following: ` _Note: it won't matter if you wrap your values in quotations._ NextJS comes with the ability to read local environment variables. It also ignores versions of this file in its .gitignore so we don't have to. _If publishing an app to production, it's recommended to use environment variables._ Next, create a src/api/client.ts file at the root of the project. This will contain an easily referenced version of our client for querying Notion. ` Follow that up with a src/api/query-database.ts file: ` Parse the Query Because the returned query object is so complex, we need to parse it. There are better ways to do this using more advanced techniques, but basic mapping will suffice. In a new src/utils/parse-properties file: ` Now we can leverage NextJS server rendering feature via getStaticProps to prefetch and render our Home page. In index.tsx: ` We should now see our post titles loaded on the Home page when we run npm run dev. Finishing Up With a few setup pieces, it's easy to setup a basic blog using Notion's API, but there are more possibilities and use cases for Notion as a CMS. Keep in mind that this may not be the best database to use in a production environment, but playing around with one of my favourite tools creates some new possibilies for non-Notion-tailored experiences. Full Code Example Here...
Apr 27, 2022
4 mins
Performing a Migration in AWS Amplify
Back-end migrations can be a tricky task if you're going in blind, and it may take a few attempts before you know the ins and outs of a specific technology being used. Those with experience in AWS will understand that sometimes things don't always go according to plan when performing even the most common tasks in Amplify, and migration of an app from one app ID to another can seem like a huge undertaking. In this guide, we'll look at how to: - Reference a new app - Create a new back-end environment for the migration - And verify our deployment works > This guide assumes you have an existing application created. Before Attempting a Migration Migration can be seen as a refactor of sorts, except it's the entire project that needs to move and work. In any refactoring effort, taking into account all the moving parts is key. But with Amplify, these parts are all tied to policies while creating the environment. What this means for Amplify is that with an existing app, we have the option to use already generated policies or perform a manual shifting of resources. With the first option, policies and references are already mapped for how the BE would rebuild. However, in option two, there may not be an easy transition of resources especially if the application is large and/or is being upgraded as part of the migration processes. In the case of an older application, it may be easier to manually migrate because the upgrade process might not take into account some older pattern. > We'll use the first option of a simpler migration by referencing the new app id. Initial Setup Amplify behaves similarly to git. To get started, first follow a git-like workflow by fetching the latest: ` > It's recommended to commit the latest stable code to your source control of choice in case the migration goes wrong. In the new AWS account, where this app will live, we need to create a space for it to live. Thankfully, Amplify docs give a step-by-step guide on configuring a new app space. Referencing the New AWS App At this point, if you've created a new app in a new account, then there should be a default staging environment. We won't use that one because we want at least one working, clean environment in case we need to start over (by deleting the environment). Clear old environments Take a look at the contents of team-provider-info.json and look for AmplifyAppId under any existing environments. Depending on the current environment selected, Amplify Actions will be performed against that environment at that app id. This isn't useful to use because generating a new develop environment will have: 1. A name conflict in this file 2. New environments created in the same app > If you used the wrong credentials creating the env, a new app under the old account will be created at the new app id. Generate an env at the new app id Typically we'd perform amplify env add to add an environment to an existing app. However, we need to reference the new app. So we'll initialize a new app instead: ` > Found in the Amplify Docs for commands amplify-cli here The Amplify-Service-Project-AppId can be found by: 1. Navigating to AWS Amplify 2. Selecting the app 3. Selecting App settings > General 4. Selecting the end part of the App ARN Because there won't be environments to read from team-provider-info.json, it won't prompt for using an existing environment. Follow the interactive prompts for your configuration needs. Verify the new environment and push To verify that everything went well, look again AmplifyAppId in team-provider-info.json under the new environment. This should match with the Amplify Console. Now we push: ` Verify Successful Deployment All's that's left now is to wait while Amplify recreates the policies for all your back-end parts. If it all went well, you should have no failures in the terminal, and see the deployment success in Amplify Console with references to your API, functions, etc. like: If you have a front-end, re-attach the source control of choice. Cleanup The final step after everything is working is to remove references to the old application. We did this partially by deleting old environments in team-provider-info.json. Now we have to delete the old app from the old account, and we're done!...
Jan 7, 2022
4 mins
Tips for Better Amplify Experience: Initial Setup Pitfalls
Learning about CI/CD can be a tricky task, especially if you're unfarmiliar with the technologies available, and how to use them. AWS, Amazon's cloud-based services, is one such tool that can help accomplish a lot of your deployment needs. However, it can be a steep learning curve to getting started. Whether it's a front-end application, or an app needing a back-end, AWS can simplify some of the Dev Ops-related tasks for you. This guide is a first of a series of helpful tips for making your deployments to AWS easier to manage. In this installment, we'll walk through: - AWS CLI vs Amplify CLI - Using AWS SSO for Amplify CLI _Note: This guide assummes you've already created an account to utilize AWS features._ AWS CLI vs Amplify CLI First, aws-cli is different from amplify-cli. Where aws-cli controls credentials for AWS services, the other can also modify access, but mainly controls the deployment similar to git's version control. Because both have some level of access control, which to use and why can be confusing questions. Access and Logging in via Amplify CLI The access type of the account (non-SSO or SSO) determines which way you login to perform amplify-cli commands. Using amplify configure, you could setup access key id, and secret access key. These credentials would be stored under a profile name (usually default). ` Then, when performing amplify pull, it asks for the type of access to use authentication: ` Normally, choosing the first option would get you going. Choosing profile wouldn't work in this scenario because it expects those access credentials. Profile here is not the same as the one stored at ~/.aws/credentials. These credentials are bound to an IAM user setup under the account used to access the AWS. (Verify this by going to IAM > Users). What happens when you need to switch between instances of AWS accounts that contain their own application? Eventually, using access keys becomes a hassle because you'd have to create a new IAM user for each instance, then store multiple profiles in your credentials document with unique profile names to distinguish them. An easier solution would be to use the account level access to AWS as the single access point for these app instances. Using AWS SSO for Amplify CLI One solution to this problem is to setup SSO for AWS account(s) then utilize the same login for every app instance that SSO account has access to. To do this, first follow steps here to configure a named profile to use AWS SSO. Continue onto the section "Using an AWS SSO enabled named profile" to login which should open a browser to finalize authentication via aws-cli. However, the AWS doc misses a crucial step before you can use the new profile. Notice how that profile was setup for aws-cli, and not amplify-cli. The newly created profile lives under aws config: ` Why is this a problem? Let's try to perform an amplify pull again. We are asked the same authentication question as before (assuming previous access timed out already). Choosing the first option again gives an error that access key and secret access key are missing. ` To connect the new profile, simply intsall aws-sso-util. Once installed, selecting the AWS profile option will now work for any app. Conclusion Some AWS resolutions aren't obvious, and it can be time-consuming finding the right information to help move development along. The tips presented here are subject to change due to amplify's ever-chaning ecosystem, and the many applications that utilize its core features. The next article will feature how to perform a migration in AWS using Amplify....
Dec 1, 2021
3 mins
Next.js: Adding Localization with Next-Intl
Next.js: Adding Localization with next-intl Adding locales to a project in NextJs is as easy as creating a few files, and installing the handy npm package next-intl. Using next-intl works right away with minimal setup and configuration, and makes adding different locales to a new or existing project a breeze. We'll step trough the basic setup of the project and necessary dependendies, the project structure, and a few cool things we can do with next-intl that make langauge integrations seemless. Install To start thigns off, we'll create a nextjs app using the following: ` Once you've created the app: ` You should see a generic starter page from cloning the NextJs learn-starter project. Next we need to add the translations dependency: ` Setup At this point, we would have already considered which langauges we want to support, and which language is our default. For this example, we're going to use English as the default, and Japanese as the next supported langauge. Configure NextJs Create the file next.config.js and add the following line: ` We add this to next.config.js because we want the framework to be aware of context changes within the app when we provide static props to our app. Register Locales In our project, we want to consider the best place for loading different translation files. Typically these extra files don't need to compiled with our source code so we can create a locales folder outside the main source files: ` In the locales folder, we can create en.json and ja.json respectively, making sure to match the name of the file to what we used in the config. Using next-intl The next few steps are a basic usage of next-intl. Add Languages First we need to add to our language files, so we know where to pull information from. Using the existing text generated from our initial script, we can add to out en.json file: ` And to the ja.json file: ` *NOTE: be sure to research what the correct translation are for he languages you use and test accordingly!* Provide Locales Our pages need context to pull locale information from. We provide that to a page via NextJs built-in function getStaticProps. This gives default prop values to a react component. Place it at the bottom of index.js. ` *NOTE: the previous step is crucial to making this work correctly since the name provided in the config need to match the file name.* Then in the pages/ folder again, create a file _app.js which we'll use to register providers for our app. Then add the following: ` What this did was take the default pageProps object and give it another default property messages. Component Use Now that our setup is complete, we can use our translation package like: ` Think of the sctructure of the JSON as the copy text you'd include directly in HTML. We need to access the section of copy for the page we're on, and we identify the piece with the Home key. Then, we access the inner copy like: ` Start up the app, and if it was setup correctly, you should see the "Welcome to Next.js!" Advanced Use Now that we've covered the basic use. Let's take a look at a cool pattern we can use. next-intl gives us the option of specifying how we want to style and break apart pieces of copy. The way they accomplish this is with custom tags, declared within the copy itself. To accomplish this, first we adjust the language files by wrapping the word "NextJs" in link tags. ` ` Then in the component, we express how we want the link tag to function when rendering. We access the specific tag by the custom name given in the JSON, and give it a function where children, like in React, takes the contents between the custom tags, and interpolates that, whoever we choose. In our case, we want to maintain the original link that was generated from the project starter. ` Locale Strategies NextJs' routing feature is powerful in the way it works with the basic setup we have thus far. Because we defined our locales in the config, we can run the app and navigate to the locale code to see it render in view. For example: navigating to localhost:3000/ja will dynamically render the right context via the provider we set up in _app.js. Read more about NextJs Locale Strategies to learn more about routing and locales for your app's needs. Conclusion Adding i18n to a project is simple. As we've seen, with just a few steps, we were able to add some basic copy translations to our app with minimal effort. Try the complete code example....
Jul 28, 2021
4 mins
Advanced NgRx: Building a Reusable Feature Store
Advanced NgRx: Building a Reusable Feature Store As an angular application grows in scale and complexity, so often is the need for state management to help simplify its many moving parts. What often occurs is an increase in the amount of boilerplate involved in managing many feature states, and stores. Increase in store size can often lead to repetitive patterns, much like in poor component design. However, if state is written well, an application can utilize a less common pattern- a reusable feature store- as we attempt to eliminate much of this boilerplate headache. The following proposes a pattern where we’ll create a pattern for properly consolidating several stores, gain consistency across similar features with a reusable store, and address any pitfalls in this pattern. When to use consolidating state management patterns Before we get too deep into consolidating, we should first stop, and assess, when and why we're attempting this task. Why consolidate in the first place? - Reduce repeating patterns in feature design. - Increased maintainability of similar features. - Quicker iterations. - A better shared abstracted layer that can be extended as needed for edge cases. - Similar or extensible UI or data stores. When should you consider consolidating? A hard to answer question, but one that's satisfied by having really good foresight, a roadmap of how an app's features will work, or a set of existing features that may need a few iterations to bring them closer in overall design. What this means for both approaches is that a feature can be initially designed similarly to another, or be made to function similar to another to make it _DRY-er_ (Don't Repeat Yourself) later on. A closer look at the store pattern Now that there's a direction and reason for our efforts, let's look at the pattern using a mock version of photo website - Unsplash - to build out a data store. Let's say we have several states that look like this: ` Fortunately for us, our photo assets follow a very similar pattern. This state is simple as it will contain photos in a simple state. However, we can squash these into one state like this: ` And with that simple bit of code, we've opened up the possibility to reuse a data store per photo type into a single store! For example, a website like Unsplash could use several strategies to fetch and display photos like filtering by photo type on navigation, or pre-fetching chunks of photo types in a resolver. Imagine if each photo type acted as an individual store? That would be a lot of stores to maintain! Building the new state and reducer As this new feature store is built, keep in mind that typings become tricky when you begin to use an indexed interface as a type. Typing pitfalls Typescript doesn't like when we add more properties onto indexed interfaces because it assumes that we'd only be adding properties that follow the initial type we assigned to the index property. In this case Photo[]. For example, this will work: ` But this won't, because PhotoType on selectedPhotoType doesn't overlap in types: ` To overcome this, we can use an Intersection Type like so: ` Defining the reusable part of state We want some amount of flexibility in our store, but we have to tell the new store what features we intend to keep similar in pattern. One way we could do this is by creating a dictionary of features. Building the initial state for the photo types could look like: ` And initial state for the reducer: ` Another win for reusable store pattern Maybe you noticed already, but what if each of the individual states used entities? We could help ourselves, and speed up our dev time some more with the adapter methods and selectors exposed per PhotoType. Our biggest win here comes from the fact that we can still use NgRx Entities even in these seemingly nested states of state. The above piece changes like so: ` And give the state slices an initial state: ` Tying it together with the reducer and selectors Now that we have the state accurately defined. We can access the select slices of our single store using the selectedPhotoType property: ` And for the selectors: ` Again, we can use the entity adapter and leverage entity methods and selectors. Full Code Example Here. Conclusion When working with state management stores in NgRx, it shouldn't be a mess of maintaining boilerplates and changes that affect several data sources with the same store shape. As developers, we want to think of future-proofing strategies that abstract enough, yet still help us understand exactly how the application works. By leveraging a reusable store strategy, we gain consistency with like features, a level of abstraction and sharability between like features, with the ability to extend for edge cases, and easier maintenance....
May 11, 2021
4 mins
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
10 mins
Tips for Better Time Management as a Software Engineer
Tips for Better Time Management as a Software Engineer In today's ever-growing software landscape of tools and experience to gain, we can find ourselves lost wanting to do more, yet feeling like we don't have enough hours in the day to accomplish everything we want. This problem is all too common in every level of industry, and as software engineers we can find ourselves racing to finish multiple things yet never actually reaching the finish line with anything. If by chance we do, we're often burnt out and ready for vacation (sometimes after a few days). Sadly, we all can't be Elon Musk, but we can begin to fix our habits and patterns to feel more like a genius. Why Is Time Management Important? As professionals in any fields, it's important that we execute on our work in a consistent way that helps us not only feel *productive*, but also feel like we're helping achieve business goals as well as personal growth goals. Taking an example straight from my own life, I found myself mentally exhausted trying to keep up with everything in my life - my job, personal projects, and my life goals. It seemed like I had so much going on, but my fatal flaw was the fact that keeping myself busy with so much didn't make me feel accomplished. Something had to change. Benefits of Proper Time Management Simply put, there are no downsides to better time management. The act of time management is a great key to our success in whatever we do. While it's as simple as just doing it, focus and consistency are needed to really be successful. Because we live in a world where the speed of business and technology is increasing, being decisive about priorities is even more important. Where we fail is when we try to make snap decisions especially for important tasks that require our full attention. Not only does it take focus and consistency to succeed, but when a person knows what they're doing for the week, day, or hour, they can better focus on tasks and feel better about whatever they're doing. There's a sense of clarity that comes as a result of having a single focus on one thing and executing on it, even if it's not to completion. Helpful Tips for Better Time Management Important Being a master of your time can be a difficult task at first, but with some grit and determination, paving the road to success can become easier. Say you need to meet a deadline for a project with a release in a few days. How can we make our lives easier in a short period of time? 1. Redefine Goals and Expectations The first step is to write down all you tasks including goals, milestones, or whatever you use to describe large bodies of work. This will paint a clear picture of what is and what is *not* a priority. Wins from doing this include: - framing your to-dos to better execute them - freeing your mind from trying to remember why you're doing something - strategizing how to best execute tasks *Pro tip: adding goals and activities you're already currently working on to this list helps make sure nothing is missed.* This doesn't have to be a complicated step with each goal or task being general. In the next section, we'll see how to be effective with this list. 2. Prioritize Goals and Actionable Tasks Now we have a list of things to accomplish and activities already invested in, but we haven't figured out what to perform first. The best way we can prioritize these items is to place value on them. Value can be added to tasks by determing how much of an impact one task can make over the other. We can even timebox them to further increase that value. Ask youself these questions to categorize tasks: 1. Is it urgent and important? 2. Is it important, but not as urgent? 3. Is it urgent, but not important? 4. Is it neither urgent nor important? Remember urgency often has a time limit, and importance can be specific to you or to a group of persons. A couple of examples look like this: 1. Release candidate to deploy to production by 3/1/2021. Urgent because there's a due date, and important because it affects the team and/or business. 2. Technical task to unblock a portion of work. Doesn't have a time limit, but could help unblock yourself or another developer. 3. Make a Plan and Stick to It Lastly, and this may be the hardest part about time management: consistency is another one of those building blocks to success and it's absolutely critical that all of the effort so far does not crash down on us. This one really comes down to knowing how best you work. Whether it's waking up at 4:30 am to get your mind ready for the day or working out to keep your body active, figure out your motivation for the work being done and put it into your schedule. What you gain from doing this is: - a clear visualization of what's being worked on for the day or week - what's up next on your agenda - *when you'll have your breaks to recharge and finish strong* A note on breaks: developers write code, check processes, do code reviews, plan solutions to unique problems, suggest and articulate solutions, and the list goes on. Without scheduled breaks, we'd be on the fast track to burn out before the day's out. Make a plan solid by strategizing about the plan and how you'll *stick to it*. It makes a world of difference to set your work space away from your bedroom, or to work at the office or a coffee shop. Prepare healthy meals ahead of time so you're not skipping meals or eating junk. Workout during the week because your body is a temple, and the mind needs the body like the body needs a fully functioning mind. Tools to Help Structure Your Time As stated before, write things down and block out your time, so you know what you can and can't commit to. Here are a few tools that I use to get me through the day feeling well-accomplished: iCal - makes it easy to import multiple calendars, from one or more email addresses, into a single calendar view. Google Calendar - you won't get the same importing features as iCal, but their interface makes it easy to add shared calendars. If you can find a 3rd-party mail client that offers the same flexibility as iCal, I'd recommend that for the single calendar view. Notion - Notion has changed the way I operate entirely. You can use the free version personally and for work. It just requires that you use one email address per workspace. With Notion, you can: - Take general notes - Keep a work log - Generate to a table of tasks - Set reminders for tasks - Sort tasks into views - Use user-built templates. Some you can buy while others provide instructions on how to make them your own. If Notion isn't the right fit for you, Evernote is another really great tool for assembling thoughts into books, articles, and notes. It also features templates more than Notion does. Conclusion In the earlier example of a deadline for a release candidate, it may feel like there's no time left before that deadline rolls around. That sinking feeling like you're running out of time is the reason you should manage your expectations, priorities, and time. Only good things can come from taking back your time and focusing it. At the end of the day, you can look back and feel a sense of freedom. Be good to future you!...
Mar 8, 2021
6 mins
Introduction to Redux Pattern
Introduction to Redux Pattern In this overview of the Redux Pattern, we'll dig into the basics and answer these pressing questions: - *What is the Redux?* - *Why do we use the Redux?* - *When do we use the Redux?* Redux patterns in applications created in React or Angular are very handy tools in helping define state and managing active and passive events. What is the Redux Pattern? > Redux is a pattern and library for managing and updating application state, using events called "actions". - Redux Documentation Not only is redux great for defining events, it also guides the flow of events through preditable event tracking. What Redux Pattern is not Redux and Redux patterns are not to be confused with Flux patterns or Flux architecture. The main difference between these two patterns is the "single source of truth" concept. Stores are our single sources of truth containing the state of our application. In Flux, the store can be split and defined in multiple locations throught the application. Redux as a single source of truth means that we can better maintain and improve our applications by merging state and events into a single location. This single location feeding the application is one of the key considerations developing for the architecture and scalability of an application. Why do we use the Redux Pattern? > ...Redux makes it easier to understand when, where, why, and how the state in your application is being updated, and how your application logic will behave when those changes occur. - Redux Documentation While Redux's use is simple for managing a "global" or "single source" level of state, there are some other impacting benefits: Predictability of Events. When we know what event will happen next if we click a button or link, we take away all assumptions about events triggering other events. Better Debugging from Event Tracing. Personally, event tracing is one of the huge benefits I like about state management because defects in events can be pinpointed accurately. If state wasn't updated correctly, we can make better logical assumptions. Complex State Change State is the one thing we can rely on and sometimes this state can receive asynchronous updates from different events. Redux makes these udpates easier to manage. When do we use the Redux Pattern? Ideally, Redux should be used for parts of an application that share state. Here are a few other considerations when deciding to use the Redux pattern. Frequency of State Changes State can be small or large, simple or complex, but in every case where events are performed, state will always be updated. Application Scalability First, we need to predict how an application will grow in size from the number of features. As an application scales from a simple set of functions to an enterprise-level experience, duplicated code and events decrease performance. Additionally, a Single Page Application (SPA) benfits greatly from Redux. For example, event-based routing behaves differently from a "regular" website since we conditionally generate new pages. As the SPA increases in features or pages, so does its need for state management. Complexity of State Changes and Logic Sometimes application state complexity increases as the application scales. Technical debt takes on a different form when the state isn't properly managed. *Red, Green, Refactor* is a simple, effective strategy to help minimize state technical debt - debt casue from a lack of code hygiene. In *Red, Green, Refactor* we identify what needs to change, determine how we make the change, then execute the change. In the case for state, we can merge similar portions of state together or split apart state by feature or function, making it easier to access parts of state. Likewise, any logic that relies on combined or nested state should be updated as you make those changes. How to Start Using Redux Today While this is an introduction to using Redux, it's helpful to note where we can start to add it in our projects. File Structure First, we defined a store location. We can choose to have this live on the same directory level as our other components and services: ` React Next, we can utilize state management. For vanilla JavaScript apps, we can use Redux as is, but there is special version of it created for React applications called React-Redux. The main difference here is the React integration: ` Angular Similarly for the popular Angular framework, we have NgRx, a version of Redux created specifically for Angular. ` You can choose your own adventure with state management. Choose wisely! Closing Thoughts Talking about the glories of Redux comes with it's cons as well. Keep in mind that using Redux also means defining a state that can become overly complex and require more overhead for Red-Green Refactoring. The benefits far outway this cost, however. The key things to remember about Redux is that it's meant to define a predictable set of events, manage and share application state in a *single source of truth*, and should be used when a project becomes large and complex....
Jan 11, 2021
4 mins
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.