• Skip to main content
  • Skip to footer

InRhythm

Your partners in accelerated digital transformation

  • Who We Are
  • Our Work
  • Practices & Products
  • Learning & Growth
  • Culture & Careers
  • Blog
  • Contact Us

Software Engineering

May 08 2023

InRhythm Presents The Propel Spring Quarterly Summit

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

New York, NY – InRhythm recently concluded its very first Propel Spring Quarterly Summit; a premiere event consisting of six individual coding workshops aimed to support the learning and growth of engineering teams around the world. 

Over the last three weeks, our consulting practices have led a series of interactive experiences that delved into the latest technology trends and tools, designed to propel professionals forward into their careers. 

The workshops are free to access as a unique part of InRhythm’s mission to build a forward-thinking thought leadership annex:

  • InRhythm Propel Spring Quarterly Summit / SDET Workshop / March 17th 2023
  • InRhythm Propel Spring Quarterly Summit / Web Workshop / March 24th 2023
  • InRhythm Propel Spring Quarterly Summit / DevOps Workshop / March 29th 2023
  • InRhythm Propel Spring Quarterly Summit / Android Workshop / April 11th 2023
  • InRhythm Propel Spring Quarterly Summit / Cloud Native Workshop / April 21st 2023
Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

SDET Workshop (03/17/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

This workshop worked as an introduction to writing and running tests using Microsoft Playwright. Our SDET Practice went over Playwright’s extensive feature set before diving more in-depth with its API.  

For the workshop, the team went over setup and installation of the tool, as well as wrote a series of comprehensive tests against a test application. Once tests were run, the team afforded participants the opportunity to go over some of Playwright’s advanced features, such as its powerful debugger and enhanced reporting. 

To close out the workshop, SDET Practice Leadership compared Playwright’s features to some of its competitors, went over its pros and cons, and discussed why they believed it to be a paramount tool to consider for automated testing solutions.

Web Workshop (03/24/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

Our Web Practice focused their workshop on their top three, intertwining technologies for development cycles. 

With many modern web applications sharing many of the responsibilities that a middle layer/presentation and service layer/backend provide to the frontend layer, the project was kicked off by organizing the elements with a mono-repository.  

Once the application moved into its build phase, it was time to accelerate the architecture to the next level using NextJS. 

Web Practice Leadership wrapped their project, with an intuitive overview of web bundling and the variety of methods utilized – in order to best adapt to each individual build.

DevOps Workshop (03/29/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

In this workshop, the DevOps Practice demonstrated tools for provisioning infrastructure as well as how to construct a self-servicing platform for provisioning resources. With these new developments in the industry, bridging the gaps between development and ops by allowing developers to self-manage cloud infrastructure to satisfy their needs will be a paramount skill to adopt. Our DevOps practitioners discussed the pros and cons of a number of tools for provisioning infrastructure and identified which tools can best fit a business’ needs.

For the hands-on interactive session, the team ran through the necessary steps to get started with Pulumi and provision a resource onto AWS, along with demonstrating Terraform in order to get a feel for the difference between the two popular infrastructure-as-code tools. After that, we set up some plugins to enhance the development experience with IaC.  

Self-servicing platforms are the best way to allow for engineers to provision resources and infrastructure for their needs en-masse. With Backstage, the team was able to demonstrate a platform for engineers to come to and fulfill their needs whether it be creating a new microservice, a new repository, or even provisioning a new k8s cluster. Furthermore, the provisioning of these resources were proven to standardize and bring uniformity to ensure that best practices are enforced. Long gone are the days of submitting a ticket to create a new instance to deploy an application, with a wait time of a few hours or even a few days.  Self-servicing tools are the future of bringing operations into the hands of developers and bridging the gap between development and operations.

Finally, DevOps Practice Leadership set up a self-servicing platform and hooked it into the aforementioned IaC repository to allow for the provisioning of resources from a GUI. 

Managing infrastructure can quickly become tedious as the number of resources being used on a cloud provider continue to grow.  With infrastructure-as-code, not only DevOps engineers, but developers can now lay out infrastructure using code. Since it’s managed via code, version-controlling/source-code management tools are also available, making management of infrastructure significantly easier.

iOS Workshop (03/28/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

Our iOS Practice did a full overview of Swift Async/Await for iOS application development

Async/Await is a programming feature that simplifies asynchronous operations by allowing software engineers to write asynchronous code in a synchronous manner. It also makes code easy to read/write, improves performance/responsiveness, and reduces the likelihood of errors.

In short, Async/Await is a powerful modern feature in every avenue from development speed and simplified code to and application performance.

Android Workshop (04/11/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

Our Android Practice performed a comprehensive demonstration of the practical integration of Kotlin Multi-Platform Mobile (KMM) for cross-platform development. 

Kotlin Multi-Platform Mobile is an exciting, growing new technology that allows sharing core code between Android, iOS, and Web.  

In this workshop, Android Practice Leadership explored what KMM was, how to setup a project for KMM, a walkthrough implementing a core module to a few APIs (network layer, data models, parsers, and business logic), and then consumed this core library in an Android (Jetpack Compose) and iOS (SwiftUI) application.

Cloud Native Application Development Workshop (04/21/23)

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

In this workshop our Cloud Native Application Development Practice introduced the participants to gRPC, which is Google’s take on Remote Procedural Calls. Our Practice Leadership presented a brief history of gRPC and Protocol Buffers. Google and other companies use gRPC to serialize data to binary which results in smaller data packets. Throughout the presentation our team went over some of the pros and cons of using gRPC for individual API calls.

In our hands-on workshop portion participants created a simple application to manage users and notes powered by Java, gRPC, and Postgres. The grand finale featured a full-circle moment as we worked together to create a series of CRUD APIs in Java using gRPC to send/receive data packets, translate those into objects, and store them in a database.

About InRhythm

InRhythm is a leading modern product consultancy and digital innovation firm with a mission to make a dent in the digital economy. Founded in 2002, InRhythm is currently engaged by Fortune 50 enterprises and scale-ups to bring their next generation of modern digital products and platforms to market. InRhythm has helped hundreds of teams launch mission-critical products that have created a positive impact worth billions of dollars. The projects we work on literally change the world.

InRhythm’s unique capabilities of Product Innovation and Platform Modernization services are the most sought-after. The InRhythm team of A+ thought leaders don’t just “get a job,” they join the company to do what they love. InRhythm has a “who’s who” clients list and has barely scratched the surface in terms of providing those clients the digital solutions they need to compete. From greenfield to tier-one builds, our clients look to us to deliver their mission-critical projects in the fields of product strategy, design, cloud native applications, as well as mobile and web development. 

Written by Kaela Coppinger · Categorized: Culture, DevOps, Employee Engagement, Events, InRhythm News, InRhythmU, Java Engineering, Learning and Development, Product Development, Software Engineering, Web Engineering · Tagged: Android, best practices, Cloud Native Application Development, devops, INRHYTHMU, ios, JavaScript, learning and growth, Mobile Development, Press Release 2023, Propel, Propel Workshop, SDET, software engineering, Spring Quarterly Propel Summit, Web

Apr 20 2023

Closures Vs. Combine Vs. Async Await

Based on a Lightning Talk by: Joshua Buchanan, Lead iOS Engineer @ InRhythm on March 28th, 2023 as part of the Propel Spring Quarterly Summit 2023

Author: Mike Adams, Senior Technical Writer @ InRhythm

Introduction

This image has an empty alt attribute; its file name is IR-Spring-Summit-ZOOM-Bg_iOS-1024x576.jpg
Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

There are three methods of asynchronous coding in Swift: Closures (i.e. completion handlers), Combine, and Async/Await. 

Closures are a fundamental feature of Swift that allow developers to define self-contained blocks of functionality, while Combine provides a modern way to handle asynchronous events and data streams. Async/Await is a new feature that makes it easier to write asynchronous code that looks and feels like synchronous code, improving the readability and maintainability of Swift code.

  • Closures – Introduced in Swift 2.0, WWDC 2015
  • Combine – iOS 13 and macOS Catalina in 2019
  • Async/Await – Swift 5.5 WWDC 2021

Asynchronous Coding Methods

Closures

In Swift programming, closures are a powerful and versatile feature that allow you to capture and store functionality for later use. A closure is a self-contained block of code that you can pass around and execute at a later time, similar to a function or method.

A common use case for closures is handling asynchronous operations, such as network requests or animations. Defining a closure that executes when the operation completes helps you to keep your code organized and avoid callback functions.

You can use closures in Swift in different ways:

  • As a function argument: Pass the closure as a function argument to define a custom behavior tailored to a specific use case.
  • As a function return value: As the return value of a function, you can create functions that generate other functions.
  • As a variable: You can assign a closure to a variable for later use.

Closures can capture and retain references to values outside of their own scope which allows you to define closures that can access and modify variables defined outside of their own function or method. 

Combine

Combine is a powerful framework that allows developers to handle asynchronous events and data streams in a more intuitive and functional way. The Combine framework provides a declarative way to define and manipulate data streams using a set of operators that can transform, filter, and combine data in various ways.

Key use cases for the Combine framework include:

  1. Handling asynchronous events: Combine allows developers to handle asynchronous events, such as network requests or user input, in a more elegant and concise way than traditional callback-based APIs
  2. Managing data streams: Combine provides a unified way to manage data streams from various sources, such as user input, network requests, and local storage
  3. Composing reactive UI: Combine can be used to create reactive UI, where the UI updates automatically in response to changes in the underlying data
  4. Testing: Combine’s declarative syntax makes it easy to write unit tests for asynchronous code

The key building blocks of Combine are publishers and subscribers. Publishers are objects that emit a stream of values over time, while subscribers consume these values and perform some action in response. Publishers can be transformed, combined, and filtered using various operators to create complex data pipelines.

In summary, the Combine framework provides a powerful way to handle asynchronous events and data streams in Swift programming.

Async/Await

Async/Await provides a more intuitive and concise way to write asynchronous code. With Async/Await, developers can write asynchronous code that looks and feels like synchronous code, which makes it easier to read, write, and maintain.

Previously, developers used callbacks or closures to handle the results of asynchronous operations which often lead to complex and difficult-to-read code, as well as potential issues with callback hell and race conditions.

With Async/Await, developers can use familiar keywords like Await and Async to write asynchronous code, which allows them to pause the execution of a function until a result is available, without blocking the main thread. This makes it easier to write code that is both asynchronous and easy to understand.

For example, this code uses Async/Await to perform a network request:

func fetchUser() async throws -> User {
    let url = URL(string: "https://example.com/user")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

In the example, fetchUser() function is marked as Async, indicating that it is an asynchronous function. Inside the function, the await keyword is used to wait for the result of the network request, without blocking the main thread. The result is then returned as a User object.

Overall, Async/Await is a powerful new feature that makes it easier to write asynchronous code in Swift, while also improving readability and maintainability.

Comparison

Features

Note that while Closures and Combine are both used for handling asynchronous operations, they operate at different levels of abstraction. Closures are used for defining code blocks with captured values, whereas Combine is a reactive programming framework that provides a unified way to manage asynchronous data streams. Async/Await, on the other hand, is a language-level feature that simplifies the process of writing asynchronous code by allowing developers to write asynchronous code that looks and feels like synchronous code.

Feature/
Item
ClosuresCombineAsync/Await
IntroductionIntroduced in Swift 2.0 (2015)Introduced in iOS 13 and macOS CatalinaIntroduced in Swift 5.5 (2021)
PurposeDefine code blocks with captured valuesReactive programming frameworkSimplify asynchronous programming
Syntax{ (parameters) -> ReturnType in }Publisher, Subscriber,operatorasync, await
BenefitsSimplify code, increase readability,“it’s the way we’ve always done it”Manage asynchronous data streams. Pub/Sub works without much effort. Once subscribed, the “watcher” always sees the message.Very simple to code.Write asynchronous code that looks synchronous.Powerful parallelization.Less complex code.Better device utilization (additional CPU cores, etc.).More similar to other modern languages.
ShortcomingsEasy to miss “closing a loop.”Difficult to scaleDifficult to debugApple’s first try at an async coding paradigm.The developer is responsible for coding the publishers / subscribers and ensuring that the messages are published.Difficult to use in conjunction with Closures and Async/Await.For Swift Concurrency feature completeness, the minimum deployment target is iOS 15+.Though supported from iOS13+, APIs were  unavailable until iOS15.Not foolproof.Apple’s direction.
Used forEvent handlers, completion blocksAsynchronous data handling, UI bindingNetwork requests, file I/O, async operations
ConcurrencyCan run on any thread, but can cause race conditionsConcurrent data handlingNon-blocking, can run concurrently without blocking the main thread
Error handlingUses try, catch, throwUses sink, catch, replaceErrorUses try, catch, async let, throws
CompatibilityAvailable in all versions of SwiftAvailable in iOS 13+ and macOS Catalina+Available in Swift 5.5+

Side-By-Side Code Function Definition

ClosureCombineAsync/Await


The Closure example code is fairly complex and a developer would need to examine the entire code block to be certain of its operation.

In the Combine block, the code is slightly less complex. The addition of .map, .decode, and .mapError help make it more understandable.

In the Async/Await code block, not only is there less code, it is also easier to understand what the code does: Set the path, create the request, make the call, and send the data back.

The code is still doing all of the “heavy lifting” for asynchronous coding, but it doesn’t LOOK as though it is doing the heavy lifting.

Side-By-Side Function Usage

ClosureCombineAsync/Await

The comparison of the three approaches really becomes clear when you look at the synchronizing calls inside of the same function.

As you can see, the result of the first call (i.e. getting a list of food by name) must come back to complete the second call (i.e. getting a list of foods that have the same “category” as the initial result).

Managing the response from the initial call is rather difficult, especially if we need to obtain sensible information about an error when something does go wrong. That difficulty only increases when we become reliant not only on a successful response, but also rely on the data as a result of that second response to power the second request.

Resources

  • Combine
    • Apple Combine:  https://developer.apple.com/documentation/combine
    • Getting Started with Combine: https://www.vadimbulavin.com/swift-combine-framework-tutorial-getting-started/
    • Is Combine Dead? https://remotion.com/blog/is-swift-combine-dead
    • Lightning Talk: Swift Combine https://youtu.be/6AB_3oFWvBg
  • Async Await
    • “Getting Started with Swift Concurrency” https://developer.apple.com/news/?id=o140tv24
    • “Async Await in Swift explained with code examples” https://www.avanderlee.com/swift/async-await/

Written by Mike Adams · Categorized: Code Lounge, InRhythmU, Learning and Development, Software Engineering · Tagged: Async/Await, Closures, Combine, INRHYTHMU, learning and growth, software engineering, Swift

Apr 12 2023

Structured Concurrency In Swift

Based on a Lightning Talk by: Joshua Buchanan, Lead iOS Engineer @ InRhythm on March 28th, 2023 as part of the Propel Spring Quarterly Summit 2023

Author: Mike Adams, Senior Technical Writer @ InRhythm

Swift Concurrency

Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

Concurrency is a task-based system that allows developers to take full advantage of the “await” portion of the Async/Await keywords to perform concurrent task execution. An Async/Await task waits until its process finishes before continuing.

Async/Await lets you take advantage of parallelization to make full use of all the available CPU cores to give your users the best user experience. 

Swift Concurrency includes, Async/Await, Tasks, and Task Groups. As you read “Async/Await,” assume that it means the entirety of Swift Concurrency and not simply, Async/Await.

Here are the keywords and concepts we’ll use in discussing Structured Concurrency:

  • Task – That portion of the concurrency framework that creates the concurrent environment. It can throw errors and return values
  • Child Task – A task generated and managed by a Parent Task.The Parent is responsible for task execution
  • Cancellation – In Swift, you can cancel or stop any task from completing. Unlike Combine, structured concurrency does not require a strong reference to emit values from the publisher (i.e., the Task) and continue to run even if you remove references to the publisher. If you don’t want the task to run, you must either cancel or stop it
  • Priorities – Structured Concurrency’s Task Priorities are very similar to Apple’s Quality of Service system. Task Priorities include:
    • High
    • Background
    • Low
    • Medium
    • userInitiated
    • Utility

When using Structured Concurrency in your code, remember that while priority setting in your code tells the system which tasks are most important, those priorities are only a suggestion, not a mandate. 

Async/Await

Async/Await provides the Structured Concurrency that removes the necessity of manually propagating errors and managing cancellation, as well as any other types of concurrency issues (e.g., race conditions). It makes program logic simpler to follow as the methods execute linearly rather than with the back and forth required when using completion handlers. 

Structured concurrency also improves performance and allows for cleaner, more readable code with more precise error handling. In structured concurrency, long-running tasks are self-managing in regard to resources, error propagation, or any concurrency issues. 

Async/Await was first popularized in 2012 via the C# programming language. Between 2012 and 2020, other languages began adopting Async/Await, including but not limited to:

  • Python / Typescript in 2015
  • Kotlin in 2018
  • Rust in 2019
  • C++ in 2020
  • Swift in 2021

Tasks

Although Tasks appear very basic, behind the scenes there is a great deal happening. 

The Task keyword tells the compiler that the code inside the brackets must run in its own area using different rules than the rest of the application. This is the beginning of writing concurrent code in Swift.

In Swift, Tasks check if they were cancelled at appropriate times during execution. If cancelled, the Task begins whatever processing is necessary to cease execution and then responds to the cancellation. Depending on the code, the response could be returning partially finished work, returning an empty collection (or nil), or throwing a cancellation error.

Task Example

The load function shown below displays all the parts of a concurrent function coded as a task.

Child Tasks

Child Tasks are bound to a Parent Task and inherit the Parent Task’s Priority. Parent Tasks can have multiple Child Tasks and a Child Task can be a Parent Task to other Child Tasks.

While Parent Tasks can cancel a Child Task, a Child Task can not cancel their Parent task. Child Tasks begin whatever process is necessary for them to halt once their Parent Task is cancelled. All Child Tasks must finish before the Parent Task can be completed.

Cancellations

Unlike Combine, Tasks in Structure Concurrency will continue to run even when there are no Subscribers. Tasks run until they are completed or until you cancel them in code or programmatically. Cancellations are not determined by strong reference.

Tasks “know” whether they’ve been canceled and you can explicitly cancel a Task. You can also use the Task.checkCancellation() call to check if a Task was cancelled.

There are a number ways to programmatically cancel a Task including:

  • Navigating away from a view where the task was triggered
  • Canceling that Task’s Parent Task to cancel all of its Child Tasks
  • When another Child Task of the same Parent throws an Error

Async Let

Async Let is a variation of Async/Await that differs from the Await version, in that it will immediately launch a known number of Tasks in parallel and manage them in a slightly different manner than Async/Await. Where an Async/Await call suspends the Parent Task during Child Task execution, the Async Let call allows the Parent Task to continue running normally. 

You would use Async Let when you’re certain that the Async code can run independently. Note that unlike a regular Async/Await Call, you cannot directly cancel Async Let calls.

A further difference is that you can only use Async Let in local declarations, not at the top level.

Use Async Let when you need the results from the call later in your application, not immediately. For example, you could use multiple Async Let calls to load gallery images without blocking the main thread, thereby allowing the user to continue using the application’s GUI while the images load. 

Use Async Let when:

  • You have enough detail to request the information you need prior to making the call 
  • The calls do not depend on another call’s results 
  • You are returning different kinds of data
  • The order in which the app returns results is unimportant

Task Groups

Task Groups allow you to combine an unknown number of parallel Child Task calls that return the same Type of data into a batch, and then wait until the last Child Task finishes before completing the call. This is most useful when the results are a consistent type, such as when combining API responses into a single object. Task Groups only complete after all Child Tasks in the Task Group are complete.

It is important to never mutate the Task Group using code from outside the Task where the Task Group was created. Doing so interleaves data obtained by the Task Group with the data from outside the Task Group which leaves the results inconsistent. 

Using Try Await allows you to handle any potential thrown errors in the grouped call using additional code.

For example, let’s say you have a function that returns a string value and you need to call the function n times. Each time that function returns, you want to append the resultant string to an array of strings:  

Once all the Tasks in the Task Group are complete, you want the Task Group to return a String array. The “of” type for the Task Group is String because the result of the parallel task is a String and the returning type is an array of Strings

Coding UIImages in Task Groups will appear more familiar. For example, let’s say that you have a list of indeterminate size composed of URLs that point to specific images, and a function that downloads an image from each of those URLs and then adds it to an image array returned from the Task Group.

In this case, the “of” type for your Task Group is UIImage, and because the parallel function inside the task is downloading UIImage data, and the returning type for the Task Group is an array of UIImages.

Task Group Example

The Of type for this example Task Group scenario is UIImage and because the parallel function inside the task is downloading UIImage data, the “returning” type of the task group is an array of UIImages.

There are two things happening in this example code. The first is the execution of the parallel downloading task for the individual images located at each URL. The second takes the results from the previous task (the UIIMage) and combines them into a single array of images.

Resources

  • Apple Developer: Getting Started with Swift Concurrency
  • InRhythm Swift Lightning Talk (Deck): Structured Concurrency in Swift
  • Linkedin Video: InRhythm Propel Workshop (Video) 
  • GitHub Repo: Async Await Propel Workshop GitHub Repo 
  • Blog, Antoine van der Lee: Async await in Swift explained with code examples

Written by Mike Adams · Categorized: Code Lounge, InRhythmU, Learning and Development, Product Development, Software Engineering · Tagged: Async Await, best practices, INRHYTHMU, ios, iOS Workshop, learning and growth, Mobile App Development, Mobile Development, Mobile Engineering, Propel Spring Quarterly Summit 2023, software engineering, SwiftUI, ux

Apr 12 2023

What You Can Expect From React 18

Based on a Lightning Talk by: Godfrey Best, Senior Software Engineer @ InRhythm on March 29th, 2023 as part of the Propel Spring Quarterly Summit 2023

Author: Paris Leach, Senior Software Engineer @ InRhythm

Overview

Recently we had an exciting Lightning Talk led by Godfrey Best, who walked us through the changes introduced by React 18.

React 18 ushers in structural changes to the library that will help developers create more performant applications. Among these changes are the highly anticipated concept of concurrent rendering, which gives the developer fine-grain control over how their components render. We will discuss these changes at a (mostly) high level, in the hopes that you walk away from this article with a solid understanding of the changes that this version introduces.

What Is React?

Before we dive into React 18, we’re going to take a brief look at what React is for those who are not familiar. Feel free to skip this section if you already have a good grasp of React.

React is, succinctly, a JavaScript library for building user interfaces. It was created at Meta in 2011 (many of you will remember that it was called Facebook, at the time) and open sourced in 2013. It swiftly became the most popular frontend library/framework.

It provides a declarative, component-based API so that you don’t need to worry about page changes on every update. You pass data to the components, and React determines how they should render. React renders a Virtual DOM (not to be confused with the Shadow DOM), listens for changes in component data, and by default re-renders only those components whose data has changed.

React data is generally passed unilaterally (from parent to child, and not vice-versa), and is usually either a component property (data that is passed from a parent to a child) or a part of component state (internal data that belongs to a specific component and can only be directly changed by that same component).

For most of React’s lifespan, it has relied on synchronous rendering, which means that once an application has begun rendering, the user must wait for the render to be completed before they can interact with the components (these render methods and their callbacks are pushed to JavaScript’s single-threaded call stack).

About Version 18

React 18 was released on March 29th, 2022, and among other changes, it adds features that allow the developer to switch from synchronous rendering to asynchronous rendering, or as React has coined it, concurrent features. This allows React to render and re-render its components outside of the call stack, unblocking the user’s opportunity to interact while the render process occurs. In addition, the developer can establish priority for certain renders, giving them more granular control over their applications. React concurrent features:

  • are opt-in (when upgrading to React 18, components are not automatically set to render concurrently)
  • are backwards compatible
  • employ reusable state
  • are interruptible

How Can We Use These New Features?

There are a number of new hooks introduced in React 18, most which are expected to be implemented by framework authors, such as Next.js, Hydrogen and Remix. A few of the new hooks made available are:

  • useId
    • Used for generating unique ids on both the client and server to prevent hydration mismatches
  • useInsertionEffect
    • Allows for CSS and JavaScript libraries to address performance issues while they are injecting styles during rendering
  • useSyncExternalStore
    • Allows external stores to support concurrent reads by forcing updates to the stores to be synchronous (useful for state management libraries like Redux)
  • useTransition
    • Allows the library’s authors to mark certain actions as low priority (such as switching between pages) *We’ll be taking a closer look at this hook later in the article

React 18 also splits the rendering API (ReactDOM) into 2 parts:

  • ReactDOM/client
  • ReactDOM/server

What Features Can We Use Today?

Not all of these features require time for frameworks (or us) to implement; some of them can be used today, out-of-box:

Automatic Batching

Before React 18, if you had multiple state updates that were called inside of a React event handler function, they would be batched automatically, and the component would only be re-rendered once. This formerly only applied to React state handlers, and not, for example, setTimeouts or native event handlers. React 18 changes this by automatically batching all state updates inside any function by default. This reduces unnecessary re-renders.

useDeferredValue()

This tells React to only render a value when it’s convenient, similar to debounce, though this feature has superior performance to the former. Unlike debounce, there is no fixed time delay before this fires; additionally, this can be interrupted and does not block user input.

useTransition()

This hook is similar to useDeferredValue(), except that it tells React to render a state update when it’s convenient. It can also show if a transition is pending, which is a useful status to have awareness of within your application.

Suspense For Data Fetching

This feature actually existed in previous versions of React, but it was only used for code splitting. In React 18, suspense is available for data fetching, allowing for a declarative fallback ui in scenarios when the application is waiting on an asynchronous action to complete.

Conclusion

React 18 brings some long awaited performance boons and quality-of-life improvements. The move away from synchronous to concurrent rendering is something React has been working on since 2017 and now developers can finally avail themselves of its benefits. React also has some future developments in the pipeline:

  • Rendering components offscreen, allowing a developer to prepare ui to render in advance of the ui being on the page
  • Improvements around suspense for data fetching, such as more exposed primitives to make it easier to access your data, as well as the ability to use the feature without a framework having to implement it
  • Server components (an experimental but upcoming feature), allowing developers to build apps spanning both the client and the server

Written by Kaela Coppinger · Categorized: Cloud Engineering, Java Engineering, Product Development, Software Engineering, Web Engineering · Tagged: best practices, INRHYTHMU, learning and growth, React, React 18, software, software engineering, Web, Web Development, web engineering

Apr 04 2023

Playwright’s Reporting And Parallelization Features

Based on a Lightning Talk by: Oleksii Lavrenin, Lead SDET @ InRhythm on March 17th, 2023 as part of the Propel Spring Quarterly Summit 2023

Author: Ted Parton, Lead Software Engineer @ InRhythm

Overview

No alt text provided for this image
Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

We recently held our Spring Summit consisting of six workshops hosted by each of our practice areas. On March 17th, 2023, our SDET Practice led a series of talks and workshops on Microsoft’s Playwright. Playwright is a tool that enables end-to-end testing of modern web applications. Playwright works with all modern web browsers including: Chromium, Firefox, and WebKit. For more information see: https://playwright.dev/

Playwright Parallelism

No alt text provided for this image

Playwright achieves parallelism by running multiple simultaneous processes threads. Each thread runs one Playwright Test File at a time. That is to say, if we have 10 test files and 5 threads, then the Playwright orchestrator will send a test file to each thread (or process), thus running five test files in parallel. As a thread becomes available, it will be provided as part of the next test file.

Tests in a test file are run in order by default. However, it is possible to parallelize those as well; keep in mind that tests run in parallel are in independent processes and cannot communicate with each other. So if one test is dependent on another, you would not want to run them in parallel.

Disabling Parallelism

No alt text provided for this image

You may on occasion have a good reason to disable parallel testing. For instance you may be targeting hardware that has limited process threads, memory, or CPU. Alternatively, there may be a particular workflow you need to follow and it would be best to run in a particular sequence.

Fortunately, Playwright does allow you to disable parallelism by setting the number of workers to one in the `test.describe.configure` settings. You can also do this from the command line runner with `npx playwright test –workers=1`

No alt text provided for this image

Control Test Order

No alt text provided for this image

By default the tests in a Playwright Test File are run in order of declaration. However, you can override that in some circumstances. For instance if you have disabled parallelism, test files will be run in alphabetical order by default. So you could control the order by coming with a good naming convention.

You can go a step further by controlling the order in helper functions. For more information on that, we recommend that you see the documentation located at: https://playwright.dev/docs/test-parallel#use-a-test-list-file

Playwright Reporting

No alt text provided for this image

Playwright Test includes the ability to create reports based on test results. Playwright includes seven predefined reporters and provides support for creating custom reporters.

The Predefined Reporters Are:

  • List Reporter

Prints a line for each test being run, and is the default for all executions except when running with CI. For CI the Dot reporter is the default.

Example Output:

No alt text provided for this image
  • Line Reporter

According to the official documentation, a Line Reporter is more concise than the List Reporter. It uses a single line to report the last finished test, and prints failures when they occur.

Line Reporter is useful for large test suites where it shows the progress but does not spam the output by listing all the tests.

Example Output:

No alt text provided for this image
  • Dot Reporter

The Dot Reporter provides a concise report by just producing a single character per successful test. The Dot Reporter is the default reporting method for CI. This method can be very useful anytime you do not want a lot of output.

Example Output:

No alt text provided for this image
  • HTML Reporter

As its name suggests, the HTML reporter generates an HTML based report. The HTML Reporter according to the documentation, by default, HTML reports are opened automatically if some of the tests failed. You can control this behavior via the open property in the Playwright config. The possible values for that property are always, never and on-failure (default).

You can also configure host and port that are used to serve the HTML Report.

  • JSON Reporter

This reporter generates results in JSON (JavaScript Object Notation). You may find it useful to have this written to a file rather than the screen. 

Below is an example of how to do this from Bash:

No alt text provided for this image

Alternatively you can define this behavior in the configuration file:

No alt text provided for this image
  • JUnit Reporter

This will produce a report in JUnit-style xml. As with the JSON Reporter, you will likely want to write this out to a file. The JUnit Reporter offers support for a robust set of options. If you are testing an app written in Java that utilizes JUnit for tests, this reporter can be highly useful. 

More information about this can be found at: https://playwright.dev/docs/test-reporters#junit-reporter

  • GitHub Reporter

Provides automatic failure annotations when running in GitHub actions. The other reporters work with GitHub Actions, but do not provide annotations.

Invoke A Reporter

No alt text provided for this image

It is quite easy to specify which reporter to use, by setting the name like in the example below:

No alt text provided for this image

Custom Reporters

No alt text provided for this image

As previously mentioned, you can create a custom reporter. Playwright provides an API to help with this at https://playwright.dev/docs/api/class-reporter. 

Below is an example of a custom TypeScript reporter courtesy of the Playwright website:

No alt text provided for this image

As with the pre-defined reporters, you can use your custom ones by specifying the name of the reporter. For instance, the custom reporter above can be accessed as:

No alt text provided for this image

Written by Kaela Coppinger · Categorized: DevOps, Software Engineering, Web Engineering · Tagged: best practices, devops, INRHYTHMU, JavaScript, learning and growth, Microsoft, parallelization, Playwright, Propel Spring Quarterly Summit 2023, Propel Workshop, reporting, software engineering, testing

  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Interim pages omitted …
  • Go to page 17
  • Go to Next Page »

Footer

Interested in learning more?
Connect with Us
InRhythm

110 William St
Suite 2601
New York, NY 10038

1 800 683 7813
get@inrhythm.com

Copyright © 2023 · InRhythm on Genesis Framework · WordPress · Log in

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPT
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT