<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: James Konik</title>
    <description>The latest articles on Forem by James Konik (@jamibaraki).</description>
    <link>https://forem.com/jamibaraki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F630453%2F8fb106d8-8808-46d6-8a3a-64bd58b5ae21.png</url>
      <title>Forem: James Konik</title>
      <link>https://forem.com/jamibaraki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jamibaraki"/>
    <language>en</language>
    <item>
      <title>PDF Web Viewers Compared: Foxit, PDFTron, and PSPDFKit</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Wed, 27 Oct 2021 09:32:39 +0000</pubDate>
      <link>https://forem.com/jamibaraki/pdf-web-viewers-compared-foxit-pdftron-and-pspdfkit-2gi6</link>
      <guid>https://forem.com/jamibaraki/pdf-web-viewers-compared-foxit-pdftron-and-pspdfkit-2gi6</guid>
      <description>&lt;p&gt;PDF is the &lt;a href="https://www.soliddocuments.com/pdf/_word_format/170/1?id=170&amp;amp;tag=1"&gt;goto format&lt;/a&gt; for high quality, printable documents and is &lt;a href="https://pdftables.com/blog/pdf-popularity"&gt;growing in popularity&lt;/a&gt;. The files are used &lt;a href="https://www.vice.com/en/article/pam43n/why-the-pdf-is-secretly-the-worlds-most-important-file-format"&gt;everywhere&lt;/a&gt;, but displaying them in the browser comes with challenges. The format is complex, and includes a broad selection of features to implement.&lt;/p&gt;

&lt;p&gt;If you’re building software that requires PDF display, or more advanced interactions, then you need to make these features available to your users, and make them work well on multiple devices.&lt;/p&gt;

&lt;p&gt;In this article, you’ll read about three choices for teams who want to present PDF documents on the web. You’ll learn about their features, their pricing, and their documentation. You’ll also see how they’re regarded by developers, and learn the best use cases for each of them. First though, let’s cover some basics. &lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a PDF Viewer?
&lt;/h2&gt;

&lt;p&gt;There are many viewers that can show PDFs, and many have their own SDKs, so developers can build them into their applications. Using them is as simple as adding a few lines of JavaScript to your site, and there is plenty of scope for customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use a Third-party Viewer Over an Embedded iFrame?
&lt;/h2&gt;

&lt;p&gt;You can &lt;a href="https://www.codexworld.com/embed-pdf-document-file-in-html-web-page/"&gt;embed PDF files&lt;/a&gt; directly into a page, but good luck getting results with that. Several issues might occur, such as conflicting scrollbars, misalignment and divergent cross-browser behavior. Direct embedding isn’t &lt;a href="https://shortiedesigns.com/blog/why-pdf-documents-shouldnt-be-used-for-web-content/"&gt;the best way&lt;/a&gt; to display PDFs in the browser.&lt;/p&gt;

&lt;p&gt;To give your users the best experience, use a third-party viewer. These provide a better, &lt;a href="https://pdfjs.express/blog/how-embed-pdf-in-html-website"&gt;more consistent experience&lt;/a&gt;. They also offer a wide range of features like signing, interaction, and collaboration. &lt;/p&gt;

&lt;p&gt;Viewers are typically built around an SDK, enabling you to build them into your own systems and add features, as well as change the presentation to match the rest of your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Compare Viewers
&lt;/h2&gt;

&lt;p&gt;Let's go through the viewers and see what they offer. I'll talk about their features, and see how easy they are to use. I'll also look at their documentation and pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://developers.foxit.com/"&gt;Foxit PDF Web Viewer&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MZ5HsI2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/rNKn5gu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MZ5HsI2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/rNKn5gu.png" alt="Foxit web viewer screenshot including icons, highlighted text and a picture of plants" width="880" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Foxit PDF Web Viewer is the web version of Foxit’s PDF viewer, which allows you to view documents consistently across different platforms, while enjoying the kind of advanced features you would expect in a desktop app. &lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://webviewer-demo.foxit.com/"&gt;demo&lt;/a&gt; shows off its detailed, feature-rich interface. It lets you select different areas to focus on and takes you through a brief mini-tutorial for each one, which gives you a quick overview of what it can do, and how you do it.&lt;/p&gt;

&lt;p&gt;Foxit’s document manipulation features include highlighting, annotation, and strikeout. There are also security features like 256-bit encryption and user restrictions. It works with forms, can import and export data, and lets you sign documents.&lt;/p&gt;

&lt;p&gt;It also has collaboration features, allowing users to work together on the same document.&lt;/p&gt;

&lt;p&gt;It’s a pure JavaScript library, so it is easy to add to your applications. Its powerful SDK includes a viewer and interface—which can be deployed quickly—and it all runs on the frontend.&lt;/p&gt;

&lt;p&gt;Deploying Foxit is straightforward. On the website is a 21-line JavaScript snippet for you to paste into your code and you only need to update the license to get up and running.&lt;/p&gt;

&lt;p&gt;Foxit’s documentation includes a large selection of &lt;a href="https://developers.foxit.com/developer-hub/document/developer-guide-pdf-sdk-web/"&gt;developer guides&lt;/a&gt; alongside a &lt;a href="https://developers.foxit.com/resources/pdf-sdk-web/api_reference/index.html"&gt;comprehensive API reference&lt;/a&gt;, containing details of its many modules and classes. &lt;/p&gt;

&lt;p&gt;The developer guides walk you through many different tasks, with code samples and diagrams. They cover each major platform, including the web. The full API reference is also there if you want specific information quickly.&lt;/p&gt;

&lt;p&gt;There are also articles, case studies and white papers to help you understand how to integrate its products into your business.&lt;/p&gt;

&lt;p&gt;With its prices starting at &lt;a href="https://developers.foxit.com/contact/"&gt;$3000 per platform per year&lt;/a&gt;, the Foxit SDK is cheaper than PDFTron for single platform deployment, though you’ll need to discuss pricing with the viewer’s sales team for an accurate quote. &lt;/p&gt;

&lt;p&gt;It offers a &lt;a href="https://developers.foxit.com/pdf-sdk/free-trial/"&gt;30-day free trial&lt;/a&gt;, so you can test it out before making a decision.&lt;/p&gt;

&lt;p&gt;Foxit has a &lt;a href="https://www.foxit.com/resources/customers.html"&gt;vast selection&lt;/a&gt; of customers, including several major technology companies.&lt;/p&gt;

&lt;p&gt;It has a reputation for &lt;a href="https://www.g2.com/products/foxit-pdf-editor/reviews"&gt;good value&lt;/a&gt;, and has more features than the common Adobe reader. Its &lt;a href="https://www.techradar.com/reviews/foxit-reader-free"&gt;strong security&lt;/a&gt; is also a big asset.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.foxit.com/case-studies/loomion/"&gt;Loomion&lt;/a&gt; used Foxit successfully to let customers view documents in meetings, and &lt;a href="https://developers.foxit.com/case-studies/omega/"&gt;Omega&lt;/a&gt; chose it due to its superior interaction capabilities.&lt;/p&gt;

&lt;p&gt;Developers also cited that Foxit received &lt;a href="https://www.g2.com/products/foxit-pdf-sdk/reviews/foxit-pdf-sdk-review-728960"&gt;good feedback&lt;/a&gt; from customers and &lt;a href="https://www.g2.com/products/foxit-pdf-sdk/reviews/foxit-pdf-sdk-review-731365"&gt;saves them time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Foxit is strong on price and excels at presenting information to customers due to its customizability. It is also fast, with &lt;a href="https://developers.foxit.com/blog/customer-reviews-foxit-pdf-sdk/"&gt;tests showing&lt;/a&gt; it outperforms another competitor 86% of the time.&lt;/p&gt;

&lt;p&gt;Its developer guides can also help you get started with it quickly, useful if you’re using it via its free trial.&lt;br&gt;
Its speed makes it ideal for resource-heavy environments, limited bandwidth scenarios, or if you’re deploying to older devices. Foxit’s feature set makes the viewer ideal if you need document signing, collaboration, or interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.pdftron.com/webviewer/"&gt;PDFTron&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VVXN8Nho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/RutXHLT.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VVXN8Nho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/RutXHLT.png" alt="PDFTron screenshot showing light, spacious interface and a comment being added to text" width="814" height="775"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PDFTron’s web viewer is another JavaScript driven offering, letting you work with PDFs on browsers and mobile devices.&lt;/p&gt;

&lt;p&gt;Its interface is clear and intuitive, with buttons that convey their function well. The document in its &lt;a href="https://www.pdftron.com/webviewer/demo/"&gt;demo&lt;/a&gt; certainly loads fast, but doesn’t render at fantastic quality.&lt;/p&gt;

&lt;p&gt;The viewer includes annotation, encryption, watermarks, and signing. PDFTron also features ICC color management and color separation. It supports a wide range of document formats and also allows users to collaborate on files.&lt;/p&gt;

&lt;p&gt;You can also copy the canvas directly to an image in a few lines of code, letting you convert PDFs to images easily.&lt;/p&gt;

&lt;p&gt;In addition to JavaScript, PDFTron uses WebAssembly, &lt;a href="https://developer.chrome.com/docs/native-client/nacl-and-pnacl/#portable-native-client-pnacl"&gt;PNaCI&lt;/a&gt;, and compiled C++ for extra performance.&lt;/p&gt;

&lt;p&gt;Aside from the web viewer, the PDFTron SDK is considered &lt;a href="https://www.rapidvaluesolutions.com/tech_blog/how-to-build-an-android-app-for-document-collaboration-with-pdftron-sdk/"&gt;stronger on mobile&lt;/a&gt; than its competitors, making it a good choice if you’re building a multi-platform application.&lt;/p&gt;

&lt;p&gt;It &lt;a href="https://www.g2.com/products/pdftron/reviews"&gt;reviews well&lt;/a&gt;, though memory management in Linux is a minor weakness.&lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://www.pdftron.com/api/web/index.html"&gt;API documentation&lt;/a&gt; is clear, and straightforward and has been &lt;a href="https://namnguyen.design/blog/2021-03-10-how-to-integrate-pdftron-with-ui-frameworks-%F0%9F%93%83/"&gt;highly praised&lt;/a&gt; by developers.&lt;/p&gt;

&lt;p&gt;There is GitHub starter code for several frameworks, including React, Vue, and Angular. There are also several full app examples. It’s always good to see some working code when getting started with a new technology, so that will really help newcomers see how to use it.&lt;/p&gt;

&lt;p&gt;PDFTron doesn’t provide clear pricing data. You need to contact its sales team to discuss your requirements and get a quote. &lt;a href="https://pdf.wondershare.com/pdf-software-comparison/pdftron.html"&gt;Research suggests&lt;/a&gt; a baseline of $4000 per year. That’s more than Foxit, though it may vary depending on your use case.&lt;/p&gt;

&lt;p&gt;Its ease of use can help you get quick results, with clients like &lt;a href="https://www.pdftron.com/blog/customers/recover-health-innovates-new-paperless-app-in-24-days/"&gt;Recover Health&lt;/a&gt; getting applications running in just 24 days.&lt;/p&gt;

&lt;p&gt;PDFTron’s &lt;a href="https://stackoverflow.com/questions/66397320/pdftron-copy-wrong-text"&gt;developers proactively react&lt;/a&gt; to issues and can help with any issues you have, too.&lt;/p&gt;

&lt;p&gt;Its prebuilt samples are useful for those working with various frameworks, making the viewer ideal if you want to get an application out of the door fast. Its integrations also make it ideal for use with the platforms it supports.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://pspdfkit.com/pdf-sdk/web/"&gt;PSPDFKit&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gtMAWtdJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mvlPrT4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gtMAWtdJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mvlPrT4.png" alt="PSPDFKit screenshot showing drawing tools and color selection panel" width="880" height="748"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PSPDFKit is another JavaScript library-based product, with a core viewer and several other components for different features. It can be deployed in standalone form via WebAssembly, or on a server using Docker, which allows you to pre-render documents for better performance.&lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://web-examples.pspdfkit.com/hello"&gt;demo&lt;/a&gt; cleverly uses a tutorial as the sample document, teaching you the basics of the interface and inviting you to try out its annotation tools.&lt;/p&gt;

&lt;p&gt;With annotation, editing, redaction, and form filling, PSPDFKit covers many bases. It has a reader view to simplify document layouts for mobile devices. It also has digital and electronic signing. Document collaboration and commenting are available for team-based work.&lt;/p&gt;

&lt;p&gt;The viewer’s document indexing makes it easy to search through multiple documents, which is useful for research based projects.&lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://en.wikipedia.org/wiki/Optical_character_recognition"&gt;optical character recognition&lt;/a&gt; lets you convert inaccessible scanned or vector content into text you can work with directly. &lt;/p&gt;

&lt;p&gt;You can generate PDFs from HTML, and design forms. It also has comparison features. &lt;/p&gt;

&lt;p&gt;You can start using it with just ten lines of JavaScript, making it very quick to get going. Its website includes example projects using React, Node.js, webpack, and Ruby on Rails, and there are integrations for npm and Yarn.&lt;/p&gt;

&lt;p&gt;Its well written API documentation contains technical data, as well as a few lines about what each element does, which developers will appreciate.&lt;/p&gt;

&lt;p&gt;It claims to have simple and flexible pricing, though there are no figures provided on the site and, again, you’ll have to contact its sales department for a quote. Sales aren’t always quick to respond, with several developers complaining about its system on Twitter. One person described it, along with PSPDFKit, as &lt;a href="https://twitter.com/nbevans/status/1376582186862805001"&gt;a bit of a farce&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Be prepared to negotiate. On the plus side, there’s a 60-day free trial if you want to test it out while waiting for its sales team to get back to you.&lt;/p&gt;

&lt;p&gt;It doesn’t seem as widely discussed as the other products here, with differing reviews ranging in opinion. The &lt;a href="https://sourceforge.net/software/product/PSPDFKit-SDK/#reviews"&gt;general consensus&lt;/a&gt; is that ease of use is a strength and custom functionality a weakness.&lt;/p&gt;

&lt;p&gt;PSPDFKit has some strong features for mobile users, such as pre-rendering from a server and simplified document layouts.&lt;/p&gt;

&lt;p&gt;If your users need to work with scanned documents, it’s a great choice, too. It’s also ideal for those wanting to create PDFs from their image files, or create forms. Its strong indexing and conversion features make it a good choice for academics or anyone working with many documents, particularly if they need updating to make them more accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There’s no shortage of choices when adding PDF support to your web applications. These three tools have many common features, and their individual strengths make them suitable for particular use cases.&lt;/p&gt;

&lt;p&gt;They all have different features that you can implement easily and make available to your users. When deciding on one, you’ll want to check off your technical requirements and consider performance as well as ease of use. &lt;/p&gt;

&lt;p&gt;Price is also a factor. Keeping costs down never hurt anyone. You should also think about support, particularly if your product is on the bleeding edge of technology and dependent on newer features.&lt;/p&gt;

&lt;p&gt;Foxit has a broad feature set with straightforward pricing, and appears cheaper than its competitors. Its security features make it ideal if working with sensitive data or strict compliance requirements.&lt;/p&gt;

&lt;p&gt;PDFTron is quick to get up and running and is strong on mobile, making it good for prototyping, or supporting multiple devices.&lt;/p&gt;

&lt;p&gt;PSPDFKit is great if you want a fast, server-based approach. It also shines if you want its indexing features or optical character recognition. &lt;/p&gt;

&lt;p&gt;Whichever you choose, it’s worth investigating everything the various viewers offer to make sure you’re getting the most value. Every feature you take advantage of brings your app one step closer to success.&lt;/p&gt;

&lt;p&gt;Disclaimer: This article was commissioned and paid for by Foxit&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Making E-Commerce More Accessible: 6 Tips for Developers</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Tue, 07 Sep 2021 13:26:29 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/making-e-commerce-more-accessible-6-tips-for-developers-82n</link>
      <guid>https://forem.com/fabric_commerce/making-e-commerce-more-accessible-6-tips-for-developers-82n</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxndbjfe3qtskw265gng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxndbjfe3qtskw265gng.png" alt="Making E-Commerce More Accessible: 6 Tips for Developers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ignoring accessibility is a way to drive customers away from your e-commerce site. While it’s easy for developers to focus on new features and bug fixing, putting effort into inclusive, accessible sites will have huge benefits.&lt;/p&gt;

&lt;p&gt;Accessibility impairment is more common than you might think. According to &lt;a href="https://www.shopify.com/partners/blog/developing-shopify-themes-with-accessibility-in-mind" rel="noopener noreferrer"&gt;Shopify data&lt;/a&gt;, 2.3 percent of people live with a reading disorder, 8 percent of men have a form of color blindness, and 7 percent of people live with a severe dexterity disability. &lt;/p&gt;

&lt;p&gt;In this article, I’ll highlight six areas where developers can make e-commerce sites more accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Accessibility Standards
&lt;/h2&gt;

&lt;p&gt;Accessibility standards exist to outline what to work toward clearly. The &lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/" rel="noopener noreferrer"&gt;Web Content Accessibility Guidelines&lt;/a&gt; is a great resource for web content accessibility. It provides a single, shared global standard to meet the needs of individuals, organizations, and governments. &lt;/p&gt;

&lt;p&gt;In some cases, accessibility standards are &lt;a href="https://www.boia.org/blog/is-there-a-legal-requirement-to-implement-wcag" rel="noopener noreferrer"&gt;legally required&lt;/a&gt;. Applicable rules depend on your location, the products you sell, and the size of your business.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Implement Accessibility
&lt;/h2&gt;

&lt;p&gt;If you’re just beginning to implement accessibility, &lt;a href="https://a11y-101.com/" rel="noopener noreferrer"&gt;a11y-101&lt;/a&gt; is a great starting point. After implementation, ensure the product works well on screen readers and can be used via keyboard navigation. User testing, although pricier, is also an effective option.&lt;/p&gt;

&lt;p&gt;Automatic audit tools, like the &lt;a href="https://addyosmani.com/a11y/" rel="noopener noreferrer"&gt;a11y command line tool&lt;/a&gt;, identify issues quickly and easily. The &lt;a href="http://squizlabs.github.io/HTML_CodeSniffer/" rel="noopener noreferrer"&gt;HTML_CodeSniffer&lt;/a&gt; is useful when testing for specific compliance guidelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcz1jkl3d26c6mszvrx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcz1jkl3d26c6mszvrx9.png" alt="Screenshot showing the a11y command line tool giving fabric’s site a full audit pass"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See the result of using the a11y command-line tool on &lt;a href="https://fabric.inc/" rel="noopener noreferrer"&gt;fabric’s site&lt;/a&gt;. Installing took thirty seconds, and running the tool is even quicker. Tools like this can significantly improve your accessibility without sacrificing time. &lt;/p&gt;

&lt;p&gt;Let’s take a look at six specific tips for addressing problem areas to improve the accessibility of your e-commerce channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Improve Product Carousels
&lt;/h2&gt;

&lt;p&gt;A carousel is a visually appealing way to show off products. This love, however, is not &lt;a href="https://shouldiuseacarousel.com/" rel="noopener noreferrer"&gt;universal&lt;/a&gt;. They have several &lt;a href="https://a11y-101.com/development/carousels" rel="noopener noreferrer"&gt;accessibility problems&lt;/a&gt;. First, their controls are unclear, particularly for the visually or cognitively impaired. Second, a screen reader may not associate controls with the required action. A control system that is obvious to a designer may not be intuitive to users.&lt;/p&gt;

&lt;p&gt;Carousels that autoplay are an issue for those who &lt;a href="https://www.creativebloq.com/accessibility-expert-warns-stop-using-carousels-7133778" rel="noopener noreferrer"&gt;use a keyboard&lt;/a&gt; to select screen elements. Users may not reach the control they want in time. Those who need more time to read are also frustrated when content changes automatically. Furthermore, the element chosen may also revert to the first available one when the carousel updates, making the whole site difficult to use. &lt;/p&gt;

&lt;p&gt;If your client insists on using a carousel, you can still take steps to improve its accessibility. For example, see &lt;a href="https://www.w3.org/WAI/tutorials/carousels/working-example/" rel="noopener noreferrer"&gt;this sample code&lt;/a&gt; from the W3C Web Accessibility Initiative (WAI) under &lt;a href="https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document" rel="noopener noreferrer"&gt;this license&lt;/a&gt;. It features readable text, optimizes for keyboard focus, and communicates changes to all users.&lt;/p&gt;

&lt;p&gt;Although carousels are not ideal, you can still improve your site’s accessibility with them. In the below snippet, a live region is being created and then used later in the code. Doing so announces to users with visual impairments changes to the highlighted item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
    &lt;span class="c1"&gt;// In the init function, we add a live region to announce the slide number when using the previous/next buttons&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;//…… other code here&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;liveregion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;liveregion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-live&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;polite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;liveregion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-atomic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;liveregion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;liveregion visuallyhidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;carousel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;liveregion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//…… further code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// later in the setSlides function, we decide what happens when the slide is updated&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setSlides&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;//…… other code here&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;announceItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;carousel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.liveregion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;new_current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; of &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;slides&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//…… further code&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Make Visual Elements Accessible
&lt;/h2&gt;

&lt;p&gt;Using only visual elements to present your product information excludes potential customers who cannot see them. Making information available to everyone is critical for accessibility. For images, that means including an &lt;a href="https://www.w3schools.com/tags/att_img_alt.asp" rel="noopener noreferrer"&gt;alt tag&lt;/a&gt;, as seen in the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"coffee-maker.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"blue coffee maker with glass mug and simple control panel"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"200"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Video presents challenges to many users. But, with the &lt;a href="https://www.vidyard.com/blog/accessible-video/" rel="noopener noreferrer"&gt;right tweaks&lt;/a&gt;., you can make them available to everyone. Here are some changes to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Captions:&lt;/strong&gt; Captions make videos easier to follow, especially for the hard of hearing. Open captions are included in the actual video, while closed captions use a separate text file for screen readers and the visually impaired.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transcripts:&lt;/strong&gt; Providing a video’s full text as a &lt;a href="https://www.washington.edu/accessibility/videos/" rel="noopener noreferrer"&gt;separate transcript&lt;/a&gt; is an excellent way to increase accessibility. Transcripts also benefit those who prefer skimming through text, as opposed to a strictly visual format. Some media players, such as &lt;a href="https://ableplayer.github.io/ableplayer/" rel="noopener noreferrer"&gt;Able Player&lt;/a&gt;, automatically generate transcripts from closed captions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audio descriptions:&lt;/strong&gt; Spoken audio describing a video helps visually impaired users understand what is happening. This can be presented as a separate, optional file or played alongside the video.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accessible video players:&lt;/strong&gt; If your frontend channels utilize a video player, make these more accessible too. Look to include supporting captions and audio descriptions, allow videos to be paused, have clear controls, and use high-contrast colors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Replace or Improve Captchas
&lt;/h2&gt;

&lt;p&gt;Captchas are designed to prevent bots and AI from accessing websites. However, AI is &lt;a href="https://security.googleblog.com/2014/12/are-you-robot-introducing-no-captcha.html" rel="noopener noreferrer"&gt;pretty good at them&lt;/a&gt;, scoring 98.4 percent on distorted text problems. In response, captchas are becoming harder, but this added complexity is causing difficulties for those with impairments.&lt;/p&gt;

&lt;p&gt;Captchas are the biggest problem &lt;a href="https://webaim.org/projects/screenreadersurvey7/" rel="noopener noreferrer"&gt;cited by screen reader users&lt;/a&gt;. Many visually impaired people cannot solve a visual captcha, leaving them unable to access the protected content. Although an &lt;a href="https://captcha.com/articles/audio-captcha.html" rel="noopener noreferrer"&gt;audio captcha&lt;/a&gt; is a good alternative, they can also have accessibility problems. Furthermore, not all systems have audio available.&lt;/p&gt;

&lt;p&gt;There are alternative ways to identify bots beyond captchas, so you can &lt;a href="https://a11y-guidelines.orange.com/en/articles/captcha-accessibility" rel="noopener noreferrer"&gt;avoid using them&lt;/a&gt; altogether. One solution is to time how long a form on your e-commerce site takes to complete. Spambots can fill and submit forms instantly. By excluding any messages completed in under ten milliseconds, you can filter most of these bots out.&lt;/p&gt;

&lt;p&gt;Another solution is to use server-side AI to analyze messages and filter IP addresses. For example, the &lt;a href="https://www.experienceux.co.uk/ux-blog/5-alternatives-to-captcha-that-wont-baffle-or-frustrate-users/" rel="noopener noreferrer"&gt;honeypot&lt;/a&gt; involves hiding a form field so users cannot see it, but spambots still attempt to fill it in. It lets you identify spambots and filter out their responses accordingly. &lt;/p&gt;

&lt;p&gt;See how to make a form field hidden:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name_bot_trap"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not all spambots will fall for this, however. Check out other techniques &lt;a href="https://www.araweb.co.uk/Safe_Contact_Form_with_Honeypot_840" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://dev.to/felipperegazio/how-to-create-a-simple-honeypot-to-protect-your-web-forms-from-spammers--25n8"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Captchas don’t just stop bots; they prevent real people from using your site. Thus, replacing or improving captchas removes another barrier to user accessibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use High-Contrast Themes
&lt;/h3&gt;

&lt;p&gt;For users with visual impairments, some visual elements don’t stand out, affecting the UI. One way to improve accessibility for color-blind users is to use contrasting colors. For instance, selecting colors &lt;a href="https://www.colormatters.com/color-and-design/basic-color-theory" rel="noopener noreferrer"&gt;on opposite sides of the color wheel&lt;/a&gt; contrasts nicely for everyone.&lt;/p&gt;

&lt;p&gt;Some users also find excess brightness difficult to look at and prefer darker themes. Thus, some sites allow users to enable Dark Mode. You can offer this with CSS and JavaScript. Browser extensions, like &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/darkreader/" rel="noopener noreferrer"&gt;Dark Reader&lt;/a&gt;, offer solutions. This &lt;a href="https://inclusive-components.design/a-theme-switcher/" rel="noopener noreferrer"&gt;extended tutorial&lt;/a&gt; explains writing a theme switcher in React.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqygwsbbw5l1ozvktd8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqygwsbbw5l1ozvktd8l.png" alt="Screenshot showing fabric’s storefront page displayed in a color blindness simulator, with controls for different types of tests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are several types of color blindness, and a color scheme that works for one user may not work for another. Thus, you can also conduct testing with color-blind users. Alternatively, you can take a screenshot of your site and test it in a &lt;a href="https://www.color-blindness.com/coblis-color-blindness-simulator/" rel="noopener noreferrer"&gt;color blindness simulator&lt;/a&gt; to see how your site looks and identify any issues to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Provide Input Assistance
&lt;/h2&gt;

&lt;p&gt;Form inputs need to be clear and understandable. They should alert users to any errors but also offer solutions. For example, making a field “required” is &lt;a href="https://a11y-101.com/development/required" rel="noopener noreferrer"&gt;impairs accessibility&lt;/a&gt;. Using an asterisk to indicate a required field confuses screen reader users, who just read out “asterisk.” If you mark a field as required in HTML, screen readers will pick up on it but still read out the asterisk.&lt;/p&gt;

&lt;p&gt;Adding the text “required” is a good compromise. You can use the &lt;code&gt;&amp;lt;aria-hidden&amp;gt;&lt;/code&gt; tag to mask the asterisk. This displays the asterisk while making sure readers ignore it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"input_four"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;First Name &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"visible-hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;required&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"input_four"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;visible-hidden&lt;/code&gt; is a CSS class to hide the “required” text from visual rendering. See &lt;a href="https://a11y-101.com/development/skip-link" rel="noopener noreferrer"&gt;a11y-101’s approach&lt;/a&gt; to hiding text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="nc"&gt;.visible-hidden&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.visible-hidden&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although that’s a good start, older readers may not support the &lt;code&gt;&amp;lt;aria-hidden&amp;gt;&lt;/code&gt; tag. &lt;/p&gt;

&lt;p&gt;Another aspect to consider is where to place an indication of “errors” on forms. Readers should be able to find it. For example, a small line of text at the top or bottom of your form can easily be cut off from the user’s screen. Providing text that explains how to fix specific errors automatically read by screen readers is ideal. Like carousels, you should aim to prevent screen updates resetting keyboard navigation.&lt;/p&gt;

&lt;p&gt;By handling &lt;a href="https://webaim.org/techniques/formvalidation/#error" rel="noopener noreferrer"&gt;errors sensibly&lt;/a&gt;, you ensure users will continue to use your e-commerce site.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Keep Customers On-Site
&lt;/h3&gt;

&lt;p&gt;Affiliate links can confuse users by taking them away from your site to a different one. For instance, driving users to a commercially driven, flashy site can be stressful.&lt;br&gt;
To improve accessibility, ensure it’s clear &lt;a href="https://easyaffiliate.com/blog/3-ways-you-can-make-your-affiliate-program-more-accessible/" rel="noopener noreferrer"&gt;where links lead&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Those using screen readers navigate using the tab key to move around the page. They must tab through affiliate links, making this process slow. Allowing users to &lt;a href="https://www.w3schools.com/accessibility/accessibility_skip_links.php" rel="noopener noreferrer"&gt;skip links&lt;/a&gt; helps speed up the process. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://fabric.inc/xm" rel="noopener noreferrer"&gt;fabric’s Experience Manager&lt;/a&gt; lets you build a headless CMS that keeps data and backend services separate from the presentation layer. This allows you to deliver a consistent, accessible experience across multiple channels, ensuring users don’t get confused as they move between channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;In an increasingly diverse, complex e-commerce landscape, it’s more important than ever to consider the differing needs of your users. This is particularly true for the millions of users who have difficulties with site usability. Therefore, improving your site’s accessibility is essential.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fabric.inc/" rel="noopener noreferrer"&gt;fabric&lt;/a&gt; can help build an e-commerce site to meet user accessibility needs and deliver a great experience for everyone.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Scaling Multi-Channel E-Commerce with Microservices and a Headless CMS</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Fri, 30 Jul 2021 20:43:56 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/scaling-multi-channel-e-commerce-with-microservices-and-a-headless-cms-4327</link>
      <guid>https://forem.com/fabric_commerce/scaling-multi-channel-e-commerce-with-microservices-and-a-headless-cms-4327</guid>
      <description>&lt;p&gt;Having a multi-channel e-commerce solution helps you reach new customers by giving you distribution on a variety of channels. Brands and retailers can now sell through traditional catalogs and POS, online stores, third-party sellers, and even social media.&lt;/p&gt;

&lt;p&gt;From a technical perspective, supporting a multi-channel e-commerce workflow isn’t easy. Doing it well demands you take the right technical approach and design an architecture that can handle rapid change without limiting your potential for growth.&lt;/p&gt;

&lt;p&gt;Microservices, APIs, and a headless CMS can form the basis for solving this problem. In this guide, I’ll explain the benefits of using this kind of architecture, and I’ll share some examples of how such a system works in practice, with workflows and code samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Multi-Channel E-Commerce?
&lt;/h2&gt;

&lt;p&gt;Multi-channel e-commerce is selling your products in more than one place online. We usually think of online stores when considering e-commerce, but there are plenty of other ways to reach customers.&lt;/p&gt;

&lt;p&gt;Apps, social media, and marketplaces such as Amazon that allow third-party sellers are all good places to sell goods online. Tablets in physical locations, such as stores or trade events, are also popular.&lt;/p&gt;

&lt;p&gt;Selling in multiple channels brings new challenges. Your backend infrastructure needs to support everything it’s connected to, and your developers need to be ready to handle the extra work of building and supporting these channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Headless CMS?
&lt;/h2&gt;

&lt;p&gt;A headless CMS is a content management system that keeps the &lt;a href="https://resources.fabric.inc/blog/glossary/headless-cms" rel="noopener noreferrer"&gt;backend independent&lt;/a&gt; from frontend delivery channels.&lt;/p&gt;

&lt;p&gt;The backend makes its services available to these channels via APIs. These all use the same underlying data, so things like product or customer information can stay the same across all of them.&lt;/p&gt;

&lt;p&gt;For example, if you have a product available on both Amazon and Google Shopping, your headless API can route its pricing data from a common source like a PIM, meaning the price, product descriptions, and images are identical on both channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Microservices?
&lt;/h2&gt;

&lt;p&gt;Microservices are encapsulated services that each have their own interface. They can be updated and modified without affecting other services. If the interface stays consistent, internal changes shouldn’t affect other components.&lt;/p&gt;

&lt;p&gt;For example, if you want to upgrade the security on your orders, that’s easier if your orders are handled by a set of microservices. If you were tied into a monolith, such as Oracle ATG, you’d have to upgrade the whole platform.&lt;/p&gt;

&lt;p&gt;With microservices, each individual service can be deployed and scaled on its own container. With AWS, for example, you pay for what you use, and if one service is suddenly in demand, Amazon’s cloud can manage the upsurge without problems and without affecting the rest of your backend.&lt;/p&gt;

&lt;p&gt;That’s useful if some part of your infrastructure sees a spike in traffic. Perhaps you have a holiday product that gets mentioned in an article. A lot of people will look at your catalog. A few days later (hopefully), a lot of them will come back and buy the product. Amazon can let you ride the wave of traffic to your catalog and then handle the increased demand on your ordering system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building vs. Buying
&lt;/h2&gt;

&lt;p&gt;Once you understand the requirements of multi-channel e-commerce, it becomes clear that you need some sort of headless, API-driven solution, and microservices offer clear benefits when it comes to scaling and modifying features.&lt;/p&gt;

&lt;p&gt;The hard question is whether you should build these services yourself or use a third-party solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building multi-channel e-commerce microservices
&lt;/h3&gt;

&lt;p&gt;Here’s an example of how data might flow through a microservices-based setup, with an API gateway receiving calls and a service mesh routing calls from your checkout service to the packing and accounts services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadm9mzkbwyvh1awy1zup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadm9mzkbwyvh1awy1zup.png" alt="API Gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To set up an architecture like this, you first need to decide what services you want it to provide and how they will connect. Once the essentials are in place, you can build from there. Let’s look at a couple of the key components you’ll need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order management system (OMS)
&lt;/h3&gt;

&lt;p&gt;An order management system deals with taking orders and handling different payment methods, as well as updating inventory, invoicing, and passing information to your delivery and accounting teams.&lt;/p&gt;

&lt;p&gt;When an order is placed, data flows from a frontend application to your backend infrastructure, which is responsible for distributing it among the other services that need it. Your product database will be updated, as will your accounts, and the warehouse will need to know what to deliver.&lt;/p&gt;

&lt;p&gt;As orders involve the interaction of multiple services, they are a good test of your architecture, as well as being essential to get right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product information manager (PIM)
&lt;/h3&gt;

&lt;p&gt;Storing product information is a key component of any e-commerce business with large and growing volumes of data to manage. The fields and relationships between them may evolve as new sales channels provide new ways to present them.&lt;/p&gt;

&lt;p&gt;The PIM provides information on products to your customers and allows for manual updates by staff, as well as automatic updates via other services, such as inventory.&lt;/p&gt;

&lt;p&gt;With a headless architecture, you can keep all this in one place so that updates will be reflected everywhere. You can add fields and redefine existing ones as required, and also expand your range of services to support new kinds of queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  API gateway and service mesh
&lt;/h3&gt;

&lt;p&gt;Another key component to this architecture is your API gateway. It routes API calls to the correct services from the various frontend channels. You can change the routing, which allows you to easily switch between different services or versions of them.&lt;/p&gt;

&lt;p&gt;For example, you could swap in a newer version of a service for testing or swap it out if you need to roll back to an earlier version. You can also route services from existing monoliths to newer microservices during a migration.&lt;/p&gt;

&lt;p&gt;A service mesh acts as an intermediary between your services and controls the data flow between them. A service mesh can handle logging, load balancing, and encryption.&lt;/p&gt;

&lt;p&gt;It can also enforce call limits on your services and provide a layer of security, letting you choose what data services are allowed to send to others. You may want to track which of your channels are calling particular services to help you identify issues or usage spikes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other services
&lt;/h3&gt;

&lt;p&gt;Aside from the core services and gateway layers, there are many other supporting services that make up a headless, e-commerce microservice platform.&lt;/p&gt;

&lt;p&gt;A personalization service can bring together the information you collect across all your channels and use it to customize the user experience on each one. A promotions and loyalty service can apply discounts to all your channels or specific ones. You could allow users to collect points or earn rewards from social media shares and then spend them on your web store, for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Processing Orders from Multiple Channels
&lt;/h2&gt;

&lt;p&gt;Let’s look at an example of how a microservice might deal with a call to its API. I’ll describe a workflow for processing orders using a prebuilt API, but if you build your own, it should be similar.&lt;/p&gt;

&lt;p&gt;When the customer has selected their items and verified their order details, the order is sent via the checkout service as a post request to the checkout endpoint.&lt;/p&gt;

&lt;p&gt;All channels can send the same request, regardless of their platform or UI. We can add or remove new channels without changing the backend, provided they send requests in the same format.&lt;/p&gt;

&lt;p&gt;The post request is sent to:&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;POST /api-order/checkout&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;To send it in JQuery (assuming you have a web frontend), you can do something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$.ajax(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;contentType:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;url:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api-order-checkout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON.stringify(data)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;dataType:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;success:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(data)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;formatted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;section&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;below&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;know&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;successfully&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;error:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(e)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;know&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;wrong&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request is formatted like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cartId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5f1b4158bb24210008b9a3f0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customerEmail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@fabric.inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customerPhoneNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"07780811973"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mobile"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paymentDetails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"transactionDetails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"paymentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CARD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"cardNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4111111111111111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"expDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1122"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"cvv"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"999"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"cardHolderFullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Joe Demo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"cardIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1111"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentKind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fabric User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11.27"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"conversion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"billToAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"first"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Joe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"last"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Demo"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"demo@fabric.inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"07780811973"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mobile"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"street1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"600 CONGRESS AVE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"street2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AUSTIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"zipCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1003"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"estimatedTax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"itemsTaxes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"lineItemId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"lineItemId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"shipToTaxes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shipToId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5f1b41892e8f1c0008fc20e8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shipFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"street1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"888 Broadway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"street2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"zipCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"46282"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API gateway will route this data to the relevant service. If the request is received and processed correctly, the backend will send a response formatted as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"checkoutComplete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4679-1016-66250"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the frontend can present a confirmation message to the user, and of course, this will vary depending on the sales channel you’re using.&lt;/p&gt;

&lt;p&gt;The backend can send further requests to other services, as determined by you and managed by your service mesh. As shown in the application diagram above, these could include calls to the shipping or promotions services, but the options are endless. To users, the interface is simple, while the backend implementation can be as complex as it needs to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Headless, microservices-based architectures have several advantages. Their modular nature makes them easy to change and gives you the flexibility to evolve your systems over time. They are also scalable, allowing you to allocate resources efficiently as you grow.&lt;/p&gt;

&lt;p&gt;Building them yourself is time-consuming and expensive, so using a prebuilt solution can give you a headstart. These building blocks can get you up and running quickly and keep you ahead of the competition. With your architecture in place, you can add features and support new services, confident that your setup can handle their requirements.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Design Patterns for Modern Day Commerce Using Microservices</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Fri, 30 Jul 2021 20:07:33 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/design-patterns-for-modern-day-commerce-using-microservices-3fg5</link>
      <guid>https://forem.com/fabric_commerce/design-patterns-for-modern-day-commerce-using-microservices-3fg5</guid>
      <description>&lt;p&gt;E-commerce businesses are using microservices to build a set of reusable components for their stores. These services make it easier to deliver your content to multiple channels at scale by operating independently from the frontend.&lt;/p&gt;

&lt;p&gt;In this post, I’ll talk about several design patterns you can implement and explain what they offer. I’ll also mention common use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Software Design Patterns
&lt;/h2&gt;

&lt;p&gt;Software design patterns are defined ways to solve common problems. They help developers understand how the components of a system relate to each other and interact. There’s no “perfect” design pattern—each has pros and cons and is helpful in specific situations. &lt;/p&gt;

&lt;p&gt;Most developers spend years of practice getting these patterns right. However, by applying them properly, you can achieve results. There are five design patterns for modern e-commerce architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The strangler pattern:&lt;/strong&gt;  A useful way to migrate from legacy software to a more modern approach. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ambassador pattern:&lt;/strong&gt; This gives you an encapsulated approach to handling network issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sidecar pattern:&lt;/strong&gt; This helps you add functionality without getting too tightly coupled to the rest of your software.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API interfaces:&lt;/strong&gt; These help software services and components communicate. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function chains:&lt;/strong&gt; These help code to handle sequential tasks. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While implementation is the most difficult part, knowing the names and intentions of each pattern is an essential first step. At the end of this guide, you will have a starting point for deciding when each is right for your e-commerce platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  The strangler pattern
&lt;/h3&gt;

&lt;p&gt;Named after the &lt;a href="https://www.overops.com/blog/strangler-pattern-how-to-keep-sane-with-legacy-monolith-applications/" rel="noopener noreferrer"&gt;strangler fig tree&lt;/a&gt;, the strangler pattern is moving from one platform to another gradually. You do this by replacing parts of your software one by one until eventually the old system is fully strangled. In practice, you can break it down into &lt;a href="https://blogs.sap.com/2017/09/25/strangler-applications-monolith-to-microservices/" rel="noopener noreferrer"&gt;three steps&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transformation: you create new versions of your services, replacing them one at a time&lt;/li&gt;
&lt;li&gt;Co-existence: where you run the new services and older services together&lt;/li&gt;
&lt;li&gt;Elimination: you replace everything you need and can retire the old system &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the strangler pattern allows continuous delivery of new features and high code coverage. It also facilitates a modular, test-driven approach enabling you to isolate issues and ensure each service you deliver works well.&lt;/p&gt;

&lt;p&gt;It’s a great way to shift to a new software setup, such as from a &lt;a href="https://resources.fabric.inc/blog/magento-to-microservices" rel="noopener noreferrer"&gt;monolith to microservices&lt;/a&gt;. It lets you break the work down into manageable chunks, driving results quickly. Furthermore, you can distribute tasks to different teams to increase buy-in and accountability across your engineering organization.&lt;/p&gt;

&lt;p&gt;On the other hand, it can take time. However, you can mitigate that by having teams work in parallel. Setting up your team right is as important as &lt;a href="https://developer.ibm.com/depmodels/microservices/articles/cl-strangler-application-pattern-microservices-apps-trs/" rel="noopener noreferrer"&gt;nailing the technical side&lt;/a&gt; of things.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ambassador pattern
&lt;/h3&gt;

&lt;p&gt;In the ambassador pattern, the ‘ambassador’ service is dedicated to communication. You create a proxy process or service that handles network requests for the rest of your application. &lt;/p&gt;

&lt;p&gt;With an ambassador service in place, you can add features like monitoring, logging, and call rerouting. It’s useful to translate requests from one format to another—for example, multi-channel e-commerce, where you distribute products to many different frontend consumers. &lt;/p&gt;

&lt;p&gt;If you’re using a mix of legacy and modern software, it can help bridge the gap, ensuring your network meets modern security and accountability standards. From an organizational viewpoint, it lets you &lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador" rel="noopener noreferrer"&gt;assign a team&lt;/a&gt; to the proxy service itself, allowing you to divide responsibility.&lt;/p&gt;

&lt;p&gt;While the ambassador pattern can quickly tie disparate systems together, it isn’t ideal if network latency is a concern. It can increase inter-service communication and higher memory and CPU usage.&lt;/p&gt;

&lt;p&gt;If you have issues moving away from your monolith or legacy software you’re stuck maintaining, the ambassador can be a great way to circumvent those weaknesses. It allows you to add features to old software without having to rewrite everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  The sidecar pattern
&lt;/h3&gt;

&lt;p&gt;In the sidecar pattern, you move a specified set of functionality into a separate component. This component exists alongside the primary application, generally sharing the same lifecycle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyesbuj9wwvf0svnzzv1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyesbuj9wwvf0svnzzv1c.png" alt="diagram showing sidecar pattern. The main application and sidecar both exchange information and have access to data on the shared host. The sidecar writes to the shared data when logging.)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sidecar is hosted together with its parent and can even run in the same process. That means there is little to no latency when the sidecar communicates with the parent, and it has access to the same resources.&lt;/p&gt;

&lt;p&gt;It can, however, use a different programming language or framework than the primary service, and multiple sidecars can use different languages. That means you can use the right tool for the job when adding extra functionality or cater to the strengths and preferences of various team members.&lt;/p&gt;

&lt;p&gt;Often the sidecar process can handle peripheral functions such as logging or network connectivity, while the main application handles core functions. Thus, if you need to move or reconfigure the application, teams can focus on the sidecar without having to change the main application.&lt;/p&gt;

&lt;p&gt;It’s a simple pattern with many potential applications. For example, in an e-commerce setting, you could use it to log financial transactions. As detailed records are vital in e-commerce, you can have an independent one to add to and build on over time.&lt;/p&gt;

&lt;p&gt;You can also use the sidecar pattern for handling network operations like adding modern encryption to a legacy service. This can let you partially modernize old e-commerce systems without resorting to a complete rewrite.&lt;/p&gt;

&lt;h3&gt;
  
  
  API interfaces
&lt;/h3&gt;

&lt;p&gt;An application programming interface, or API, is a way for software components to communicate with each other using a defined set of calls. Web services or microservices commonly use APIs. &lt;/p&gt;

&lt;p&gt;In addition to their use over networked communication, you can also use them for communication between microservices on the same host. There are several patterns commonly seen in API interfaces.&lt;/p&gt;

&lt;p&gt;REST is the most recognizable. It’s a staple of computer science courses and standard for a vast number of websites and services. It includes a set of verbs, which implement the CRUD pattern. &lt;a href="https://resources.fabric.inc/blog/rest-apis" rel="noopener noreferrer"&gt;RESTful services&lt;/a&gt; are stateless and cacheable, making them ideal for the web.&lt;/p&gt;

&lt;p&gt;In headless commerce, APIs allow multiple frontend applications to communicate with your backend services. Websites, apps, and software deployed on any other platform can send API requests to the same location. This lets you work on each component separately, making improvements and additions without worrying about the effect on the whole ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function Chain
&lt;/h3&gt;

&lt;p&gt;You can build serverless functions on the cloud that are self-contained and stateless and can execute on demand. Services like Amazon Web Services, Microsoft Azure, and Google Cloud let you create these, so you don’t have to worry about hardware issues.&lt;/p&gt;

&lt;p&gt;You can organize serverless functions into a &lt;a href="https://dashbird.io/knowledge-base/well-architected/serverless-functions-composition-strategies/" rel="noopener noreferrer"&gt;function chain&lt;/a&gt;. In this pattern, each function invokes the next when it completes. This pattern is ideal if a user action kicks off a series of tasks that are slow to process. The first function can respond to the user, so they aren’t left waiting.&lt;/p&gt;

&lt;p&gt;There are a few issues to consider when applying this pattern. Ideally, functions are independent and replaceable, but here the functions are dependent on each other. This breaks object-oriented design principles, but it’s necessary for certain applications. You can use a queuing system to call the functions in sequence, making them more independently operable and scalable.&lt;/p&gt;

&lt;p&gt;Function chains are useful to implement sequential tasks that are well defined. For example, you may want to call a function chain after a user places an order to process data through different microservices and push it into each subsequent data store. &lt;/p&gt;

&lt;p&gt;These tasks can each happen independently and in the background. This way, your e-commerce store’s UI stays snappy while the backend functions might take minutes to complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;The more you know about software patterns and how to apply them to e-commerce microservices, the better you can leverage this existing knowledge to solve problems.&lt;/p&gt;

</description>
      <category>microservices</category>
    </item>
    <item>
      <title>Using the Strangler Pattern to Break Down Your E-Commerce Monolith</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Wed, 30 Jun 2021 19:24:10 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/using-the-strangler-pattern-to-break-down-your-e-commerce-monolith-aem</link>
      <guid>https://forem.com/fabric_commerce/using-the-strangler-pattern-to-break-down-your-e-commerce-monolith-aem</guid>
      <description>&lt;p&gt;Monolithic platforms like &lt;a href="https://resources.fabric.inc/blog/shopify-plus-to-microservices" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt;, &lt;a href="https://resources.fabric.inc/blog/oracle-atg-to-microservices" rel="noopener noreferrer"&gt;Oracle ATG&lt;/a&gt;, and &lt;a href="https://resources.fabric.inc/blog/bigcommerce-to-microservices" rel="noopener noreferrer"&gt;BigCommerce&lt;/a&gt; are easy to get up and running. However, they lock you into various platform-specific limitations. As a result, you're subject to each platform’s constraints and may feel stuck using one-size-fits-all software.&lt;/p&gt;

&lt;p&gt;You face similar challenges if you’ve built your own e-commerce monolith. When more components of the application are intertwined, it is harder to modify features, scale components, or divide the work. After years of using one of these systems, technical debt builds up and changes are hard to implement.&lt;/p&gt;

&lt;p&gt;Microservices solve such problems. You can modularize your e-commerce business. Adapting quickly to the wealth of new opportunities to engage with your customers is a competitive advantage. That's why modern tech companies like &lt;a href="https://blog.dreamfactory.com/microservices-examples/" rel="noopener noreferrer"&gt;Netflix, Amazon, and Etsy&lt;/a&gt; have all switched to microservices.&lt;/p&gt;

&lt;p&gt;Migrating from monolith to microservices provides many technical and business challenges. One approach that helps to replace your monolith is the &lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html" rel="noopener noreferrer"&gt;strangler pattern&lt;/a&gt;. It does so one service at a time.&lt;/p&gt;

&lt;p&gt;In this post, you’ll learn how to use the strangler pattern to break down each piece of your e-commerce monolith until you’ve replaced it with discrete, scalable microservices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Microservices?
&lt;/h2&gt;

&lt;p&gt;Microservices have several advantages over a monolithic approach:&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical flexibility
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One-size-fits-all platforms are fast and convenient when you get started, but as your business develops, issues start to arise. &lt;/li&gt;
&lt;li&gt;With microservices, you are free to implement the programming languages and third-party services that are best for each piece of your application. 
Because they’re scalable and modular, your decisions don’t tie you down.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Microservices are independent and decoupled from your frontend. That means you can easily build new ways to reach your customers and wire them up to your services without having to reinvent the wheel each time. &lt;/li&gt;
&lt;li&gt;With your own services, you can ensure each service matches your needs, defining the data format, and functionality. You can also control how user access is structured. 
Flexibility also prevents bottlenecks as your teams are not &lt;a href="(https://dzone.com/articles/monolith-to-microservices-using-the-strangler-patt)"&gt;dependent&lt;/a&gt; on each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Attackers that &lt;a href="https://resources.fabric.inc/blog/ecommerce-security" rel="noopener noreferrer"&gt;gain access&lt;/a&gt; to your monolithic platform often gain access to &lt;em&gt;everything&lt;/em&gt; - customer, product, and order data. Microservices can create silos between services, keeping them more secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Scalability and the ability to focus resources on your more heavily trafficked services dynamically mean you can improve performance. 
For example, Best Buy improved its catalog API &lt;a href="https://blog.runscope.com/posts/monolith-microservices-transforming-real-world-ecommerce-platform-using-strangler-pattern" rel="noopener noreferrer"&gt;sync time&lt;/a&gt; from 24 hours to under 15 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Strangler Pattern?
&lt;/h2&gt;

&lt;p&gt;The strangler pattern takes its name from the &lt;a href="https://en.wikipedia.org/wiki/Strangler_fig" rel="noopener noreferrer"&gt;strangler fig&lt;/a&gt; tree. Like the tree, you use your existing application as a base. Then, you build a new service that replaces one specific element of it. When it’s done you retire the old part of the application.&lt;/p&gt;

&lt;p&gt;You continue this service by service until the new microservices replace your entire monolith. You ‘strangled’ the old code and thus can abandon it completely. &lt;/p&gt;

&lt;p&gt;There are &lt;a href="https://blogs.sap.com/2017/09/25/strangler-applications-monolith-to-microservices/" rel="noopener noreferrer"&gt;three phases in the strangler lifecycle&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transform&lt;/strong&gt; the application by creating new versions of existing services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Co-exist&lt;/strong&gt; with the old application running alongside an ever-increasing number of microservices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate&lt;/strong&gt; the old when the new services completely replace the old system.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Strangler vs. waterfall approach
&lt;/h3&gt;

&lt;p&gt;Besides the strangler pattern there is also the waterfall replacement pattern, the more common approach to migrating microservices. The waterfall pattern requires you to commit to a long development and deployment cycle, which &lt;a href="https://insidenow.deloitte.lu/is-waterfall-only-option/article/" rel="noopener noreferrer"&gt;increases the risk of bugs and lowers your velocity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The waterfall method can take &lt;a href="https://paulhammant.com/2013/02/16/misapplying-bayes-theorem-to-agile-versus-waterfall/" rel="noopener noreferrer"&gt;well over a year to deliver results&lt;/a&gt;, but you can make progress in bursts of six months or less by using the more agile strangler method. It naturally divides work into attainable targets, which means &lt;a href="https://federalnewsnetwork.com/cloud-computing/2016/02/cloud-potential-strangle-outdated-programs-not-post/" rel="noopener noreferrer"&gt;developers are motivated&lt;/a&gt; to complete tasks that deliver visible results.&lt;/p&gt;

&lt;p&gt;With the strangler pattern, you can use each new microservice as soon as it is ready. There’s no need to build a completely new system. &lt;a href="https://www.kiuwan.com/strangle-pattern-legacy-apps/" rel="noopener noreferrer"&gt;Some recommend&lt;/a&gt; rolling out changes monthly. For one, you can enjoy the advantages quickly. Secondly, it also lets your developers move on to the next project. If issues occur, they can roll pieces of the system back more easily than the whole thing.&lt;/p&gt;

&lt;p&gt;The strangler pattern is often the better option. It allows you to migrate each piece of your infrastructure step-by-step in a manageable, low-risk way and deliver business value faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  The downside to the strangler pattern
&lt;/h3&gt;

&lt;p&gt;There are some caveats. Migrating a complete application one step takes a while. Analyzing &lt;a href="https://www.leadingagile.com/2018/10/the-urge-to-stranglethe-strangler-pattern/" rel="noopener noreferrer"&gt;successful projects&lt;/a&gt; using the strangler pattern suggests to remaining consistent and ensuring your management team commits to the long-term project.&lt;/p&gt;

&lt;p&gt;Microservices benefit from robust development practices (like continuous integration and deployment) and having engineers that are familiar with them. Finding the right team is just as important as picking the right languages and frameworks. It’s important to make sure your developers are on board with the new processe. If they understand the advantages of the changes, &lt;a href="https://hmh.engineering/why-strangler-applications-are-not-completely-mad-8835c0abd612" rel="noopener noreferrer"&gt;buy-in will be higher&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One way to mitigate the risks of migrating to microservices is to use &lt;a href="http://fabric.inc/" rel="noopener noreferrer"&gt;an established e-commerce platform like fabric&lt;/a&gt;. We've built fabric on microservices and can work with your team to ensure a smooth migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Using the Strangler Pattern in E-Commerce
&lt;/h2&gt;

&lt;p&gt;Let’s look at how to implement the strangler pattern. I use the monolith provided billing service feature and move it to a new microservice. Then, I'll show you how to migrate important data and features without breaking your existing application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Decide where to start the migration
&lt;/h3&gt;

&lt;p&gt;The service you choose to start with depends on your need and the platform you’re using. There are two common approaches. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Critical features that you need to upgrade:&lt;/strong&gt; If it's impossible to update your legacy codebase or you’re facing performance issues that cost you customers (like a slow checkout experience), starting here might be best. Ensure everything is watertight before deploying. It takes more time but has more impact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick something less critical, to test the process:&lt;/strong&gt; It's a great idea if your developers are implementing microservices for the first time as it’s less risky. However, it will drive less value for the business.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s look at moving an e-commerce billing address service from a monolithic platform like Oracle ATG to a microservice hosted on AWS. Billing services that are slow or prone to errors might be preventing you from collecting revenue from customers. Thus, they’re often mission-critical in online stores. &lt;/p&gt;

&lt;p&gt;I’ll only include a couple of attributes, but you can replicate this general pattern with whatever data you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Build a middle layer
&lt;/h3&gt;

&lt;p&gt;An API gateway can manage service calls and filter them to either your existing monolith or new services. AWS includes &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started.html" rel="noopener noreferrer"&gt;a guide&lt;/a&gt; on how to do it. A &lt;a href="https://resources.fabric.inc/blog/ecommerce-service-mesh" rel="noopener noreferrer"&gt;service mesh&lt;/a&gt; is also useful for load balancing and routing to manage data flow between your services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqdI26Z3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqdI26Z3.png" alt="Diagram showing microservice architecture, with multiple services connected to a central service mesh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the middle layer in place, you can switch between your new and old services seamlessly. You could also theoretically A/B test the old and new path or roll back if something goes wrong during the migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Build a new service and migrate data
&lt;/h3&gt;

&lt;p&gt;Next, replace the old billing portion of your application with a new microservice. Here’s some code based on this example from Amazon’s &lt;a href="https://aws.amazon.com/getting-started/hands-on/break-monolith-app-microservices-ecs-docker-ec2/module-four/" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt; that uses EC2 and Docker to deploy a billing microservice. &lt;/p&gt;

&lt;p&gt;This task definition creates a new Docker container running on AWS to replace an Oracle ATG &lt;a href="https://docs.oracle.com/cd/E24152_01/Platform.10-1/ATGCommProgGuide/html/s2607setdefaultbillingaddresswebservi01.html" rel="noopener noreferrer"&gt;billing address service&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"containerDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[billing-address-service]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[account-id].dkr.ecr.[region].amazonaws.com/[service-name]:[tag]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"memoryReservation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"portMappings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"hostPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"containerPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"volumes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"networkMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bridge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"placementConstraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[billing-address-service]"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll need to transfer data from your existing monolith’s database to your new microservice’s backend database in most cases. &lt;/p&gt;

&lt;p&gt;For example, the Oracle ATG billing address service described above uses profile data. You can copy this from your Oracle application’s backend to AWS, as demonstrated below.&lt;/p&gt;

&lt;p&gt;This sample code uses Amazon SQS to queue up a series of data transfer jobs. This is critical if you have lots of data to move. Because the process may take a long time, you don’t want a single failed transfer to break the whole process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SendMessageCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//replace with your region&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="na"&gt;DelaySeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;MessageAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// add other fields if you need them, remove what you don’t.&lt;/span&gt;
    &lt;span class="na"&gt;profileId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;543&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;29 Acacia Road, Springfield&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clothing Store Product Data.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SQS_QUEUE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// your queue URL&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SendMessageCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Success, product sent. MessageID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you’ve queued up each row, you need a service to receive and process the data. It will add each row to your new database and delete messages from the queue as they are successfully processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//replace with your region&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqsClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sqsClient&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ReceiveMessageCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;DeleteMessageCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sqsClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./libs/sqsClient.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set the parameters&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queueURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SQS_QUEUE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//Your queue URL&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;AttributeNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SentTimestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;MaxNumberOfMessages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;MessageAttributeNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;queueURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;VisibilityTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;WaitTimeSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReceiveMessageCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;deleteParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;queueURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ReceiptHandle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;ReceiptHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO: Save your data here&lt;/span&gt;
        &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Then delete the queued message&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DeleteMessageCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deleteParams&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message deleted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No messages to delete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// For unit tests.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Receive Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your data is transferred into the new microservice, and you’ve verified it is correct, you can begin testing the new service. If everything works correctly, you can retire part of your monolith and repeat the process with each part of your application.&lt;/p&gt;

&lt;p&gt;Obviously, this migration process varies widely depending on the monolithic e-commerce platform you’re using. Still, hopefully, this gives you a sense of how you can apply the strangler pattern in your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The strangler pattern can help move away from your legacy software platform in a structured, low-risk way. It helps make meaningful improvements quickly without breaking your existing e-commerce store.&lt;/p&gt;

&lt;p&gt;You can thus roll out new features and turn your platform into scalable, robust services that form the core of your e-commerce business. The decoupled nature of microservices lets you use them across multiple channels. &lt;/p&gt;

&lt;p&gt;If you’d like to avoid doing a complete migration yourself, &lt;a href="http://fabric.inc/" rel="noopener noreferrer"&gt;fabric&lt;/a&gt; can help. With industry-leading expertise in e-commerce microservices, they can help you migrate to their suite of e-commerce microservices using a secure, scalable method like the strangler pattern.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Moving from BigCommerce to Microservices-Based E-Commerce</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Fri, 25 Jun 2021 01:53:34 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/moving-from-bigcommerce-to-microservices-based-e-commerce-467j</link>
      <guid>https://forem.com/fabric_commerce/moving-from-bigcommerce-to-microservices-based-e-commerce-467j</guid>
      <description>&lt;p&gt;BigCommerce includes many features and services, but if you want to take every opportunity to engage with your customers, you need a solution of which you’re in complete control.&lt;/p&gt;

&lt;p&gt;There’s no better way to do that than replacing it with microservices. After all, this is &lt;a href="https://resources.fabric.inc/blog/answers/amazon-ecommerce-platform" rel="noopener noreferrer"&gt;the approach Amazon took&lt;/a&gt; to scale and become so successful. You can move one step at a time, adding reusable core components that act as a foundation for multiple frontend sales channels.&lt;/p&gt;

&lt;p&gt;In this post, we’ll discuss replacing BigCommerce with a microservices-based alternative, looking at the reasons for making the change. Then we'll discuss the specifics, along with a few examples of what to do code-wise. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We've written before about migrating away from &lt;a href="https://resources.fabric.inc/blog/answers/enterprise-ecommerce-platforms" rel="noopener noreferrer"&gt;classic e-commerce monoliths&lt;/a&gt; like &lt;a href="https://resources.fabric.inc/blog/salesforce-commerce-to-microservices" rel="noopener noreferrer"&gt;Salesforce Demandware&lt;/a&gt;. As you'll see, many of the same concepts and migration practices apply to modern monoliths like Shopify Plus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Microservices?
&lt;/h2&gt;

&lt;p&gt;Microservices have several advantages over a pre-built, one-size-fits-all solution. &lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Microservices are modular and interchangeable by design. That means your developers can work on them without affecting other parts of your system. It also means you can quickly make and test changes and slot in older or alternate versions of your code. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being able to respond fast and hone in on potential problem areas are key advantages of microservices. By contrast, a large platform may take time to fix holes, and the process of upgrading might be out of your control. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;BigCommerce offers you several templates and has plenty of features, but you are also at the mercy of any changes it makes. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With your own microservices, you can update them when you like. You can choose the fields and data format to work with and decide how your services connect and share information. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can make every decision related to your business yourself. That may seem daunting, but specialists can help, even if you’re using your own solution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Costs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;While BigCommerce is extendable, many of the upgrades aren’t cheap. Even one can significantly add to your costs, and the more you have, the bigger the hit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://thenewstack.io/microservices-pricing-whats-it-all-going-to-cost/" rel="noopener noreferrer"&gt;Estimates suggest&lt;/a&gt; ongoing costs for microservices can drop by up to 90%, and that’s before you factor in the productivity gains for your developers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replacing BigCommerce
&lt;/h2&gt;

&lt;p&gt;BigCommerce’s headless architecture is ideal when shifting to microservices as you can pick and choose what you replace relatively quickly. Furthermore, by taking a modular approach and focusing on one service at a time, you can gradually transition. &lt;/p&gt;

&lt;p&gt;Moving one service at a time makes it easy to identify any issues and roll back any mistakes. If you have trouble with any of your new services, just swap the old one back in, then test and improve the new one until it does what you expect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Decide where to start with the migration
&lt;/h3&gt;

&lt;p&gt;There isn’t a fixed approach to migrating from one platform to another, and you might take several valid routes. Let’s look at some of BigCommerce’s services and decide what to implement using microservices.&lt;/p&gt;

&lt;h4&gt;
  
  
  Product information management (PIM)
&lt;/h4&gt;

&lt;p&gt;Product Information Management is one of the most important tasks in e-commerce, and being able to update and access this data is crucial. BigCommerce has &lt;a href="https://www.bigcommerce.com/apps/product-information-management-pim/" rel="noopener noreferrer"&gt;several apps available&lt;/a&gt; to help with it.&lt;/p&gt;

&lt;p&gt;With microservices, though, you can customize everything from storing the data you need in the format of your choice to making it available to every channel you use. So you aren’t limited to finding the closest fit from a range of options.&lt;/p&gt;

&lt;p&gt;fabric’s &lt;a href="https://resources.fabric.inc/blog/pim-software" rel="noopener noreferrer"&gt;PIM system&lt;/a&gt; gives you a ready-made solution, allowing you to make changes using an intuitive UI and supporting features like multiple product hierarchies, auditing, and one-click migration.&lt;/p&gt;

&lt;h4&gt;
  
  
  Order management system (OMS)
&lt;/h4&gt;

&lt;p&gt;Your order management system needs to handle payments, store the user’s order, and make sure it gets dealt with. In addition, logistical issues, like stock management, need it to run flawlessly.&lt;/p&gt;

&lt;p&gt;BigCommerce has its own OMS with a &lt;a href="https://support.bigcommerce.com/s/article/Order-Management-in-BigCommerce" rel="noopener noreferrer"&gt;defined workflow&lt;/a&gt; and several extensions available in its marketplace.&lt;/p&gt;

&lt;p&gt;Your own OMS will be a crucial component of your business. It will take time to build and to get everything right. But a customized system built to your specifications can make the rest of your business run smoothly and efficiently.&lt;/p&gt;

&lt;p&gt;fabric &lt;a href="https://fabric.inc/oms" rel="noopener noreferrer"&gt;has its own OMS&lt;/a&gt;, and using this as a starting point for your system can save you a lot of time and ensure you nail the basics.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other supporting services
&lt;/h4&gt;

&lt;p&gt;PIM and OMS are essential to nearly all e-commerce businesses. The other services you pick will depend on which of BigCommerce’s capabilities you currently use and want to improve or replace. &lt;/p&gt;

&lt;p&gt;BigCommerce &lt;a href="https://www.websitebuilderexpert.com/ecommerce-website-builders/comparisons/bigcommerce-vs-shopify/" rel="noopener noreferrer"&gt;offers many features&lt;/a&gt; out of the box. You might want to replicate its customer review system or perhaps control user access for your staff.&lt;/p&gt;

&lt;p&gt;If you want to take things slowly, starting with a small, non-essential service can be a great way to get going.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Build a middle layer
&lt;/h3&gt;

&lt;p&gt;As you switch from BigCommerce to your new microservices, you need to make sure the system sends requests to the right place. You can do this with an API Gateway. &lt;a href="https://medium.com/bigcommerce-developer-blog/how-i-built-a-serverless-bigcommerce-app-on-aws-4efe21446bea" rel="noopener noreferrer"&gt;Setting one up&lt;/a&gt; lets you choose which services deal with requests, so you can pick and choose what your new services handle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqdI26Z3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqdI26Z3.png" alt="ECommerce microservice architecture diagram, showing services surrounding central service mesh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Swap out legacy services
&lt;/h4&gt;

&lt;p&gt;Once the middle layer is in place, you can retire old services and add your new ones. You can also swap things back and forth between new and existing services for testing or even filter requests so that some are dealt with by BigCommerce, and some go to your new setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Migrate data from BigCommerce to microservices
&lt;/h3&gt;

&lt;p&gt;When switching over, you’ll need to get your data out of BigCommerce and into your new backend database. It’s easy to export data from BigCommerce: you can &lt;a href="https://support.bigcommerce.com/s/article/Importing-Exporting-Products" rel="noopener noreferrer"&gt;generate a CSV&lt;/a&gt; file that contains everything, or you can pick and choose the fields to export.&lt;/p&gt;

&lt;p&gt;As well as getting the fields out, you need to decide on your new data structure. Will you use identical field names for the fields you want, or will you change them? You may want to allow for additional fields too.&lt;/p&gt;

&lt;p&gt;If you want to extract data from BigCommerce dynamically, you can do that &lt;a href="https://developer.bigcommerce.com/api-reference" rel="noopener noreferrer"&gt;via its APIs&lt;/a&gt;. The latest version of its REST API is three, faster and more efficient, though it doesn’t yet include everything in the older version two. &lt;/p&gt;

&lt;p&gt;There’s also a GraphQL API, though this is &lt;a href="https://developer.bigcommerce.com/api-docs/storefront/graphql/graphql-storefront-api-samples" rel="noopener noreferrer"&gt;still in early access&lt;/a&gt; and feature-incomplete. Being able to build your own full-featured API in any language is one advantage of microservices.&lt;/p&gt;

&lt;p&gt;Let’s look at the data format for &lt;a href="https://developer.bigcommerce.com/api-reference/storefront/carts/cart-items/addcartlineitem" rel="noopener noreferrer"&gt;shopping cart items&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;** Field Name  **&lt;/th&gt;
&lt;th&gt;** Data Type **&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;id&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;customerId&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;email&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;currency&lt;/td&gt;
&lt;td&gt;object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;isTaxIncluded&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;baseAmount&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;discountAmount&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cartAmount&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;coupons&lt;/td&gt;
&lt;td&gt;array[object]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;discounts&lt;/td&gt;
&lt;td&gt;array[object]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lineItems&lt;/td&gt;
&lt;td&gt;object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;createdTime&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;updatedTime&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;locale&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here’s the JavaScript for adding this code to a message queue, adapted from the &lt;a href="https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/sqs-examples-send-receive-messages.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;. You can also find code there to receive the data, which doesn’t need much adaptation.&lt;/p&gt;

&lt;p&gt;I’ve picked out a few attributes from the list above. You can add more, using the same format, or remove any you don’t want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Imports for AWS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SendMessageCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Set this to your region&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;// The parameters, swap in what you need, and out what you don’t&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;DelaySeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;MessageAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;475&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;562567&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;baseAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;79.99&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="na"&gt;discountAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;59.99&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shopping cart information.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SQS_QUEUE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Your queue URL, e.g. 'https://sqs.REGION.amazonaws.com/ACCOUNT-ID/QUEUE-NAME'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SendMessageCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Success, message sent. MessageID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Test and repeat
&lt;/h3&gt;

&lt;p&gt;As you replace each service, you should test thoroughly, making sure everything works correctly. That makes it easier to fix issues, as you can be reasonably sure that they relate to your recent changes. &lt;/p&gt;

&lt;p&gt;Once everything is working, move onto the next service and repeat the process. This iterative, step-by-step approach lets you stay focused and get the right balance between working on new services and putting them through their paces in the real world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Developing a new system yourself allows you to tune everything to your liking. It also lets your developers build the system the way they want and learn how it works as they put it together.&lt;/p&gt;

&lt;p&gt;Taking advantage of existing solutions like BigCommerce also has benefits. It’s cheaper, quicker and many have tested the solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://fabric.inc/" rel="noopener noreferrer"&gt;fabric&lt;/a&gt; specializes in microservices, and its solutions can help you make the switch easily. Its products are API-driven, allowing you to extend fabric core features easily and grow your services as your business expands.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Moving from Shopify Plus to Microservices-Based Commerce</title>
      <dc:creator>James Konik</dc:creator>
      <pubDate>Thu, 13 May 2021 22:01:27 +0000</pubDate>
      <link>https://forem.com/fabric_commerce/moving-from-shopify-plus-to-microservices-based-commerce-ccd</link>
      <guid>https://forem.com/fabric_commerce/moving-from-shopify-plus-to-microservices-based-commerce-ccd</guid>
      <description>&lt;p&gt;If you’re selling products online, there’s a good chance you’re using a one-size-fits-all platform. These platforms offer many advantages but they also have limitations. If you want to move beyond these limitations, &lt;a href="https://resources.fabric.inc/blog/answers/ecommerce-microservices-architecture" rel="noopener noreferrer"&gt;microservices&lt;/a&gt; can help.&lt;/p&gt;

&lt;p&gt;Shopify Plus is a one-size-fits-all platform that allows you to use headless systems while retaining most of its features. So if you already have a Shopify Plus setup, you can keep the frontend and migrate the backend to a microservices-based alternative for more flexibility.&lt;/p&gt;

&lt;p&gt;In this post, we'll explain why businesses are moving away from monolithic e-commerce platforms like Shopify Plus and how they are doing it from a high level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We've written before about migrating away from &lt;a href="https://resources.fabric.inc/blog/answers/enterprise-ecommerce-platforms" rel="noopener noreferrer"&gt;classic e-commerce monoliths&lt;/a&gt; like &lt;a href="https://resources.fabric.inc/blog/salesforce-commerce-to-microservices" rel="noopener noreferrer"&gt;Salesforce Demandware&lt;/a&gt;. As you'll see, many of the same concepts and migration practices apply to modern monoliths like Shopify Plus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Microservices?
&lt;/h2&gt;

&lt;p&gt;Shopify is a fantastic system in many ways, but if you use it exclusively you have to accept its limitations. Moving all or part of your system away from it can avoid these problems. Let’s look at some of the areas microservices can improve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Shopify has &lt;a href="https://techcrunch.com/2020/09/23/shopify-data-merchant-breach/" rel="noopener noreferrer"&gt;been in the news&lt;/a&gt; regarding data theft before. Managing your services means you’re free to address those concerns and implement additional security.&lt;/li&gt;
&lt;li&gt;  Its fraud protections aren’t as comprehensive as some services, so moving to a different payment system that matches your requirements can give you and your customers peace of mind.&lt;/li&gt;
&lt;li&gt;  Working with APIs means you can control the data flow in and out of your backend. It also means you can develop it incrementally while building on what you already have. That means you don’t have to reinvent the wheel when you want to offer something new on the frontend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  One issue with Shopify Plus is its &lt;a href="https://paulnrogers.com/shopify-plus-international-multi-store/" rel="noopener noreferrer"&gt;lack of multi-store architecture&lt;/a&gt;, though this feature has been promised in the future and some plugins may help with it. If you can’t wait, you can build a backend that can handle data across all your outlets.&lt;/li&gt;
&lt;li&gt;  Shopify Plus's SEO approach is good but hard to modify. Using a custom frontend can allow you to change the URL structure, the robots.txt file, and give you better control over your subdomains.&lt;/li&gt;
&lt;li&gt;  It’s a similar situation with Shopify’s checkout. It’s hard to customize, leaving you with a fixed approach. What’s there isn’t bad; it’s just that you can’t deviate from it significantly or add specific features easily.&lt;/li&gt;
&lt;li&gt;  Shopify Plus can also slow down as you add features; its &lt;a href="https://weareuv.com/shopify-vs-salesforce-commerce-cloud-which-one-should-i-choose/" rel="noopener noreferrer"&gt;plugins don’t have to be certified&lt;/a&gt;. Handling services independently means you can ensure they continue to perform at the level you require.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Shopify allows you to get up and running quickly, but you’re tied into the way it does things. With microservices, you can take a &lt;a href="https://resources.fabric.inc/blog/glossary/modular-commerce" rel="noopener noreferrer"&gt;modular approach&lt;/a&gt;, get the essentials in place, and add whatever you need on top.&lt;/li&gt;
&lt;li&gt;  Shopify apps aren’t always geared to work well internationally and can cost a lot if you have multiple local versions of your store. Data for multiple stores is also tricky to combine.&lt;/li&gt;
&lt;li&gt;  Shopify payments can have restrictions for products, as well as countries and currencies. You need a local business and bank account in each territory you have a store. That makes changing and expanding difficult.&lt;/li&gt;
&lt;li&gt;  With microservices, you can add an API query doing whatever it is you need—you aren’t limited to what Shopify offers. If you need to support a new feature, you can do that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replacing Shopify Plus
&lt;/h2&gt;

&lt;p&gt;You can take advantage of the modularity of microservices to move from Shopify bit by bit. Identify what you can benefit most from replacing and build it. If you do that repeatedly, you can move away from Shopify step by step, improving your service with minimal disruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Decide Where to Start the Migration
&lt;/h3&gt;

&lt;p&gt;Let’s look at some of Shopify Plus’s services and decide what to implement using microservices.&lt;/p&gt;

&lt;h4&gt;
  
  
  Product Information Management (PIM)
&lt;/h4&gt;

&lt;p&gt;Your Shopify installation will include lots of product-specific data. Moving this to a separate backend, with an API letting you retrieve, modify, and create new products, is a great place to start.&lt;/p&gt;

&lt;p&gt;Decoupling this data from Shopify means you can use it on any of the new channels you create. It gives you complete control over what’s shared, and the formatting and structure can be defined however you like.&lt;/p&gt;

&lt;p&gt;Fabric has a &lt;a href="https://fabric.inc/pim" rel="noopener noreferrer"&gt;prebuilt PIM system&lt;/a&gt; that will help you make the transition quickly and easily and offers you plenty of flexibility. As well as helping you get set up, Fabric can also help with data migration.&lt;/p&gt;

&lt;h4&gt;
  
  
  Order Management System (OMS)
&lt;/h4&gt;

&lt;p&gt;Your order management system includes your user’s shopping cart as well as payments. You have to smoothly pass the data on to your payment handler and delivery setup while allowing users to track and potentially cancel the whole process. There’s a lot involved, and everything needs to run like clockwork.&lt;/p&gt;

&lt;p&gt;Taking control of this area means you can evolve it over time and perfect everything, adding features for the various frontend services you want to use while ensuring the core functionality is rock-solid.&lt;/p&gt;

&lt;p&gt;Fabric can help with this, too. Its &lt;a href="https://fabric.inc/oms" rel="noopener noreferrer"&gt;OMS&lt;/a&gt; promises a friction-free experience that can drive customer satisfaction and make life easier for everyone involved in your order and delivery chain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other Supporting Services
&lt;/h4&gt;

&lt;p&gt;Shopify Plus offers a whole suite of features and services. Some of these will matter to you more than others—priorities differ from business to business. When picking a feature to include, you should consider what you’d like to make available to channels other than Shopify and which areas have the most scope for improvement.&lt;/p&gt;

&lt;p&gt;These might include store management, customer personalization, or analytics. Take a look at the features &lt;a href="https://fabric.inc/products" rel="noopener noreferrer"&gt;Fabric offers&lt;/a&gt; to see what it can do for you in those areas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Build a Middle Layer
&lt;/h3&gt;

&lt;p&gt;To integrate your new services with your Shopify installation, you can set up an &lt;a href="https://www.shopify.com/partners/blog/shopify-webhooks-how-to-prep-your-app-this-black-friday-cyber-monday" rel="noopener noreferrer"&gt;API gateway&lt;/a&gt;. That will let you reroute requests to your new backend.&lt;/p&gt;

&lt;p&gt;You could also adopt a &lt;a href="https://resources.fabric.inc/blog/ecommerce-service-mesh" rel="noopener noreferrer"&gt;service mesh&lt;/a&gt; model, which handles communication between your application components and lets you manage data flow between your existing application and external microservices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fresources.fabric.inc%2Fhs-fs%2Fhubfs%2FE-commerce%2520microservice%2520architecture%2520with%2520service%2520mesh.png%3Fwidth%3D886%26name%3DE-commerce%2520microservice%2520architecture%2520with%2520service%2520mesh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fresources.fabric.inc%2Fhs-fs%2Fhubfs%2FE-commerce%2520microservice%2520architecture%2520with%2520service%2520mesh.png%3Fwidth%3D886%26name%3DE-commerce%2520microservice%2520architecture%2520with%2520service%2520mesh.png" alt="E-commerce microservice architecture with service mesh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a new layer in place, you can look at replacing services one by one, thoroughly testing at each stage, and ensuring the new process is fully integrated before moving on to the next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Migrate Data from Shopify Plus to Microservices
&lt;/h3&gt;

&lt;p&gt;To move data from your old system, you can export it to a CSV file, then use JavaScript to shift it across to your new microservice. You can do this as you go, create a service, copy your data into it, and then adjust your API gateway to handle future requests from Shopify.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exporting Data from Shopify Plus
&lt;/h4&gt;

&lt;p&gt;Shopify Plus has a simple export system, letting you easily create a CSV file. Its &lt;a href="https://help.shopify.com/en/manual/shopify-admin/duplicate-store" rel="noopener noreferrer"&gt;documentation explains&lt;/a&gt; how to do this for a product, customer, and order data, among other things. You can find an &lt;a href="https://help.shopify.com/en/manual/products/import-export/using-csv" rel="noopener noreferrer"&gt;example file here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shopify product data includes the following fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Required but can be blank&lt;/th&gt;
&lt;th&gt;Optional&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Handle&lt;/td&gt;
&lt;td&gt;Body&lt;/td&gt;
&lt;td&gt;SEO Title&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Title&lt;/td&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;SEO Description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Published&lt;/td&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Google shopping metafields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;Tags&lt;/td&gt;
&lt;td&gt;Cost per item&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Image Src&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Image Position&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Image Alt Text&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Gift Card&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are more fields for products that have additional options and variants. &lt;a href="https://help.shopify.com/en/manual/products/import-export/using-csv" rel="noopener noreferrer"&gt;Consult the documentation for details&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your new system won’t have to use the same fields, so you can pick and choose which are relevant to you and which, if any, are required in your system. That kind of flexibility is one of the advantages of working with microservices. You can have a compact, faster system or one that contains whatever extra information you need.&lt;/p&gt;

&lt;h4&gt;
  
  
  Importing Data into Microservices
&lt;/h4&gt;

&lt;p&gt;You can use JavaScript to transfer your data into your new system. Here’s an example showing how to import data using the latest version of &lt;a href="https://aws.amazon.com/sqs/" rel="noopener noreferrer"&gt;Amazon SQS&lt;/a&gt;. You can find more details in &lt;a href="https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/sqs-examples-send-receive-messages.html" rel="noopener noreferrer"&gt;Amazon’s documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SendMessageCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//or whatever your region is&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="na"&gt;DelaySeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;MessageAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sneakers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;Vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comfy Sneakers Inc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;InventoryQty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;146&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;79.99&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Product Data.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SQS_QUEUE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//replace this with your queue URL&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SendMessageCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Success, product sent. MessageID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Test and Repeat
&lt;/h3&gt;

&lt;p&gt;As you expand your microservices and move functionality away from Shopify, it’s essential to test thoroughly. This should be done at every stage. You need to have a rigorous testing system to ensure everything is still working smoothly, including the area being moved and everything else.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advantages of the Iterative Approach
&lt;/h4&gt;

&lt;p&gt;Taking a section by section approach means you can focus on a particular service and know where to look should any problems arise. That makes issues easier to fix and the overall adjustment smoother.&lt;/p&gt;

&lt;p&gt;In addition to finding errors, it’s helpful to have metrics that measure the speed of transactions. If you can connect these to sales and customer retention, all the better. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Shopify Plus is an excellent platform with much to like about it, but the world is moving away from one-size-fits-all software toward more flexible, customized solutions.&lt;/p&gt;

&lt;p&gt;Building services yourself is very achievable, but there is plenty of support available so you don’t have to go it alone entirely. An existing solution can save you time and money, and, as these services mature, the argument for that route gets stronger.&lt;/p&gt;

&lt;p&gt;Consider taking advantage of prebuilt or customized microservices with &lt;a href="http://fabric.inc/" rel="noopener noreferrer"&gt;Fabric&lt;/a&gt; to quickly build a system that offers adaptability for new challenges and opportunities based on solid, reusable foundations.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
