<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[StackAdapt Tech Blog - Medium]]></title>
        <description><![CDATA[StackAdapt is a leader in AdTech handling billions of ad requests every day. This blog shares the experiences of their technology team in building a scalable, high performance DSP with world class user experience and AI. - Medium]]></description>
        <link>https://stackadapt.tech?source=rss----20d84872b28e---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>StackAdapt Tech Blog - Medium</title>
            <link>https://stackadapt.tech?source=rss----20d84872b28e---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 12 Apr 2026 16:53:46 GMT</lastBuildDate>
        <atom:link href="https://stackadapt.tech/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[StackHack: Powering Bottom-Up Innovation]]></title>
            <link>https://stackadapt.tech/stackhack-powering-bottom-up-innovation-9e93dddb9c8b?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/9e93dddb9c8b</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[hackathons]]></category>
            <category><![CDATA[stackadapt]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Julia Ren]]></dc:creator>
            <pubDate>Tue, 03 Feb 2026 01:20:12 GMT</pubDate>
            <atom:updated>2026-02-03T01:20:11.345Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This article was co-authored by Julia Ren and Max Woghiren.</em></p><h3>StackHack</h3><p>Since 2022, StackAdapt has hosted our annual internal hackathon, StackHack, during our December code freeze. StackHack has become a massive driver for bottom-up innovation and cross-team collaboration, and it has emerged as a marquee event featuring prizes, awards, and swag, and a judging panel including our CEO, Vitaly Pecherskiy, CTO, Yang Han, and Engineering SVP, Tishan Mills.</p><p>StackAdapt is a remote-first company, so StackHack makes sure to accommodate all of our employees, but for those near our hub in Toronto, the event culminates in a full-blown closing ceremony and on-site social!</p><h3>More Than Just a Fun Event</h3><p>StackHack is more than just a fun event. For one, the hackathon strongly embodies our <a href="https://www.stackadapt.com/careers#site-values-anchor-link">recently-updated values</a>. For instance, we get a chance to <strong>walk in our customer’s shoes</strong>, with many of our ideas focused directly on addressing our users’ pain points. We <strong>operate like underdogs</strong> during StackHack, with humility and ambition. Many of our hackathon teams bring together StackAdapters from a variety of teams…<strong>we only win together</strong>!</p><p>Beyond exemplifying our company’s values, StackHack provides opportunities for StackAdapters to explore and sharpen skills they don’t get to exercise regularly. Everyone has an opportunity to take on leadership and product/project management roles, put together mocks and designs, and fire up an IDE.</p><p>StackHack also gives StackAdapters the opportunity to explore emerging technologies. 2025 was another year of AI, and this buzz inspired some of our hackathon themes (which doubled as award categories), including <strong>Best Asset Auto Creation </strong>and <strong>Best GenAI Integration</strong>.</p><p>Every year, the hackathon inspires a wave of innovation. It shapes our roadmap and empowers StackAdapters across the company to directly and tangibly contribute to the company’s direction. While only selected projects win, it’s always a joy to see how many hacks were approved to be added to our product roadmap for the following year. The momentum is real!</p><figure><img alt="StackHack award ceremony for in-person participants." src="https://cdn-images-1.medium.com/max/1024/1*0kFPBHfi7f-1kL44vmtlJA.jpeg" /><figcaption>StackHack award ceremony for in-person participants.</figcaption></figure><h3>Looking Back at StackHack 2024</h3><p>In 2024, we had <strong>10 projects</strong> begin official development, many of which were added to our product and released. <strong>Transforming Ad Targeting with AI-Powered Precision</strong> is a shipped project that uses Generative AI to supercharge polygon targeting, a type of precise geographic targeting. Here is what the project team (kudos to Aamir, Hassaan, Mavelyn, and Ros!) pitched:</p><blockquote>Imagine transforming a request like “Target all independent coffee shops in Toronto’s Entertainment District within 2.5km of Rogers Centre, excluding major chains like Starbucks” into optimized polygon clusters in seconds. Using generative AI and machine learning, we will create a precise and scalable solution tailored to the platform.</blockquote><p>Not all hackathon projects need to be complex. Sometimes, huge impact comes from small changes. One of our sharpest engineers, Yuya, noticed the StackAdapt loading spinner was a legacy <strong>GIF</strong> contributing to <strong>~95% of our index.html </strong>file size, and to top it off, this file cannot be cached locally. Yuya took care of this by redesigning the spinner using nothing but beautiful, light-as-a-feather <strong>CSS</strong>!</p><h3>A Look at StackHack 2025</h3><p>Following StackHack 2025, <strong>14 projects</strong> were promptly green-lit and added to our 2026 roadmap.</p><p>Many of these ideas align with our emphasis on responsibly leveraging AI to better serve our users. One of the award-winning projects, <strong>Creative Intelligence</strong>, explored the application of AI into the creation and curation of the ads themselves. Incorporating this into our core offering has massive potential to improve our users’ results. Given the fast-moving nature of AI, it is essential to build proofs-of-concepts and swiftly integrate them into our current product offerings.</p><p>As with 2024, however, we had plenty of high-impact projects that weren’t necessarily complex. One award-winning hack explored upgrading TypeScript across our code, outlining the difficulty and measuring impact. Perhaps less glamorous than AI, but exploring the nuts and bolts of our coding environments is hugely beneficial, and we’re proud to recognize these kinds of projects in our judging.</p><figure><img alt="StackHack opening ceremony for in-person participants." src="https://cdn-images-1.medium.com/max/1024/1*pIjLvEgeHRg_uTIBi9C_EA.jpeg" /><figcaption>StackHack opening ceremony for in-person participants.</figcaption></figure><h3>Lessons Learned</h3><p>We’re fortunate that StackAdapt champions bottom-up innovation and advocates for company-wide hackathons. Of course, we didn’t nail everything on the first try. Iteration isn’t just for software; it’s for events too. Here are some valuable lessons we’ve learned over the years.</p><h4>Broaden the scope</h4><p>We moved from narrow, platform engineering-specific categories to open-ended themes. This encouraged participants from all departments to find their own problems to solve, leading to more diverse innovation.</p><h4>Provide access to necessary resources</h4><p>An engineer is only as good as their tools! We provide temporary elevated AWS access, API keys, and OpenAI tokens upfront, ensuring no one is blocked by permissions. We also learned that cleanup is vital. To avoid any unwelcome billing surprises or security risks after the hackathon, we make sure to deactivate any temporary resources allocated during the event.</p><h4>Be flexible</h4><p>To accommodate 30+ teams and remote participants, we introduced the option to pre-record presentations or present live. This kept the last day on schedule and better accommodated for different presentation styles, all while giving everyone a moment in the spotlight!</p><figure><img alt="StackHack presentation day for in-person participants." src="https://cdn-images-1.medium.com/max/1024/1*_EeVYGiRx1Ibf-S8yoXTow.jpeg" /><figcaption>StackHack presentation day for in-person participants.</figcaption></figure><h3>Raising the Bar: StackHack 2026 and Beyond</h3><p>This was StackHack’s fourth year, and it’s been a great opportunity for us to live out our values, try out new roles in the development cycle, explore new tech, and actively contribute to our company roadmap. It has become a cornerstone of development at StackAdapt, and it continues to grow and improve. We’re already excited to <strong>raise the bar</strong> for a bigger and better next edition!</p><p>Ready to turn your passion project into a paid reality? Want to have some productive fun with your fellow coworkers near the holiday season? If you have innovative ideas and the skills to execute them, StackAdapt is the place for you.</p><p><a href="https://www.stackadapt.com/careers/engineering"><em>Apply today</em></a><em> and we’ll see you at StackHack 2026!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9e93dddb9c8b" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/stackhack-powering-bottom-up-innovation-9e93dddb9c8b">StackHack: Powering Bottom-Up Innovation</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GenAI for Ad Creatives]]></title>
            <link>https://stackadapt.tech/genai-for-ad-creatives-84127a997ba0?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/84127a997ba0</guid>
            <category><![CDATA[ad-tech-industry]]></category>
            <category><![CDATA[video-diffusion-models]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[video-ad-creatives]]></category>
            <category><![CDATA[generative-ai-use-cases]]></category>
            <dc:creator><![CDATA[Abhishek Tanpure]]></dc:creator>
            <pubDate>Thu, 16 Jan 2025 18:48:54 GMT</pubDate>
            <atom:updated>2025-01-16T18:48:54.800Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TOu0-epCjthgCB2xRrmwYw.png" /></figure><p>The advertising landscape is undergoing a remarkable transformation, largely driven by advancements in generative AI (GenAI). By automating creative tasks, optimizing performance, and enabling hyper-personalization, GenAI is helping brands produce captivating, cost-effective campaigns at scale. As brands and marketers increasingly adopt these technologies, they are discovering new ways to engage consumers and enhance their creative processes. In this blog, we delve into the latest technical advancements and how they’re revolutionizing video ad production.</p><h3>Generative AI in Advertising</h3><p>Generative AI refers to a subset of artificial intelligence that focuses on creating new content. This can include text, images, videos, and more. By leveraging large datasets and sophisticated algorithms, GenAI can generate content that is not only high-quality but also tailored to specific audiences. This capability is particularly valuable in advertising, where personalized and engaging content can significantly impact campaign success.</p><p>One of the key benefits of GenAI is its ability to automate the creative process. Traditional ad creation can be time-consuming and resource-intensive, requiring input from multiple creative professionals. GenAI streamlines this process by generating content quickly and efficiently, allowing brands to produce more campaigns in less time. Additionally, GenAI can optimize ad performance by analyzing data and making real-time adjustments to improve engagement and conversion rates.</p><h3>Diffusion models</h3><p>Diffusion models are a type of generative model known for their ability to create high-quality visual and video content. These models are particularly useful in video ad production, where realism and visual appeal are crucial. The core idea behind diffusion models is to start with simple, easily generated data — often random noise — and gradually refine it into complex, realistic outputs. This process involves a series of steps that simulate the evolution of data, allowing the model to generate new samples that closely resemble the original training data.</p><h4>1. Overview of Diffusion Models</h4><p>Diffusion models are based on a process of iteratively denoising data. This involves:</p><ul><li>Forward Diffusion Process: In this step Gaussian noise is progressively added to data (e.g., an image) over multiple steps until the data becomes completely noisy and unrecognizable.</li><li>Reverse Diffusion Process: Starting from the noisy data, the model is made to learn to reverse the noise step-by-step and reconstruct the original data distribution. This is done using a neural network trained to predict noise at each timestep.</li></ul><p>Compared to traditional generative models like GANs (Generative Adversarial Networks), diffusion models often produce superior image quality and coherence. They are less prone to overfitting due to their structured approach to generating data. This makes them particularly effective for applications where high fidelity and consistency are important.</p><h4>2. Video Diffusion Models</h4><p>Recent advancements have extended diffusion models to video generation. <a href="https://video-diffusion.github.io/">Ho et al</a> introduced a framework for video generation that is an extension of the existing image generation architectures. This architecture allows for both unconditional and conditional video generation, achieving state-of-the-art results in sample quality. This model generates videos in blocks of fixed frames, which can then be combined to create longer sequences.</p><p>The conditioning technique enhances the model’s ability to generate videos based on specific prompts or inputs. This means that the model can create videos that follow a particular storyline or respond to user-defined criteria, making it highly versatile for various applications, including targeted advertising and personalized content creation. The ability to conditionally generate videos opens up new possibilities for creating customized and engaging video ads that can capture the viewer’s attention more effectively.</p><p>As brands seek to leverage GenAI for video content, significant advancements have emerged. Meta’s introduction of MarDini, a next-generation video diffusion model, exemplifies this trend. MarDini offers advanced capabilities for video generation, including seamless frame interpolation and dynamic scene creation. It specifically uses Masked Autoregressive (MAR) Techniques which allows for flexible handling of various video tasks, such as interpolating frames or converting images into videos.</p><h4>3. Key Innovations in Diffusion Models</h4><p>Recent advancements in diffusion models have made them particularly well-suited for creative tasks like video generation:</p><ul><li>Guided Diffusion: Techniques like <a href="https://openaccess.thecvf.com/content/CVPR2022/papers/Kim_DiffusionCLIP_Text-Guided_Diffusion_Models_for_Robust_Image_Manipulation_CVPR_2022_paper.pdf">CLIP-guided diffusion</a> integrate text prompts or class labels to control the output generation, allowing for highly specific and creative results.</li><li>Improved Noise Schedules: Models like <a href="https://arxiv.org/abs/2010.02502">DDIM</a> (Denoising Diffusion Implicit Models) reduce the number of reverse steps while maintaining quality, speeding up the generation process.</li><li>Temporal Consistency in Video: For video content, diffusion models maintain <a href="https://openaccess.thecvf.com/content/CVPR2024/papers/Zhou_Upscale-A-Video_Temporal-Consistent_Diffusion_Model_for_Real-World_Video_Super-Resolution_CVPR_2024_paper.pdf">temporal coherence across frames</a> by conditioning generation on previous frames, ensuring smooth transitions​.</li></ul><h4>3. Applications in Video Ad Creatives</h4><ul><li>Video Super-Resolution: Diffusion models upscale low-resolution videos while adding realistic details.</li><li>Video Generation from Text Prompts: Models like RunwayML’s Gen-2 use diffusion principles to generate entire video sequences from simple textual descriptions.</li><li>Style and Content Control: Users can control aesthetics (e.g., color grading or animation styles) by guiding diffusion with reference images or specific attributes​</li></ul><p>Integrating diffusion models into generative AI workflows enhances the overall creative potential of tools used for advertising. Below, we explore broader applications and advancements in generative AI for ad creatives.</p><h3>Personalized and Localized Ad Content</h3><p>AI can adapt video scripts to specific languages and even synchronize localized audio with realistic lip movements using AI video dubbing. This creates tailored ads for global markets without expensive manual work​. GenAI tools use demographic data to tweak ad visuals, such as background colors, text placements, and image overlays, ensuring relevance to the target audience</p><h3>Creative Content Generation with AI</h3><p>Emerging platforms like Runway and Sora can transform simple textual prompts into engaging video sequences, making video creation accessible to everyone. Adobe Premiere Pro integrates AI tools like Pika to extend shot durations and enhance videos with seamless 3D effects, such as parallax movements, perfect for immersive ads.</p><p>Amazon Nova Reel significantly enhances the ability of brands and influencers to create high-quality video content for social media platforms. By leveraging natural language prompts, users can effortlessly generate visually appealing videos that capture audience attention, drive engagement, and increase reach. The built-in safety features, such as watermarking and content moderation, ensure responsible use and maintain the integrity of the content shared across social media channels.</p><p>Veo 2 stands out for its ability to generate longer clips — over two minutes — while maintaining exceptional quality. Users can easily customize their videos by specifying angles and styles, allowing for a high degree of creative control. With its advanced understanding of cinematography, Veo 2 not only enhances the visual experience but also empowers creators to bring their unique visions to life in ways that were previously unimaginable.</p><h3>Automated Video Resizing and Multi-Platform Adaptation</h3><p>Tools like Meta’s Image Expansion automatically optimize video dimensions for different feeds and screens, saving hours of manual editing. AI-based tools analyze the focal point of a video and ensure key elements remain intact across all formats, maintaining the creative’s integrity while improving usability.</p><h3><strong>Opportunities and Challenges</strong></h3><p>There, however, notable pitfalls of generative AI that brands must navigate. One significant concern is the lack of clarity around copyright and ownership, which has hindered broader adoption of generative AI in marketing. Many companies worry about potential intellectual property violations when using AI-generated content. To address these issues, platforms like Amazon’s Titan and Adobe’s models emphasize training on licensed data and implementing watermarking solutions, which could provide a pathway to mitigate copyright concerns. Additionally, ethical considerations such as bias and fairness in AI outputs remain critical challenges that need ongoing attention to ensure responsible use in advertising.</p><h3>Conclusion</h3><p>The integration of generative AI, particularly diffusion models, into advertising is transforming the creative landscape. By automating and optimizing the creative process, GenAI enables brands to produce high-quality, personalized content at scale. As these technologies continue to evolve, they will unlock new possibilities for engaging consumers and driving campaign success. Brands that embrace these advancements will be well-positioned to lead in the competitive world of digital advertising.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=84127a997ba0" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/genai-for-ad-creatives-84127a997ba0">GenAI for Ad Creatives</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[In-app Advertising and SKAdNetwork]]></title>
            <link>https://stackadapt.tech/in-app-advertising-and-skadnetwork-ffb871d231d8?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/ffb871d231d8</guid>
            <category><![CDATA[data-privacy]]></category>
            <category><![CDATA[in-app-ads]]></category>
            <category><![CDATA[skadnetwork]]></category>
            <category><![CDATA[programmatic-advertising]]></category>
            <category><![CDATA[mobile-app-marketing]]></category>
            <dc:creator><![CDATA[Frank Yan]]></dc:creator>
            <pubDate>Tue, 27 Jun 2023 20:46:51 GMT</pubDate>
            <atom:updated>2023-06-28T19:36:45.487Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Image showing crowd attribution for mobile ads" src="https://cdn-images-1.medium.com/max/1024/0*voVLFKKsjyDCHZoQ" /><figcaption>Image showing crowd attribution for mobile ads</figcaption></figure><p>In-app advertising is a revenue stream for mobile apps to leverage their real-estate to show ads to their users. In other words, ad buyers pay them for displaying ads within their app.</p><p>Genres such as Gaming, Social, Utility, and Entertainment rely heavily on IAA (In-App Advertising).</p><p>In 2022, users on average spent 5 hours on their phones and mobile app ad spend surpassed $336 billion. The trend of consumer time and transactions in apps continues to grow, with projections that the market will reach an <a href="https://www.data.ai/en/insights/market-data/2023-mobile-forecast/">estimated $362 billion in 2023</a>.</p><p>Let’s explore how you can develop a strong capability to execute on app install and in-app conversion campaigns for both Android and IOS. Below, we will go through in-app advertising for iOS and the SKAdNetwork framework.</p><h3>What is SKAdNetwork</h3><p>StoreKit Ad Network, otherwise known as SKAdNetwork or SKAN, is Apple’s API-based, privacy-centric framework for attribution and ad measurement. It provides aggregated ad activity measurements to advertisers with no user level data.</p><p>Post iOS 14.5 release, users have the choice to opt out from any app tracking their user level data via Apple’s Identifier for Advertisers, also known as the ATT framework (App Tracking Transparency). SKAdNetwork became the only way for advertisers to measure the success of ad campaigns while maintaining user privacy.</p><h3>How Does SKAdNetwork Work</h3><p><strong>SKAdNetwork leverages </strong>3 main components:</p><ol><li>Ad network: signs ads and receives install-validation postbacks after ads result in conversions.</li><li>Publishing app: the app that displays the ad.</li><li>Advertised app: the app being advertised.</li></ol><p><strong>There are </strong>2 types of ad engagements:</p><ol><li>Views: ad shown for at least 3 seconds.</li><li>StoreKit renders (a miniature version of the advertised app page from the app store): There is an engagement rule that controls when the storekit renders, for example when the user clicks on the ad.</li></ol><p>SKAdNetwork Flow:</p><figure><img alt="SKAdNetwork flow diagram" src="https://cdn-images-1.medium.com/max/1024/0*-sEAJd30mKjV2nej" /><figcaption>SKAdNetwork flow diagram</figcaption></figure><p>When an ad is clicked and the store is opened, the publishing app and the network provide it with some basic information such as ad network, publisher, and campaign ID. The app store will then send a notification of successful conversion to the ad network.</p><p>If the user launches the app within an attribution time-window, the ad impression is eligible for install-attribution postbacks. The attribution time-window can be up to 35 days depending on the ad type. As the user engages with the app, the app updates the conversion value.</p><p>SKAdNetwork postbacks are delayed by a minimum of 24 hours, making sure to not tie the install to a specific user, thus preserving privacy.</p><h3>Challenges</h3><ol><li><strong>No real ROI: </strong>SKAN provides a very limited set of data, mostly on installs, conversion values and post-install.</li><li><strong>Limited granularity: </strong>No device or creative-level data, only allows up to 100 campaigns and six bits of post-install conversion data.</li><li><strong>Hard to optimize campaigns immediately: </strong>The postback delay makes it very hard to make decisions in a short amount of time.</li><li><strong>No re-engagement attributions: </strong>No device or user-level data is collected or shared, thus it’s impossible to target users for re-engagement.</li></ol><h3>SKAdNetwork 4.0 (SKAN 4.0)</h3><p>On October 24, 2022, Apple released the next version of SKAdNetwork (4.0), which introduces significant changes that allow advertisers and ad networks to measure more while maintaining user privacy. At StackAdapt, we are using SKAN 4.0.</p><h3>Here are the benefits of using SKAN 4.0:</h3><ol><li><strong>Three postbacks instead of one: </strong>Advertisers can now receive up to 3 postbacks, each based on a specific activity window (0–2 days, 3–7 days and 8–35 days). This allows advertisers to understand how users engage with their app over time.</li><li><strong>LockWindow: </strong>Developers have the ability to lock the measurement window in a specific window to stop conversion measurements in order to receive postbacks sooner.</li><li><strong>Crowd anonymity: </strong>Conversion values are split into 3 types: low, medium, or high. Postbacks contain masked conversion values when crowd anonymity is low, when crowd anonymity is medium, a coarse value is returned, and a fine grained conversion value is only returned when crowd anonymity is high.</li><li><strong>Web-to-app support: </strong>In SKAN 4.0, web-to-app attribution for Safari is also supported.</li></ol><p>Image showing crowd anonymity based on campaign, location and placement:</p><figure><img alt="Image showing crowd anonymity based on campaign, location and placement" src="https://cdn-images-1.medium.com/max/1024/0*QDd7bfjHo_BOb_8m" /><figcaption><strong><em>Source: Apple’s </em></strong><a href="https://developer.apple.com/videos/play/wwdc2022/10038"><strong><em>What’s new with SKAdNetwork — WWDC22</em></strong></a><strong><em> video</em></strong></figcaption></figure><h3>Summary</h3><p>As the advertising industry continues to adapt a privacy-centric reality, it is important for us to understand the benefits and limitations of using different frameworks, and to create a more innovative ecosystem to make the most of them.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-career-path"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ffb871d231d8" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/in-app-advertising-and-skadnetwork-ffb871d231d8">In-app Advertising and SKAdNetwork</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Natural Language Processing in Contextual Advertising]]></title>
            <link>https://stackadapt.tech/natural-language-processing-in-contextual-advertising-63509f982bf0?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/63509f982bf0</guid>
            <category><![CDATA[programmatic-advertising]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[naturallanguageprocessing]]></category>
            <category><![CDATA[data-scientist]]></category>
            <dc:creator><![CDATA[Panteha Naderian]]></dc:creator>
            <pubDate>Wed, 19 Apr 2023 19:45:02 GMT</pubDate>
            <atom:updated>2023-04-21T12:58:14.770Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Graphic showing an example of an ad on a mobile phone powered by StackAdapt." src="https://cdn-images-1.medium.com/max/1024/1*sOhonDgIf-T4wUCPfaJDzw.png" /><figcaption>Graphic showing an example of an ad on a mobile phone powered by StackAdapt.</figcaption></figure><p>Contextual advertising models analyze the content on web pages and determine where to place the most suitable and relevant ads on websites. The primary assumption behind contextual advertising is that users consume content on topics they are interested in. For example, if a user is reading about the latest fashion trends in high heel shoes, then it’s likely that they are interested in purchasing a new pair of shoes. <a href="https://www.mediapost.com/publications/article/383059/subterranean-context-shoppers-prefer-ads-related.html?utm_source=newsletter&amp;utm_medium=email&amp;utm_content=headline&amp;utm_campaign=129462&amp;hashid=PFQn8SGnQCKEgKx1XJL6JQ">Studies</a> have shown that people engage far more frequently with ads that appear in relevant contexts. Furthermore, with the rise of privacy concerns around browser cookies, it has become imperative for DSPs to invest in contextual advertising.</p><p>The central technology behind contextual advertising is natural language processing (NLP). This technology helps to better model content found on a web page and work with a bidding algorithm to ensure that a DSP wins the auction to place relevant ads in high-quality context.</p><p>At StackAdapt, we regularly explore the latest, natural-language processing techniques, and with recent technological approaches, including transformers, large pre-trained models, and few-shot learners, the sky’s the limit.</p><p>Below, I explore three NLP publications that can potentially be useful in building contextual targeting models:</p><p><a href="https://aclanthology.org/2022.emnlp-main.619.pdf"><strong>Intriguing Properties of Compression on Multilingual Models</strong></a></p><p>Multilingual models are powerful tools that can analyze and operate across several languages, eliminating the need to train separate models for each language. This approach offers several attractive benefits, including higher performance on low-resource languages, reduced maintenance, and cost savings. This can specifically be helpful in contextual advertising as it significantly accelerates the process of expanding to new languages and countries.</p><p>This paper investigates the impact of compression and sparsification on multilingual models. We know that with larger size and increased parameters of multilingual models, it’s increasingly more challenging to deploy on resource-constrained environments. Specifically, the authors focus on pruning sparsification methods in which all weights lower than a pre-specified threshold are eliminated from the model.</p><p>The study experimented with various compression parameters, revealing some interesting insights. First, low-resource languages typically suffer from lower performance with extreme sparsification; however, medium-range compressions may improve their performance. Second, it’s possible that sparsification can improve robustness by reducing overfitting.</p><p><a href="https://arxiv.org/pdf/2203.15556.pdf"><strong>Training Compute-Optimal Large Language Models</strong></a></p><p>In recent years, researchers have observed promising improvements in a variety of NLP tasks by increasing the size of language models. As a result, larger language models have been trained over the past few years, such as GPT-3 with 175 Billion parameters, Gopher with 280 Billion parameters, and MT-NLG with 530 Billion parameters. A natural progression to the ongoing research is to discover methods to enhance computational resource optimization. These optimizations can result in cost-saving and more effective use of resources in contextual advertising.</p><p>In this paper, the authors aimed to find a compute-optimal language model given a specific resource constraint. Specifically, they aimed to find an optimal number of parameters (N) and the number of tokens (D) that minimize model loss given a pre-specified computational constraint. They experimented with 400 different models to empirically estimate the optimal values for N and D. Interestingly, they discovered that optimal models tend to have a higher number of tokens and a lower number of parameters compared to current pre-trained models.</p><p>For instance, for the same budget used to train Gopher, the optimal model should have four times more tokens and 1/4th the number of the parameters. By extracting these optimal numbers, the authors introduced Chinchilla with 1.4 Trillion and 70 Billion parameters. This approach not only resulted in improved results, but also reduced inference costs due to the lower number of model parameters.</p><p><a href="https://aclanthology.org/2022.acl-long.220.pdf"><strong>Learned Incremental Representations for Parsing</strong></a></p><p>Syntactic parsing can improve language comprehension by extracting grammatical dependencies in a sentence. Specifically, this paper focuses on incremental syntactic parsing, a process where the model gradually processes a sentence word-by-word to extract grammatical dependencies, and attach meaning and structure to each word. This method contrasts with other approaches where the model waits for the entire sentence to begin the analysis. The authors remind us that this is very similar to how humans comprehend language, processing sentences incrementally rather than waiting for the complete sentence to be spoken.</p><p>The key challenge the paper aims to address is false committing in incremental processing, where the model commits to an incorrect structure in times of ambiguity that only becomes apparent once the full sentence has been revealed. A simple approach to overcome this problem is beam search, where the model considers multiple plausible solutions simultaneously and selects the most accurate structure once the sentence is complete.</p><p>The authors offered a solution for false committing by training an end-to-end model. The first half of the model combines the GPT-2 encoder, followed by a discretization step where continuous vectors are collapsed into a small set of symbols. The second half of the model is a bidirectional read-out network that reads the discretized symbols and creates the final syntactic structure for the entire sentence.</p><p><strong>Conclusion</strong></p><p>We have explored several recent publications that could potentially be useful in contextual advertising. Multilingual models can assist in analyzing web pages across various countries and languages, compute-optimal models can help us better manage our computational resources, and using syntactic parsing can lead to more accurate language understanding.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=63509f982bf0" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/natural-language-processing-in-contextual-advertising-63509f982bf0">Natural Language Processing in Contextual Advertising</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[4 Requisites For Building Accessible Digital Products]]></title>
            <link>https://stackadapt.tech/4-requisites-for-building-accessible-digital-products-c957787d1e92?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/c957787d1e92</guid>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[aria]]></category>
            <category><![CDATA[wcag]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Hok Laam Cheng]]></dc:creator>
            <pubDate>Wed, 22 Feb 2023 12:02:37 GMT</pubDate>
            <atom:updated>2023-02-28T22:03:48.419Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="A wireframe for a page with semantic HTML, distinct button states and accessible colours" src="https://cdn-images-1.medium.com/max/1024/0*vLFDJrp0D8Ur0gNk" /><figcaption><em>A wireframe for a page with semantic HTML, distinct button states and accessible colours</em></figcaption></figure><p>It’s common to think about accessibility in the context of physical spaces, but it’s an important aspect of digital spaces too. Building accessible digital products ensures inclusivity, creating an opportunity for these products to reach all users in a fair and beneficial way.</p><p>The best digital products, and the teams that build them, leverage important characteristics that make them truly accessible. In this article we’re exploring the processes and technical tools that make building an accessible digital product possible.</p><h3>1. Understand Why Accessibility Is Important</h3><p>The first requisite for building accessible digital products is to understand why we care about accessibility.</p><p>Inaccessible design is found all throughout the digital world. For example, you’ll still find digital products on the web that do not support assistive technologies like screen readers and magnification, which make web content more accessible. Accessible design makes a product equally usable by everyone, and in many countries there are <a href="https://www.w3.org/WAI/policies/">digital accessibility laws</a> in place to ensure this.</p><p>Digital accessibility is most often measured using the Web Content Accessibility Guidelines (WCAG). The WCAG defines three levels of conformance: A (lowest), AA, and AAA (highest), with each level of conformance requiring conformance against a set of success criteria, each building upon the previous. For example, in order to achieve the AA conformance level, a product must meet all the success criteria in both A and AA levels.</p><p>According to a 2021 <a href="https://webaim.org/projects/million/2021">report by WebIAm</a>, analysis of the top 1,000,000 home pages in 2021 showed 97.4% of analyzed web pages failed to meet one or more of the criteria from the Web Content Accessibility Guidelines (WCAG) 2.0 Level AA, the consensus standard for digital accessibility. The analyzed websites had an average of 51.4 errors per page. Clearly, there is still more work to do.</p><p><em>Note: At the time of writing in February 2023, the published WCAG version is </em><a href="https://www.w3.org/TR/WCAG21/"><em>WCAG 2.1</em></a><em>, however a new version </em><a href="https://www.w3.org/TR/WCAG22/"><em>WCAG 2.2</em></a><em> is in the draft stage and is set to be published later in the year.</em></p><p>The WCAG defines the accessibility goal that a digital product is trying to achieve. Now that there is a goal, how would an organization work towards that goal?</p><h3>2. Get Everyone’s Buy-In</h3><p>The responsibility for an accessible digital product does not lie on a single person, role, or even team, but requires the buy-in of the entire organization, including:</p><ul><li>Leadership</li><li>Product</li><li>Design</li><li>Engineering</li></ul><p>A focus on accessibility starts with leadership. Dedicating resources towards educating an organization about accessibility and hiring people with knowledge in this area is often one of the first steps towards building an accessible digital product. These top-level actions enable the rest of the organization to focus on accessibility.</p><p>It then continues at the product level. The<a href="https://info.digital.ai/rs/981-LQX-968/images/AR-SA-2022-16th-Annual-State-Of-Agile-Report.pdf"> 2022 State of Agile report</a> highlights that 80% of respondents are predominantly using agile methodologies (although this statistic should be taken with a grain of salt, as the survey population skews towards agile users).</p><p>As agile methodologies that emphasize continuous iteration become more popular, a focus on accessibility must likewise increasingly be a continual, iterative effort. Not only should a digital product be <strong>built</strong> for accessibility, but it should also be <strong>maintained</strong> for accessibility. It is the responsibility of product and project managers to ensure that accessibility is prioritized on the product roadmap.</p><p>A digital product should also be designed such that it is accessible to all. Designers should treat accessibility as a first-class requirement that is equally as important as usability or aesthetics. In fact, good accessibility often promotes good UX as well. We will cover tools designers can use to ensure accessible designs in the next section.</p><p>Last but not least, the engineers that are bringing the designs to life should not only adhere to the (hopefully) accessible designs, but also proactively diagnose potential accessibility issues. It is also often their responsibility, alongside quality assurance, to test the accessibility of the product, with the aid of automated tools and manual testing.</p><p>Building accessible digital products is impossible without organization-wide buy-in. If any one of leadership, product, design, or engineering teams fails to buy-in, then the goal of building and maintaining an accessible product will become incredibly difficult to achieve.</p><p>That being said, the ultimate execution of accessible design and development lies in the hands of designers and engineers, so the next section will cover a range of tools that can be used to ensure a product is accessible during the design, development and testing phases.</p><h3>3. Use The Tools at Your Disposal</h3><p>When it comes to accessibility, designers and engineers are the hands and the feet that make an accessible digital product a reality. Therefore, it is important for designers and developers to know, understand, and use the tools available to them to ensure that a product is accessible to all.</p><p>Below are several categories of tools that are useful for ensuring accessibility in design and development, along with examples for each category.</p><h4>Contrast Ratio</h4><p>Contrast ratio is the difference in perceived luminance between two colours. Contrast ratios can be within the range of 1 to 21, or commonly written as 1:1 to 21:1. It is calculated using the following formula:</p><p>(<em>L</em>1 + 0.05) / (<em>L</em>2 + 0.05)</p><p>Where:</p><ul><li>L1 is the <a href="https://www.w3.org/TR/WCAG20/#relativeluminancedef">relative luminance</a> of the lighter of the colors</li><li>L2 is the <a href="https://www.w3.org/TR/WCAG20/#relativeluminancedef">relative luminance</a> of the darker of the colors</li></ul><p><a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html">WCAG success criterion 1.4.3</a> generally suggests a contrast ratio of at least 4.5:1.</p><p>Colour contrast checkers are widely available to validate that text and background colours have sufficient colour contrast so that text is clear and legible to all levels of visual capabilities. They should be used during both design and development processes to validate all text and background colours, as well as adjacent colours.</p><p>Some examples of colour contrast checkers:</p><p><a href="https://webaim.org/resources/contrastchecker/">WebAIM Colour Contrast Checker</a></p><p><a href="https://color.adobe.com/create/color-contrast-analyzer">Adobe Color — Colour Contrast Analyzer Tool</a></p><p><a href="https://snook.ca/technical/colour_contrast/colour.html#fg=33FF33,bg=333333">Colour Contrast Check</a></p><p><a href="https://www.figma.com/community/plugin/748533339900865323/Contrast">Contrast — Figma Colour Contrast Checker Plugin</a></p><h4>Component States</h4><p>Component states communicate the current status of a component and are especially important for interactive components. Some examples of component states include:</p><ul><li>Enabled: A component is interactive.</li><li>Disabled: A component is non-interactive.</li><li>Hover: When the user’s mouse cursor is over a component.</li><li>Focused: When an element has received focus via keyboard or voice.</li><li>Selected: An option is chosen by the user.</li><li>Error: A mistake has occurred due to the user or the system.</li></ul><figure><img alt="Enabled, disabled, hover, and focused states of the button from Halo-UI, StackAdapt’s custom design system" src="https://cdn-images-1.medium.com/max/498/1*4gSe2xz5vQR_ZrkBGAoe5A.png" /><figcaption><em>Enabled, disabled, hover, and focused states of the button from Halo-UI, StackAdapt’s custom design system</em></figcaption></figure><p>There are more states for some components, while others have fewer, so designers should carefully consider the required states for each component in their designs. Material UI provides a helpful <a href="https://m2.material.io/design/interaction/states.html#usage">summary of states</a>, outlining each state and their usage.</p><h4>Semantic HTML</h4><p>For developers, the most fundamental tool to ensure accessibility is HTML. HTML is the backbone of <strong>semantics</strong> on the web, or in other words, it is crucial in providing meaning to a web page. Using correct, semantic HTML elements at the correct places ensures convenient navigation and meaningful interactions.</p><p>For example, when implementing an interactable action, use the &lt;button&gt; element instead of just a &lt;div&gt;. The advantages of using the &lt;button&gt; element are:</p><ul><li>Buttons have default styling, such as interactive states mentioned in the previous section.</li><li>Screen readers identify it as a button.</li><li>They are focusable and clickable.</li></ul><p>As long as HTML best practices are followed, much of the accessibility issues that a web application could fall prey to can be addressed. The following are some of the most important best practices when writing HTML:</p><ol><li>Structure headings properly, starting from &lt;h1&gt; and descending to &lt;h6&gt; sequentially</li><li>Provide alternative text for images.</li><li>Use landmark elements, such as &lt;header&gt;, &lt;main&gt; and &lt;section&gt; to provide semantics.</li><li>Use the &lt;label&gt; element to name form fields.</li></ol><h4>ARIA</h4><p>While semantic HTML is the most powerful tool when implementing accessible web applications, <a href="https://www.w3.org/WAI/standards-guidelines/aria/">ARIA</a> can also be a useful tool to use alongside semantic HTML.</p><p>ARIA stands for Accessible Rich Internet Applications, and is a set of attributes and roles that can be used to enhance accessibility on web applications. It may be helpful to think of ARIA as CSS for assistive technologies like screen readers.</p><p>Some of ARIA’s features include:</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles">Roles</a> — Each element has a default role, e.g. &lt;button&gt; has the button role, &lt;h1&gt; to &lt;h6&gt; have the heading role, and &lt;a&gt; has the link role.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label">Aria-label</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby">aria-labelledby</a> provide powerful, but potentially dangerous, overwriting of element names which are read by assistive technologies.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby">Aria-describedby</a> provides a mechanism for adding extra context to an element.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-activedescendant">Aria-activedescendant</a> is used in composite widgets or elements to indicate the currently active element.</li></ul><p>Though powerful, ARIA should be used sparingly, especially when an accessibility issue can be solved using HTML. The rule of thumb is if an HTML feature can be used to satisfy an accessibility requirement, use HTML instead of adding ARIA.</p><h3>4. Test Your Product</h3><p>Lastly, a product should be tested to validate that it is accessible. Accessibility testing can range from using automated tools to professional 3rd-party audits, and manual and user testing.</p><p>All these options provide feedback in different ways at different times and monetary costs. It is advisable to use a combination of methods when testing for accessibility, so that there is a balance between quick feedback and thorough insights.</p><p>Automated testing tools provide the quickest feedback loop at the cost of inaccuracy. Many testing tools exist to test a web application against the WCAG success criteria, often providing feedback in a report consisting of:</p><ul><li>Specific success criteria conformances and violations.</li><li>Suggested steps to take to remedy those violations.</li></ul><p>However, they often provide inaccurate results in the form of false positives, which cause inefficiencies when trying to fix a problem that is not a problem, or false negatives, allowing accessibility issues to slip through. Examples of automated testing tools include <a href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse</a> and <a href="https://www.deque.com/axe/">Axe Tools</a>.</p><figure><img alt="The Lighthouse Panel of Chrome DevTools" src="https://cdn-images-1.medium.com/max/1024/0*uYwlw5FGKDuWjdBC" /><figcaption><em>The Lighthouse Panel of Chrome DevTools</em></figcaption></figure><p>A professional 3rd-party audit can provide a similar report that automated testing tools provide, but in a more accurate and detailed manner. However, it is often time consuming and expensive to conduct an audit, making it more suitable for sporadic health checks rather than continuous monitoring and remedying.</p><p>Manual and user testing should be conducted to gather real user feedback that could be missed by automated testing. Product managers, designers and developers should be encouraged to use screen readers to test their own products.</p><p>However, nothing can replace getting real user feedback from people with disabilities who use assistive technologies to consume web content regularly.</p><h3>Start Your Web Accessibility Journey</h3><p>Digital products are not built to be accessible overnight. An accessible digital product requires multiple parties working iteratively over time. It starts with understanding the problems that people face when consuming web content, then continues with leadership, product, design, and engineering taking ownership of a product’s accessibility.</p><p>It is then up to design and product to use the tools at their disposal to implement and test accessibility. Only then, can an organization work towards building and maintaining an accessible digital product.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c957787d1e92" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/4-requisites-for-building-accessible-digital-products-c957787d1e92">4 Requisites For Building Accessible Digital Products</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How We Manage the StackAdapt UI Design System]]></title>
            <link>https://stackadapt.tech/how-we-manage-the-stackadapt-ui-design-system-6c8edba4326f?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/6c8edba4326f</guid>
            <category><![CDATA[ui-design]]></category>
            <category><![CDATA[product-management]]></category>
            <category><![CDATA[design-systems]]></category>
            <category><![CDATA[designer]]></category>
            <category><![CDATA[design-process]]></category>
            <dc:creator><![CDATA[Ellery Yang @ StackAdapt]]></dc:creator>
            <pubDate>Wed, 25 Jan 2023 12:02:31 GMT</pubDate>
            <atom:updated>2023-02-28T22:08:49.244Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Dark and light blue graphic background overlayed with the StackAdapt logo, and text reading Halo Design System" src="https://cdn-images-1.medium.com/max/1024/0*PG56PsMI2MJHYT4o" /></figure><p><em>This article was co-authored by Ellery Yang and Cloris Qian.</em></p><h3>The Beginning of Halo</h3><p>The year was 2020. StackAdapt was on a fast track of growth in terms of both the size of our team and the complexity of our platform.</p><p>With this growth, a new challenge presented itself in front of us: It became essential for us to build standardized tools and guidance to ensure UI/UX consistency across the platform.</p><p>To address this challenge, we introduced a new StackAdapt UI Design System, codenamed Halo. At its core, Halo was created as a standardized UI component library.</p><p>It is a collection of StackAdapt-branded UI building blocks that feature teams across the company could use to build customer-facing features for the StackAdapt platform.</p><p>Halo started as a small, experimental project. In its early days, 3 designers and 1 engineer came together in a casual, ad-hoc way to discuss UI components that may need to be standardized and become part of the library, which is later shared with the engineer to be built and added to the Halo library.</p><p>Quickly, this standardization-driven approach gained popularity among feature teams, and increasing usage of the Halo components demanded more resources be directed to the development of Halo.</p><h3>The Challenge of Sustainability</h3><p>As more members joined the team and the Halo library expanded, the ad-hoc style in which we ran Halo quickly became inefficient and cumbersome.</p><p>The growing Halo team found it increasingly challenging to reach consensus on the ever-larger number of issues needing discussion in our casual meetings, and lack of documentation resulted in repeated discussions.</p><p>The intuitive prioritization of work items that once worked just fine became clearly unscalable. And without a great system to keep each other informed on the growing team.</p><p>Engineers and designers were sometimes unaware of the full picture of what’s needed, what’s being developed, and the gaps between them.</p><p>This also impacted the boundary between the Halo team and feature teams. Sometimes, the Halo team spent a lot of effort developing a component, only to realize no feature team was planning to use it any time soon.</p><p>Other times, a feature team may have been looking for a UI component but didn’t know what was the best way to make such a request to the Halo team, resulting in delays in collaboration.</p><h3>The Evolution of Our Design Process</h3><p>It was clear our process was unsustainable so we started diagnosing the underlying issues. We did so in a two-phase exercise.</p><h4>Looking Inwards</h4><p>In the first phase, we looked inwards at our own effectiveness in running the Halo project. A few problems were identified and we started upgrading our process to address them.</p><p><strong>Problem #1: No source of truth.</strong></p><p>Ad-hoc discussions worked just fine when Halo was a small library casually taken care of by just a few StackAdapters. As both the project and the team grew, we needed Halo topics, work items, and requests to live in established venues of discourse for visibility.</p><p><strong>Solution #1:</strong></p><ul><li>Create regular guided huddles and Slack channels to reach consensus.</li><li>Use a templated component request format.</li><li>Document the design and decision-making process in our project management tool (Jira).</li></ul><figure><img alt="graphics illustrating the request form, review process, and approval process for Halo projects at StackAdapt" src="https://cdn-images-1.medium.com/max/1024/0*dv2GrjkRDceNIR-h" /></figure><p><strong>Problem #2: Lack of guidance for prioritization.<br> <br></strong>The intuitive prioritization method that we used in our early days was clearly not sustainable as the project grew. The sometimes-adopted method of prioritizing the lowest-hanging fruits first was also problematic.</p><p>The increasing complexity of the Halo project required us to have a structured approach to work item prioritization.</p><p><strong>Solution #2:</strong></p><p>We installed systematic guidelines into our prioritization exercises. While we identified many factors to consider, at the core we decided to focus on two questions when assigning priority to a task:</p><ul><li>Does this significantly improve our user experience (UX) or fix an important breakage that’s causing unexpected UX?</li><li>Does this have a downstream consumer already lined up?<br>(Is there a feature team ready to use this once it’s done?)</li></ul><p>The philosophy we employed here goes back to the purpose of the Halo project, which is to help feature teams easily build great user experiences for StackAdapt.</p><p>We decided to look at the UX impact and proposed usage of component work items as the centrepieces of our prioritization.</p><p><strong>Problem #3: Lack of transparency with stakeholders.</strong></p><p>We didn’t have a great system in place to identify and notify stakeholders in the Halo team as work items unfolded. As the team and project grew, we needed to mindfully give each other visibility of our work.</p><p><strong>Solution #3:</strong></p><p>We implemented many process changes such as:</p><ul><li>Identify individuals to be the core stakeholders of a work item as soon as it’s created.</li><li>Automate notifications to these stakeholders of status updates or actions required.</li><li>Keep feature team product managers (PMs) in the loop on updates to existing components to eliminate UI/UX “surprise updates.”</li></ul><h4>Looking Outwards</h4><p>In addition to improving our own effectiveness running the Halo project, we also looked outwards at how we could become more effective collaborating with feature teams at StackAdapt.</p><p>We felt the necessity of this phase came from the nature of our work: Halo components were meant to be used by StackAdapt feature teams and designers, so it was imperative that we also up our game in cross-team collaboration.</p><p><strong>Problem #1: No clarity on how our components are consumed by feature teams.</strong></p><p>We often did not have clarity on how or if feature teams planned to use the proposed UI components in our Halo backlog.</p><p>This resulted in newly created Halo components not actually being used by feature teams, or requested components not being prioritized properly by the Halo team.</p><p><strong>Solution #1:</strong></p><p>We made it part of our process to align scenarios and timelines with feature teams. In other words, our investigation into a potential Halo backlog item is not complete until we know if someone will use it, and when.</p><p>Of course, this did not mean we could not implement components for their long-term benefits, but it effectively reduced the instances where our priorities and those of feature teams were misaligned.</p><p><strong>Problem #2: Low awareness of the component request process.</strong></p><p>This problem was in the other direction, where it was the feature teams that may need to reach out to the Halo team for component requests. We realized that not everyone was aware of how to do that, often resulting in delayed conversations or ineffective communication of requirements.</p><p><strong>Solution #2:<br> </strong><br>With newly-created request templates and channels, we built a process for feature teams to easily follow and share all the required info with us, illustrated in the image below.</p><p>Once such requests were received, we triaged them and communicated with the requestor when we expected to take on the request, or in some cases, why we felt the component didn’t need to be built and what our recommended alternative was.</p><p>We shared this new process with the entire StackAdapt Platform team in a Lunch and Learn session, and have received positive feedback that the request process is much easier to follow now.</p><figure><img alt="graphic illustration of the process of making component requests on the StackAdapt engineering team" src="https://cdn-images-1.medium.com/max/1024/0*dyTAdxkjMdTGFjOR" /></figure><h3>Our StackAdapt UI Design System Today</h3><p>These self-reflections and course corrections were by no means easy, quick or painless. But as we embarked on these changes, we started to see great improvements in our process.</p><p>As our process allowed us to involve all relevant stakeholders more efficiently for component changes, we saw our communications and collaborations become more effective.</p><p>We were able to reduce the time it took to triage incoming UI component requests from a few weeks to within a week’s time. Our work item prioritization became more structured and, as a result, our Halo project backlog became a better representation of how we could help feature teams deliver the most impact to customers.</p><p>Feature teams also feel like it’s easier to work with us to address their feature scenarios in need of UI components, and we are keeping them informed of Halo changes that they should be aware of and plan for.</p><p>In addition to these tangible improvements, we also experience some more intangible but important changes that lubricate and accelerate our development process.</p><h4>Build an adaptive team culture that constantly optimizes efficiency.</h4><p>After seeing positive results from the aforementioned process evolution efforts, the Halo team didn’t stop there and continues to tweak our work process.</p><p>For example, we consistently evolve how we run our regular Halo team huddle as the team grows, sometimes making minor tweaks to the meeting structure every few weeks.</p><p>Recently, we started decentralizing our Halo huddle. We reserve it for topics needing the entire team’s attention and create follow-up meetings involving only the team members who will be working on an item once its scope is defined.</p><p>We made these changes due to the growing size of our team and the number of items needing our attention. More importantly, we were able to constantly make these changes thanks to the adaptive mindset of our team.</p><p>This adaptive culture ensures we as a team collectively keep a growth mindset and are constantly looking for and open to ways to improve how we work together.</p><h4>Build an elevated level of trust in the process.</h4><p>We also saw an increased level of trust in the process both within the Halo team and between the Halo team and feature teams.</p><p>What we mean by this is not a trust in the process being perfect, but rather that the process is always improving, and any imperfections we encounter can be addressed by our adaptive team culture.</p><p>To paraphrase <a href="https://franklincovey.co.nz/the-4-cores-of-credibility/">author Stephen M. R. Covey</a>, one of the most important factors that build trust is past results.</p><p>The Halo team and our partner feature teams have been through a lot of process-improving exercises together, and have observed the positive results we were able to achieve collaboratively.</p><p>Both teams now have a great track record of making our collaboration process better, and that gives us trust in our ability to continue improving it in the future.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6c8edba4326f" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/how-we-manage-the-stackadapt-ui-design-system-6c8edba4326f">How We Manage the StackAdapt UI Design System</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to 5X your Background Job Processing With Sidekiq]]></title>
            <link>https://stackadapt.tech/how-to-5x-your-background-job-processing-with-sidekiq-e0be8279a074?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/e0be8279a074</guid>
            <category><![CDATA[rails]]></category>
            <category><![CDATA[delayed-jobs]]></category>
            <category><![CDATA[sidekiq]]></category>
            <category><![CDATA[background-jobs]]></category>
            <category><![CDATA[ruby-on-rails]]></category>
            <dc:creator><![CDATA[Shahid Khaliq]]></dc:creator>
            <pubDate>Wed, 25 Jan 2023 12:02:31 GMT</pubDate>
            <atom:updated>2023-02-28T22:09:23.035Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to 5X Your Background Job Processing With Sidekiq</h3><figure><img alt="Graphic that has a two toned blue background, overlayed with text that reads “Sidekiq” and “Delayed Job.”" src="https://cdn-images-1.medium.com/max/1024/1*MTv41nm-TaYe46WqQyyK2g.jpeg" /></figure><p>Here at StackAdapt, excellent user experience is our highest priority. We are constantly evaluating the tools and systems we use to ensure that they meet the evolving needs of our users.</p><p>In a project led by our web infrastructure team, we are currently undergoing a migration from Delayed Job to Sidekiq for background job processing in our Ruby on Rails web application monolith. In this post, we will explain why we decided to make the switch, the challenges we faced during the migration, the benefits we’ve seen since completing the migration, and offer our conclusions on the process.</p><h3>Introduction to Delayed Job and Sidekiq</h3><p>Ruby on Rails is a synchronous web application framework. As it can only process one request at a time, it is crucial that a single request does not take too long to execute because it would block the web application and prevent it from being able to handle subsequent incoming requests.</p><p>In any web application, big or small, it is natural to have tasks, or “jobs” as we prefer to call them, which can take a long time to execute. Ruby gems like Delayed Job and Sidekiq solve this problem by enabling long-running jobs to execute in the background, asynchronously, and therefore, leaving the main web application free to process short and quick-running web requests.</p><p><a href="https://www.oreilly.com/library/view/distributed-programming-with/9780321669919/ch10.html">First released in 2008</a>, Delayed Job was written by Shopify CEO, Tobias Lütke, and extracted from the core Shopify Rails application. Delayed Job is a free to use, single-threaded, database-backed, asynchronous job processing gem. It offers a simple delay API that developers can use to process jobs asynchronously.</p><pre># without delayed_job<br>@user.activate!(@device)<br><br># with delayed_job<br>@user.delay.activate!(@device)</pre><p>Sidekiq is a more popular and modern alternative, <a href="https://www.mikeperham.com/2012/02/07/sidekiq-simple-efficient-messaging-for-rails/">first released</a> in 2012 and authored by Mike Perham. It is multi-threaded, backed by Redis and offers much better community support. Sidekiq offers a free OSS (Open-Source Software) version that is actively maintained by the Ruby community. It also offers advanced features in its Pro and Enterprise versions. Sidekiq has a simple API, with the idea of “jobs” which are simply a way to encapsulate long-running tasks.</p><pre>class HardJob<br>  include Sidekiq::Job<br><br>  def perform(name, count)<br>    # do something<br>  end<br>end<br><br>HardJob.perform_async(‘bob’, 5)</pre><h3>Why Sidekiq Over Delayed Job?</h3><p>Tied to our tremendous growth, the number of background jobs we process for our web application has grown exponentially over the past couple of years. One of the main reasons for our move away from Delayed Job was our trouble scaling it to handle the increased load.</p><h3>Redis as the Data Store</h3><p>We had always used our main MySQL database as the data store for Delayed Job and, on any given day, 40% to 60% of the aggregate load on our database would be from the dozens of Delayed Job processes we had running.</p><p>If there was a particularly large influx of background jobs on a certain day, and we bumped up the number of Delayed Job workers, we would see noticeably degraded performance across the board on our web application because the database, congested by all the queries from the Delayed Job processes, would be slower in responding to regular queries from the web application itself.</p><p>Sidekiq, on the other hand, uses Redis as its data store. Being an in-memory data store, Redis is much faster than a traditional RDBMS. This lets Sidekiq push and pull jobs from Redis much faster than Delayed Job can from the database.</p><p>The added benefit for us is that using Sidekiq automatically introduces separation of concerns between the web application and our asynchronous task processing infrastructure. If there are an unexpectedly higher number of asynchronous jobs, it does not affect the performance of our web application at all because the data stores, that is Redis and MySQL, are completely independent of each other.</p><h3>Multi-Threading</h3><p>We run our Delayed Job and Sidekiq processes on AWS EC2 instances. We configure these processes as <em>systemd</em> services so they can start on system startup and restart on failure. There is, of course, a limit to the number of processes that can run on a single machine and, as our requirements went up, we started hitting this limit with Delayed Job.</p><p>Delayed Job and Sidekiq processes need to load the whole Ruby on Rails application to be able to process async jobs and for our web application, the resident set size (RSS) for these processes usually starts around the 400 MB to 500 MB mark. This size varies, based on the kinds of jobs the process is executing, and usually goes up during the life of a process.</p><p>Unlike Delayed Job, Sidekiq is multi-threaded by default. Each Sidekiq process can be configured to run multiple threads, where each thread independently processes asynchronous jobs. We have configured each of our Sidekiq processes to have 5 threads.</p><p>For newly started processes, this directly results in a 5x drop in memory overhead for us, for the same number of workers, and allows a single EC2 machine to process a lot more async jobs when using Sidekiq processes compared to Delayed Job processes.</p><h3>More Features, Better Tooling, Bigger Community</h3><p>Out of the box, Sidekiq offers more features than Delayed Job such as support for middleware and a built-in web UI. The pro and enterprise versions offer an even greater range of features such as batches, cron jobs, unique jobs and worker metrics. The Sidekiq community is also more active in building useful extensions that add lots of additional functionality to Sidekiq.</p><p>It is difficult to gauge popularity but, from our experience, Sidekiq definitely seems more popular in the Ruby community. The gem is updated more frequently, it has more open source contributors and the GitHub repository has more stars than Delayed Job.</p><p>Ultimately, the popularity only matters to us because it is easier to find guides and tutorials online and when new Ruby on Rails developers join our team, they are more likely to be familiar with Sidekiq than with Delayed Job.</p><h3>Challenges Faced During the Migration</h3><p>As with any large migration, there are bound to be some hiccups along the way. In this section, we will share some of the challenges we faced when migrating from Delayed Job to Sidekiq.</p><h3>Database Transactions</h3><p>The biggest problem we had in our migration was that many of our Delayed Job jobs were being created within database transactions.</p><p>As an example, if a new advertisement campaign was created within a transaction, there were instances where jobs related to that campaign would also be created within the same transaction.</p><p>Since Delayed Job uses the application’s database as the job store, this worked out perfectly because if a transaction was rolled back, the job would never be committed to the database or picked up by a worker.</p><p>As soon as we moved some of these jobs to Sidekiq, we started seeing two problems:</p><ol><li>Jobs were pushed to Redis but the transaction had not finished.</li><li>Jobs were pushed to Redis and transaction had rolled back.</li></ol><p>In both cases, Sidekiq processes would pick up the job, only to find that the object referenced by the job did not exist in the database. We solved this problem in three ways:</p><ol><li>Move job queueing outside the transaction blocks in the code.</li><li>Modify jobs to exit if the parameters (records) are not present in the database.</li><li>Use the after_commit_everywhere gem to catch missed cases.</li></ol><p>The first two solutions are quite self explanatory but we will go into more detail for the last one. As we use Ruby on Rails’ ActiveJob framework for our background jobs, we were able to leverage ActiveJob hooks to ensure that no jobs are ever pushed to Redis within a transaction.</p><pre>require &#39;after_commit_everywhere&#39;<br><br>module JobExtensions<br>  module SidekiqJob<br>    include AfterCommitEverywhere<br><br>    def self.included(base)<br>      base.queue_adapter = :sidekiq<br>      base.around_enqueue do |_, block|<br>        after_commit { block.call }<br>      end<br>    end<br>  end<br>end</pre><p>We include this module in every job migrated to Sidekiq from Delayed Job. The first thing it does is change the job’s adapter to Sidekiq. Secondly, it uses the <a href="https://github.com/Envek/after_commit_everywhere">after_commit_everywhere</a> gem to ensure that the job is enqueued on Redis only after all surrounding transactions are committed to the database.</p><p>This technique has proven to be an incredibly effective way to solve one of Sidekiq’s biggest drawbacks for us and has made our migration process much smoother.</p><h3>Mitigating the Risk for Job Loss</h3><p>For Stackadapt, it is of utmost importance that no jobs are ever lost from our web application as this would result in a terrible user experience for our clients.</p><p>Therefore, one of our biggest concerns when migrating to Sidekiq was that Redis was an in-memory data store and if it went down for whatever reason, it might result in data (job) loss. We have taken a number of steps to mitigate this risk.</p><ol><li>We have configured Redis in <a href="https://redis.io/docs/management/sentinel/">Sentinel</a> configuration. This ensures that there is automatic failover in case one of the nodes goes down.</li><li>By default, Sidekiq processes remove jobs from Redis to process them. As such, if a process terminates unexpectedly, the job is lost. Instead of using this default behavior, we have configured Sidekiq server to use Sidekiq Pro’s <a href="https://github.com/mperham/sidekiq/wiki/Reliability#setup"><em>super_fetch!</em></a> feature to only completely remove jobs from Redis <em>after</em> they are completed.</li><li>Going a step further, we have utilized ActiveJob hooks to ensure that if the Sidekiq client is unable to reach Redis to enqueue a job, the job will be enqueued to Delayed Job automatically instead. This is a temporary measure for the migration and we will keep this in place until we have Delayed Job processes running on the sidelines.</li><li>Another temporary measure we have in place, again using ActiveJob hooks, is dual-writing jobs to a table in our main database. When a job is finished processing, it is removed from the table. We only do this for low-frequency, high-priority jobs since this negatively affects performance. This is also a temporary measure for the migration and it is mostly a sanity check for us, as this can let us catch cases where a job was enqueued but not executed by Sidekiq for whatever reason.</li></ol><p>Some of these measures are definitely overkill but, at the end of the day, it is in our clients’ best interest for us to be safe rather than sorry.</p><h3>Migrating jobs from Delayed Job to Sidekiq</h3><p>Most of our jobs on Delayed Job were already using the ActiveJob framework. Migrating these jobs was smooth sailing for the most part, as all that needed to be done was switching the job adapter.</p><p>Some of our legacy jobs are still directly using Delayed Job APIs. What makes things more complicated is that many of these jobs are also using an in-house implementation of a job uniqueness feature which relies on the jobs being present in a database table.</p><p>For the more complicated jobs, which account for between 5% to 10% of all of our jobs, the web infrastructure team has delegated the migration to Sidekiq to the teams that own the job. This slow but steady process ensures that these jobs are safely migrated over.</p><h3>Conclusion and Future Outlook</h3><p>Having migrated about 80% of our jobs to Sidekiq so far, we have seen a big decrease in database load. Sidekiq has been rock solid during the migration and the Web UI has been incredibly useful in helping us keep an eye on our background jobs.</p><p>We are pleasantly surprised at how well Redis performs compared to the database for the same use case and how little memory it consumes. Moving forward, we are hoping to continue seeing increased performance and reliability of our background job processing infrastructure.</p><p>While we wrap up this migration, the next big step for the web infrastructure team is training. On this front, some of the things we are already working on are Sidekiq runbooks for on-call, documentation to help developers run Sidekiq locally for testing and debugging and doing lunch-and-learns for the benefit of other engineering teams.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0be8279a074" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/how-to-5x-your-background-job-processing-with-sidekiq-e0be8279a074">How to 5X your Background Job Processing With Sidekiq</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Takeaways From Building a Custom Component Library]]></title>
            <link>https://stackadapt.tech/5-takeaways-from-building-a-custom-component-library-89481c107bbe?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/89481c107bbe</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[component-libraries]]></category>
            <category><![CDATA[material-ui]]></category>
            <category><![CDATA[user-experience]]></category>
            <category><![CDATA[user-interface]]></category>
            <dc:creator><![CDATA[Javier Ching]]></dc:creator>
            <pubDate>Wed, 25 Jan 2023 12:02:31 GMT</pubDate>
            <atom:updated>2023-02-28T22:10:13.282Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Graphic containing user interface components such as dropdowns, buttons, switches and checkboxes." src="https://cdn-images-1.medium.com/max/1024/1*XAaEFYXfD7sWAsu-JcgC0A.png" /></figure><p>When I joined StackAdapt in 2019, the web platform team consisted of only a few engineers. We were building the platform frontend using React and at the time, the team had worked with several component libraries but ultimately decided upon Material UI (MUI).</p><p>Within the platform team, individual project teams consisted of one or two engineers with minimal interactions between engineers of other projects. Throughout the year, as our design and engineering teams grew, so did the number of component variants. This was caused by two main issues:</p><ol><li>Designers were primarily focused on their own individual projects, which contributed to a lack of communication with other designers about components, theming, and user experience (UX). Each designer had their own design templates which further diverged designs.</li><li>There was infrequent communication between engineering project teams. Developers would build components exactly to the design spec. Because of that, shared components got extremely complex, while many new components were added to support one-off functionality.</li></ol><p>Ultimately, it got to a point where the increasing amount of components weren’t scalable and it caused a lot of confusion within the team. My goal was to fix these issues with the introduction of an internal component library. These are the five most important learnings from that process.</p><h3>1. The Importance of Proof of Concepts</h3><p>When I had initially pitched the component library idea to the whole team, not everybody was on board. The team had yet to understand its value because resources assigned to building the component library were resources detracted from pushing out new features.</p><p>Because of this, I took the opportunity to build out a proof of concept to show the team. I took some of our components and hosted them on a tool called Storybook which is an isolated virtual playground for components.</p><p>Storybook had many controls to tweak the component’s props, display those changes immediately, and generate code snippets for them for developers to reference.</p><figure><img alt="An example of a button built with Storybook, which is an isolated virtual playground for components." src="https://cdn-images-1.medium.com/max/326/0*nnQcDM0zLL4T4MiP" /><figcaption>Storybook Button Example</figcaption></figure><p>I compiled a list of the different component variants we had, and explained how a customized component library built on top of MUI would be the single source of truth to standardize the components we use across different projects.</p><p>Once the team was able to visualize the benefits of the library using this tool, they were on board and our internal component library, which we named Halo UI, was born.</p><h3>2. Communication is Everything</h3><p>The next problem to solve was communication. Not only is it one of the most important parts of a well-functioning team, but it is also one of the most challenging problems to solve.</p><p>The product team, the design team, and the engineering team often spoke different languages because of the unique context each team held.</p><p>What this created in the past was a game of broken telephone; by the time the information reached the developers, it was no longer what was originally envisioned by the product team.</p><p>To address this, we started organizing a weekly meeting to align all these teams. Each team would bring their work to the meeting, allowing members to discuss, ask questions, and provide feedback.</p><p>No design or engineering work would be taken on until all teams fully understood the requirements and agreed upon the work.</p><p>Over the years, we invested more time to teach each other about UI, UX, and coding so that we could understand each other’s perspectives better.</p><h3>3. Defining Better Processes</h3><p>To add onto the communication point, we had to ensure the documented work was written in a way such that someone without context could understand what needed to be done.</p><p>We introduced the concept of product requirement documents (PRDs) to document design decisions, requirements, and edge cases.</p><p>These documents were provided to the Halo UI engineering team to review and ask questions. Any answers would be documented in the PRD so that whoever picked up the work would still have context.</p><p>To better support our feature teams, we set up a process where they can request new features or enhancements. These requests are researched and analyzed by the Halo UI team to determine whether this effort was worth taking on.</p><p>Finally, we also introduced backlog grooming sessions to review requirements with the Halo UI engineering team in advance to reduce the amount of time tickets get blocked due to unclear information.</p><h3>4. Predicting the Future</h3><p>Building the component library in a robust way was very important to account for changes in the future.</p><p>An example of this was deciding to build Halo UI as an internally hosted npm module. At the time, we only had one GitHub repo housing our platform code. But as the company scaled, it became clear that multiple codebases would benefit from importing our library as an npm module.</p><p>Fortunately, it was an easy transition a year later when we decided to start migrating our monorepo to micro frontends which managed their own independent repos. As our team was releasing regular package updates, we had to balance flexibility with strictness.</p><p>We needed to build our components to account for potential changes in product or design requirements but also prevent engineers from making drastic changes that could deviate it from the platform’s look and feel.</p><p>We made sure to spend a lot of time thinking of how to structure our components to account for this balance. This upfront effort really helped in minimizing the amount of breaking changes when major revisions were required.</p><h3>5. Scaling the Team</h3><p>The company was barely 100 people when I joined. Fast forward to today, and StackAdapt has grown to an impressive 900+ people over these past three years. As the product and design teams grew, being the sole developer on the Halo UI team didn’t scale with all the incoming requirements.</p><p>It became clear we needed to scale the Halo UI engineering team but hiring was a challenge because we wanted to find not only technically strong candidates, but candidates that had a real passion for frontend code, and those who would fit well within the team.</p><p>We also took this opportunity to improve our onboarding documentation and it really helped in expediting the onboarding of new frontend engineers. On top of that, to ensure the team’s code aligned with best practices, we improved our ESLint rules to automate this.</p><p>We found that building a proof of concept really helped convince team members to adopt a custom component library. Maintaining good communication with the team also helped us make sure everybody was on the same page.</p><p>Having well-defined processes expedited and improved the team’s work. Making sure we thought ahead when choosing technical approaches helped reduce pain points when making major revisions. And scaling the team helped maintain good team health.</p><p>Our team has made massive improvements over these last couple years, and I am excited to continue learning and growing with the team in the years to come.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=89481c107bbe" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/5-takeaways-from-building-a-custom-component-library-89481c107bbe">5 Takeaways From Building a Custom Component Library</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Gh-ost Story: Online Schema Change at StackAdapt]]></title>
            <link>https://stackadapt.tech/a-gh-ost-story-online-schema-change-at-stackadapt-72bfe424689e?source=rss----20d84872b28e---4</link>
            <guid isPermaLink="false">https://medium.com/p/72bfe424689e</guid>
            <category><![CDATA[scalability]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[schema]]></category>
            <category><![CDATA[percona-toolkit]]></category>
            <dc:creator><![CDATA[Kenneth Thomas]]></dc:creator>
            <pubDate>Wed, 25 Jan 2023 12:02:31 GMT</pubDate>
            <atom:updated>2023-02-28T22:10:40.207Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="A collage of images including bar graph, pie chart, cloud and code." src="https://cdn-images-1.medium.com/max/1024/1*RiwvbIGX4kGfNS5GQk9rMQ.png" /></figure><p>The StackAdapt platform’s backend is powered by a rails monolith. In the past, the way we ran database schema changes, similar to most rails applications, was using the <a href="https://guides.rubyonrails.org/v3.2/migrations.html">ActiveRecord::Migration</a> class.</p><p>This class is provided by rails to help to alter database schemas using a managed approach.</p><p>Since the StackAdapt platform was an always-up platform, rails migrations were our de facto approach to keeping it up and available. Database migrations were run on production whenever a new software release was deployed.</p><p>This approach was sustainable while the table sizes were relatively small. As StackAdapt scaled, so did our data, and some of our critical tables grew exponentially to a point where we could no longer run db schema migrations on those tables using rails migrations.</p><p>ActiveRecord::Migration is a versatile tool that we still use for most of our smaller models, but when it comes to our larger tables, we had to find another alternative.</p><p>As any engineering team would, we started looking at tools that could help us perform online schema changes to our production database with zero downtime. This led us to look at the <a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html">Percona Toolkit</a>.</p><h3>Percona PT-Online Schema Change</h3><p>Pt-osc is one of the most popular tools engineering teams use to run schema migration. To run the migrations using pt-osc we had to choose a time when production traffic was at its lowest and run the migration script.</p><p>The Percona Toolkit runs the migrations by creating a copy of the original table running the schema change on the new empty table and then copying over the data from the original table in chunks. This does not block reads and writes to the original table.</p><p>Pt-osc keeps both tables in sync by using triggers. Every time there is a CRUD operation performed on the original table, a trigger is created to keep the duplicate table in sync.</p><p>Pt-osc also throttles the migration if there is a sudden surge in traffic to the DB, to make sure the database was not under too much load.</p><p>This approach made sense to the team and we chose to use pt-osc to run migrations. At first there were no issues and migrations ran fine.</p><p>As we had to run more migrations to support the engineering team’s needs, we noticed migrations failing quite often and there were quite a few exceptions due to lock contention.</p><p>Issues with using Percona Toolkit to run migrations came down to reliability since most of the time the migrations failed or took too long to run.</p><p>Percona Toolkit’s trigger based approach was the main issue.</p><ul><li>It adds overhead to write operations. For each write operation to the original table, another synchronous write operation to the pt-osc table is needed in the same transaction in order for the tool to function correctly, even if the tool is paused. This is at least 2X the writer’s workload.</li><li>While concurrent queries compete for locks in the original table, the triggers need to simultaneously compete for locks in the pt-osc table. This causes lock contention issues.</li></ul><p>Because of the above concerns, we decided to look at other alternatives, which led us to GitHub <a href="https://github.com/github/gh-ost">gh-ost</a>, an online schema migration tool which does not use a trigger-based approach to keep tables in sync.</p><h3>Gh-ost</h3><p>GitHub’s gh-ost works very similar to the Percona Toolkit. It creates a copy table called the gh-ost table, runs the schema migration on the empty table, and then copies over the data from the original table in chunks.</p><p>Instead of relying on triggers to keep the tables in sync, gh-ost uses the database bin logs to make sure new CRUD operations are also propagated over to the gh-ost table.</p><p>By not relying on triggers gh-ost reduced the load on the database writer when the migration was being throttled. This was what made it interesting to look deeper into gh-ost.</p><p>The first step we took was to benchmark the migrations using pt-osc and gh-ost while we also monitored the database and logs to see if there were any issues with lock contention.</p><h3>Benchmarking</h3><p>We wanted to compare running migration with pt-ost and gh-ost under various stress levels which would help us make an informed decision as to which tool could be a good fit for us.</p><p>We used <a href="https://dev.mysql.com/doc/refman/8.0/en/mysqlslap.html">mysql-slap</a> a load emulation client to apply various levels of stress on the database while we ran the migration.</p><ul><li>The sql script to simulate a naive CRUD operation would be run by concurrent threads on the database. The script updates a random row and then resets the data back to the original state.</li></ul><pre>SET autocommit=0;<br>BEGIN;<br>SET @randomId = (SELECT `id` FROM `table_name` ORDER BY RAND() LIMIT 1);<br>SET @oldName = (SELECT `name` FROM `table_name` WHERE `id` = @randomId);<br>SELECT * FROM `table_name` WHERE `id`=@randomId FOR UPDATE;<br>UPDATE `table_name` SET `name` = &#39;test&#39; WHERE `id` = @randomId;<br>UPDATE `table_name` SET `name` = @oldName WHERE `id` = @randomId;<br>COMMIT;</pre><ul><li><a href="https://dev.mysql.com/doc/refman/8.0/en/mysqlslap.html">Mysql-slap</a> command</li></ul><pre>mysqlslap --create-schema=&quot;databse_name&quot; --query=&quot;sql_script.sql&quot; --host=&quot;127.0.0.1&quot; --port=3306 --concurrency=20 --iterations=10000</pre><p>Result of running the migration under 3 different load conditions. We had 20 concurrent running threads against the database. The schema migration was run on a table with approximately 3 millions rows.</p><p><strong>Baseline: </strong>Run the migration with no load on the DB.</p><p><strong>Experiment 1: </strong>Run the migration with 20 concurrent threads hammering the database, and set the max-load threshold to 25 threads on the database. Setting the max-load on the migration would throttle the migration in situations where the number of running threads to the database exceeds 25.</p><p><strong>Experiment 2: </strong>Run the migration with 20 concurrent threads hammering the database, and set the max-load threshold to 35 threads on the database. Setting the max-load on the migration would throttle the migration in situations where the number of running threads to the database exceeds 35.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/46f179ff5a3ba375dfbd1c5f23e2bbd8/href">https://medium.com/media/46f179ff5a3ba375dfbd1c5f23e2bbd8/href</a></iframe><p><em>*Occurrences of lock contention/deadlocks on the table</em></p><p>In most cases gh-ost outperformed pt-osc and there were no contentions for locks when using gh-ost to run the migration. This made our decision easy.</p><p>Before choosing gh-ost as our default tool, we had to make sure we dropped foreign-keys and added a read replica to our database. <em>G</em>h-ost can run migrations directly on master, but it prefers the replica approach which is safer and does not add additional load on the master writer.</p><p>Gh-ost does provide a flag (discard-foreign-keys) that can be turned on to drop foreign-keys on tables when running migrations.</p><p>Gh-ost also provides an option to delay cut-over which is when the gh-ost table and original table are flipped, this provides us the option to verify the tables are in sync and also perform the cutover when it’s safe to do so.</p><h3>Tuning Gh-ost:</h3><p>Gh-ost provides various options to tune the migration which we took advantage of and are described below.</p><p><strong>`max-load`</strong></p><p>This value tells gh-ost when it needs to pause the migration. This avoids puttubg the database under extra load when there are sudden bursts of CRUD operations running against the DB, which could be because of scheduled jobs that are db intensive or a spike in production traffic.</p><p>We had to determine a value of max-load that we were comfortable with, and we chose a value that was an average of our baseline threads and peak threads running over 24 hours.</p><p><strong>`critical-load`</strong></p><p>A threshold at which gh-ost will terminate the migration. This could be because of a random spike or an issue with production, but when the critical value is met, gh-ost will terminate the migration.</p><p>There are other critical-load related flags that can be set where gh-ost will not terminate the migration, you can read more about them on the gh-ost wiki.</p><p><strong>`chunk-size`</strong></p><p>The size of the chunk of data that is copied from the original table to the gh-ost table.</p><p><strong>`postpone-cut-over-flag-file`</strong></p><p>Allows you to postpone the cutover to a later time.</p><pre>gh-ost \  <br>  --host=&lt;replica_host&gt; \<br>  --assume-master-host=&lt;master_host&gt; \  <br>  --max-load=Threads_running=&lt;max_load&gt; \<br>  --critical-load=Threads_running=&lt;critical_load&gt; \<br>  --chunk-size=&lt;chunk_size&gt; \<br>  --cut-over-lock-timeout-seconds=&lt;cutover_timeout&gt; \<br>  --default-retries=&lt;retry_count&gt; \<br>  --postpone-cut-over-flag-file=&lt;cutover_flag_name&gt; \<br>  --initially-drop-ghost-table \<br>  --initially-drop-old-table \<br>  --assume-rbr \<br>  --user=&lt;db_username&gt; \<br>  --password=&quot;&lt;db_password&gt;&quot; \  <br>  --database=&lt;databse_name&gt; \  <br>  --table=&lt;table_name&gt; \  <br>  --alter=&quot;&lt;alter_query&gt;&quot; \  <br>  --verbose</pre><h3>Conclusion</h3><p>After testing both Percona Toolkit and gh-ost our team was able to make an informed decision on the tool to choose for our system.</p><p>Both pt-osc and gh-ost are great tools to help run migration in a production environment with zero downtime, however we found that gh-ost works better when dealing with larger tables.</p><p><em>Interested in learning more about working at StackAdapt? Explore our </em><a href="https://go.stackadapt.com/tech-blog-engineering-jobs"><em>Engineering career path</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=72bfe424689e" width="1" height="1" alt=""><hr><p><a href="https://stackadapt.tech/a-gh-ost-story-online-schema-change-at-stackadapt-72bfe424689e">A Gh-ost Story: Online Schema Change at StackAdapt</a> was originally published in <a href="https://stackadapt.tech">StackAdapt Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>