<?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[The Telegraph Engineering - Medium]]></title>
        <description><![CDATA[The Telegraph Digital Engineering and Product team powering telegraph.co.uk, The Telegraph mobile apps, Google AMP, Google Cloud, Amazon Echo Skills and Facebook articles - Medium]]></description>
        <link>https://medium.com/the-telegraph-engineering?source=rss----e6218a55f1b0---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>The Telegraph Engineering - Medium</title>
            <link>https://medium.com/the-telegraph-engineering?source=rss----e6218a55f1b0---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 11 Nov 2026 23:35:47 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/the-telegraph-engineering" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Understanding Core Web Vitals (CWV): Why They Matter for Your Website’s SEO]]></title>
            <link>https://medium.com/the-telegraph-engineering/understanding-core-web-vitals-cwv-why-they-matter-for-your-websites-seo-9653717a23ae?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/9653717a23ae</guid>
            <category><![CDATA[core-web-vitals]]></category>
            <category><![CDATA[web-strategy-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[web3]]></category>
            <dc:creator><![CDATA[Mo Montazerian]]></dc:creator>
            <pubDate>Thu, 03 Apr 2025 10:21:03 GMT</pubDate>
            <atom:updated>2025-04-07T10:55:01.525Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aRL_3_vY3a71Aa4L" /></figure><h3>Table of Content</h3><ol><li><strong>What Are Core Web Vitals</strong></li><li><strong>Why Core Web Vitals Matter</strong></li><li><strong>Key Metrics of Core Web Vitals<br></strong>3.1 Largest Contentful Paint (LCP)<br>3.2 Cumulative Layout Shift (CLS)<br>3.3 Interaction to Next Paint (INP) <br>3.4 CWV Scoring and Penalties<br>3.5 Other Important Metrics</li><li><strong>Enhancing &amp; Testing CWV<br></strong>4.1 How to Debug and Test CWV<br>4.2 Mobile-First Indexing Context<br>4.3 Accessibility and CWV</li><li><strong>Real-World Performance Monitoring<br></strong>5.1 Balancing Lab Data and Field Data<br>5.2 Geographic Considerations in Field Data<br>5.3 Monitoring CWV<br>5.4 How we measured CWV at The Telegraph</li><li><strong>Troubleshooting Common Issues and Pitfalls</strong></li><li><strong>FAQs About CWV</strong></li><li><strong>Useful Resources</strong></li></ol><h3>1. What Are Core Web Vitals?</h3><p>Core Web Vitals (CWV) are performance metrics introduced by Google to measure user experience on websites. These metrics assess aspects like loading speed, interactivity, and visual stability. Optimizing these metrics is critical because they directly influence Google’s ranking algorithm as part of the “Page Experience” signals introduced in 2021.</p><h3>2. Why do Core Web Vitals Matter?</h3><ol><li><strong>Enhanced User Experience:</strong> Fast, responsive, and visually stable websites create better user experiences, increasing engagement and conversions.</li><li><strong>Improved SEO Rankings:</strong> CWV is a ranking factor for Google. A site with poor scores risks lower search engine visibility.</li><li><strong>Reduced Bounce Rates:</strong> Pages that meet CWV targets minimise user frustration, leading to fewer users returning to search results.</li><li><strong>Future-Proofing:</strong> As CWV evolves alongside web technology, maintaining good scores ensures your site remains competitive.</li></ol><h3>3. Key Metrics of Core Web Vitals</h3><p>The three main CWV metrics are:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*r_3TjEa8R6iJ4NMf" /></figure><h4>3.1 Largest Contentful Paint (LCP):</h4><ul><li><strong>Definition:</strong> Measures the render time of the largest visible content element in the viewport.</li><li><strong>Target:</strong> Less than 2.5 seconds (<a href="https://developers.google.com/speed/docs/insights/v5/about">PageSpeed Insights</a>).</li><li><strong>Importance:</strong> LCP indicates how quickly a page renders its most prominent visual element, which typically includes large images, videos, or block-level text. While this element is often central to the page’s purpose, it may not always represent the primary content from a user experience standpoint.</li><li><strong>Common Issues:</strong> Large images, slow server response, render-blocking JavaScript or CSS.</li><li><strong>How to Improve: </strong>Optimize and preload critical resources to ensure they load as early as possible, reducing delays in rendering key content. Compress images and serve them in modern formats like WebP or AVIF to improve load times, while using Content Delivery Networks (CDNs) helps minimize latency by delivering assets from servers closer to users. Also, reducing the main thread workload by deferring non-critical scripts and lazy-loading offscreen images can significantly enhance performance. Minifying and optimizing CSS and JavaScript further prevents render-blocking issues, ensuring a smoother and faster user experience.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*uSbbbdt5tZ0WdiRy" /></figure><h4>3.2. Cumulative Layout Shift (CLS):</h4><ul><li><strong>Definition:</strong> CLS measures layout stability by quantifying unexpected layout shifts that occur during a page’s lifespan.</li><li><strong>Target:</strong> A score below 0.1 (<a href="https://developers.google.com/speed/docs/insights/v5/about">PageSpeed Insights</a>).</li><li><strong>Importance:</strong> Prevents content from moving unexpectedly, which can disrupt user interaction.</li><li><strong>Common Issues:</strong> unoptimized animations, dynamic ads, or images without defined dimensions.</li><li><strong>How to Improve: </strong>Define width and height for all media elements to prevent unexpected shifts, and use CSS aspect-ratio to maintain consistent dimensions for images and videos. Reserving space for ads and dynamic content ensures they do not push other elements when loading. Additionally, using font-display: swap helps avoid invisible text while web fonts load, reducing visual instability.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*nrKo_DKNR_CBvuVK" /></figure><h4>3.3. Interaction to Next Paint (INP):</h4><ul><li><strong>Definition:</strong> This measure measures responsiveness by evaluating the delay between user interactions and page updates, including the time it takes for visible response or feedback to appear.</li><li><strong>Target:</strong> Less than 200 milliseconds (<a href="https://developers.google.com/speed/docs/insights/v5/about">PageSpeed Insights</a>).</li><li><strong>Importance:</strong> Ensures users can interact with the page smoothly without noticeable delays.</li><li><strong>Common Issues:</strong> JavaScript delays, heavy scripts, and large files blocking interaction.</li><li><strong>How to Improve: </strong>Break up long tasks using code-splitting techniques; optimize JavaScript and defer non-critical scripts; use modern frameworks prioritising responsiveness.</li></ul><h4>3.4 CWV Scoring and Penalties</h4><p>Each metric contributes to an overall Core Web Vitals score, which is out of 100. Google evaluates these scores to determine how well a site meets user experience standards:</p><ul><li><strong>Good Overall Score (90–100):</strong> Indicates excellent performance and compliance with Google’s expectations. No penalties apply.</li><li><strong>Needs Improvement (50–89):</strong> Scores in this range suggest areas for optimization. While not directly penalized, poor user experience can indirectly impact rankings.</li><li><strong>Poor Score (&lt;50):</strong> Sites with overall scores below 50 risk reduced visibility in search engine results due to failing to meet user expectations.</li></ul><p>Key Penalty Thresholds:</p><ul><li><strong>Individual Metrics:</strong> If any of the three core metrics (LCP, CLS, or INP) consistently fall into the “Poor” range, Google may penalize the site with lower rankings.</li><li><strong>Overall Score:</strong> Maintaining an overall CWV score <strong>below 75</strong> can hinder competitiveness and long-term SEO performance.</li></ul><h4>3.5 Other Important Metrics</h4><p>In addition to CWV, several supplementary metrics help provide a comprehensive performance overview:</p><ul><li><strong>Time to First Byte (TTFB):</strong> Measures server response time.</li><li><strong>Time to Interactive (TTI):</strong> Time until the page becomes fully interactive.</li><li><strong>Speed Index (SI):</strong> Shows how quickly the content is visually displayed during load.</li></ul><h3>4. Enhancing and Testing CVW</h3><h4>4.1 How to Debug and Test CWV</h4><p><strong>Tools for Testing</strong></p><ol><li><strong>Google</strong><a href="https://developer.chrome.com/docs/lighthouse/overview/"><strong> Lighthouse</strong></a><strong>:</strong></li></ol><ul><li>A lab testing tool available in Chrome DevTools. Run it to get actionable recommendations for improving performance.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-AEsLWIIWxcKNYR5" /></figure><p>“T<em>he Chrome DevTools </em><strong><em>Lighthouse</em></strong><em> panel.”</em></p><p>2.<a href="https://pagespeed.web.dev/"> <strong>PageSpeed</strong></a><strong> Insights:</strong></p><ul><li>Combines field and lab data to offer a comprehensive view of page performance.</li><li>Leverages the Chrome User Experience Report (<a href="https://developer.chrome.com/docs/crux/dashboard">CrUX</a>) for real-world user metrics.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*wfHpHD5ZNrQGiv6e" /></figure><p>Left: “PageSpeed Insights panel example”; Right: “CrUX Dashboard Panel example”</p><p>3. <strong>Chrome DevTools Performance Tab:</strong></p><ul><li>Simulates different network conditions and devices for detailed analysis.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*G7BPzyDiq_vnH__c" /></figure><p>Chrome DevTools Performance Tab</p><p>4. <strong>Third-Party Tools:</strong></p><ul><li><strong>Web Vitals Chrome Extension:</strong> Monitors CWV metrics in real-time while browsing.</li><li><strong>SpeedCurve:</strong> Offers advanced tracking and performance insights.</li><li><strong>DataDog:</strong> Tracks performance and monitors CWV trends.</li><li><strong>Requestly:</strong> Useful for debugging and simulating network conditions.</li><li><strong>WebPageTest</strong>– A powerful tool for in-depth performance analysis, waterfall breakdowns, and testing across different network conditions and locations.</li></ul><p><strong>Simulating Different Environments</strong></p><ul><li>Test under various network conditions (Wi-Fi, 4G, 3G).</li><li>Assess performance across different devices:</li><li><strong>Desktop:</strong> Windows, macOS.</li><li><strong>Mobile:</strong> Android, iOS.</li></ul><h4>4.2 Mobile-First Indexing Context</h4><p>Google evaluates sites primarily based on their mobile performance. If a site performs poorly on mobile, it can negatively affect rankings, even if the desktop experience is excellent.</p><p><strong>Key Mobile-Specific Strategies:</strong></p><ol><li><strong>Optimize for Smaller Screens:</strong></li></ol><ul><li>Ensure images are appropriately sized for mobile screens using responsive design techniques like srcset.</li><li>Test font sizes to maintain readability without zooming.</li></ul><p>2. <strong>Test Under Realistic Mobile Conditions:</strong></p><ul><li>Simulate slow network speeds (e.g., 3G or 4G) using tools like <strong>Chrome DevTools</strong> to identify bottlenecks.</li><li>Use <strong>Lighthouse</strong> in mobile emulation mode to analyze performance.</li></ul><p>3.<strong> Minimize Mobile-Specific Issues:</strong></p><ul><li>Avoid intrusive interstitials that can disrupt the mobile user experience.</li><li>Prioritize above-the-fold content to load first for mobile users.</li></ul><p><strong>Tools for Mobile-First Indexing:</strong></p><ul><li><strong>Google Mobile-Friendly Test:</strong> Quick check for mobile usability issues.</li><li><strong>WebPageTest:</strong> Allows detailed testing under mobile conditions with different network speeds.</li></ul><h4>4.3 Accessibility and CWV</h4><p><strong>How CWV Enhancements Benefit Accessibility:</strong></p><ol><li><strong>Improved Load Times:</strong></li></ol><ul><li>Faster loading pages reduces frustration for users relying on assistive technologies like screen readers. These devices can perform more efficiently when pages load quickly and provide structured content.</li></ul><p>2. <strong>Visual Stability (CLS):</strong></p><ul><li>Predictable layouts help users navigate easily, especially those with cognitive disabilities. Sudden layout shifts can disorient users relying on visual or keyboard navigation aids.</li></ul><p>3. <strong>Interactive Performance (INP):</strong></p><ul><li>Delays in interactivity impact users relying on screen readers or keyboard-only navigation. Ensuring responsive interactions improves the usability of web elements like forms, buttons, and menus.</li></ul><p><strong>Actionable Accessibility Improvements:</strong></p><ul><li>Use semantic HTML elements (e.g., &lt;header&gt;, &lt;nav&gt;, &lt;main&gt;) for better screen reader support.</li><li>Define clear focus states for interactive elements to help keyboard users.</li><li>Optimize ARIA (Accessible Rich Internet Applications) attributes alongside CWV improvements to ensure compatibility with assistive technologies.</li><li>Test accessibility using tools like:</li><li><strong>WAVE Accessibility Tool</strong> — identifies accessibility issues.</li><li><strong>Axe DevTools</strong> — integrates into browser dev tools for accessibility auditing.</li></ul><h3>5. Real-World Performance Monitoring</h3><p>Understanding website performance requires combining <strong>lab data</strong> and <strong>field data</strong> for a comprehensive view of strengths and weaknesses under various conditions.</p><h4>5.1 Balancing Lab Data and Field Data</h4><p><strong>Lab Data:</strong> Tools like Google Lighthouse and Chrome DevTools test performance in controlled environments (e.g., high-speed networks, specific devices). They identify technical bottlenecks but don’t fully represent real-world user experiences.</p><p><strong>Field Data:</strong> Real User Monitoring (RUM) tools like CrUX and SpeedCurve collect metrics from actual users, reflecting performance across diverse conditions, including geographic location, device type, and network speed.</p><p><strong>Key Differences</strong></p><ul><li><strong>Environment:</strong> Lab data uses ideal conditions; field data accounts for real-world factors like geography and internet speed.</li><li><strong>Granularity:</strong> Lab data provides specific recommendations; field data shows broader trends.</li><li><strong>Purpose:</strong> Lab data aids proactive optimization; field data validates improvements and monitors trends.</li></ul><h4>5.2 Geographic Considerations in Field Data</h4><p>Performance varies by user location due to server distance and network infrastructure. Latency increases with distance, especially in regions with weaker networks. Field data helps identify slow regions, enabling localized optimizations like CDNs or edge servers to reduce latency.</p><h4>5.3 Monitoring CWV</h4><ol><li><strong>Field Monitoring:</strong></li></ol><ul><li>Use tools like Chrome User Experience Report (CrUX) and SpeedCurve to gather real-world performance data.</li></ul><p>2. <strong>Set performance budgets:</strong></p><ul><li>Define acceptable thresholds for metrics. Use alerts in tools like DataDog to monitor deviations.</li></ul><p>3. <strong>Integrate in CI/CD Pipelines:</strong></p><ul><li>Automate performance tests to ensure new deployments don’t negatively impact CWV.</li></ul><h4>5.4 How we measured CWV at The Telegraph</h4><p>At The Telegraph Media Group (TMG), monitoring and improving CWV is essential for ensuring an optimal reading experience — especially on content-heavy pages where layout stability, load time, and responsiveness matter deeply.</p><p>To effectively measure and track CWV metrics like <strong>LCP</strong>, <strong>CLS</strong>, and <strong>INP</strong>, TMG employs a combination of <strong>synthetic</strong> and <strong>real-user monitoring tools</strong>, including:</p><ul><li><strong>Google Chrome User Experience Report (CrUX)</strong></li><li><strong>PageSpeed Insights</strong></li><li><strong>WebPageTest</strong></li><li><strong>Chrome DevTools</strong></li><li><strong>Datadog</strong> (for alerting and anomaly detection)</li></ul><p>This hybrid approach helps not only catch regressions before they reach production but also understand performance across various devices, templates, and geographic locations.</p><p>By tracking and valiadating improvements over time by integrating performance monitoring directly into development workflows and using internal dashboards for visibility.</p><p>For a full breakdown of how The Telegraph approaches CWV optimization — including how they resolved layout shifts— check out the following full case study on <a href="https://web.dev/case-studies/telegraph">web.dev</a>.</p><h3>6. Troubleshooting Common Issues and Pitfalls</h3><p>Optimizing CWV requires understanding common challenges, avoiding frequent mistakes, and taking actionable steps. Here’s a consolidated guide:</p><ol><li><strong>For CLS Drops:</strong></li></ol><ul><li>Ensure all images and videos have defined dimensions.</li><li>Use CSS animations instead of JavaScript for smoother transitions.</li><li>Test with slow networks to spot problematic layout shifts.</li></ul><p>2. <strong>For LCP Drops:</strong></p><ul><li>Optimize server response times.</li><li>Compress and preload critical assets (images, fonts).</li><li>Minify CSS and JavaScript files.</li></ul><p>3. <strong>For INP Drops:</strong></p><ul><li>Reduce JavaScript execution time by lazy-loading scripts and splitting large bundles.</li><li>Defer non-critical JavaScript to improve INP.</li><li>Use efficient event handlers to minimize delays.</li><li>Monitor long tasks in the Performance tab of Chrome DevTools.</li></ul><p>4. <strong>General Optimization</strong></p><ul><li>Minify CSS, JavaScript, and HTML files.</li><li>Use a Content Delivery Network (CDN) to reduce server response times.</li><li>Enable browser caching for reusable assets.</li></ul><p>5. <strong>Common Pitfalls to Avoid:</strong></p><ul><li>Overoptimizing for a single metric without considering holistic user experience.</li><li>Neglecting mobile testing in favour of desktop.</li><li>Failing to account for the impact of third-party scripts or heavy assets.</li></ul><h3>7. FAQs About CWV</h3><ol><li><strong>What happens if my site fails the CWV assessment?</strong></li></ol><ul><li>Poor CWV scores can negatively impact your search rankings and user retention.</li></ul><p>2. <strong>Can CWV be tested in staging environments?</strong></p><ul><li>Yes, using lab tools like Lighthouse or WebPageTest.</li></ul><p>3. <strong>How often should CWV be monitored?</strong></p><ul><li>Continuously monitor using tools like SpeedCurve and DataDog and set performance budgets for ongoing checks.</li></ul><p>4. <strong>How do third-party scripts affect CWV?</strong></p><ul><li>Third-party scripts can significantly slow down performance. Use a tag manager to control them and load only necessary scripts.</li></ul><h3>8. Useful Resources</h3><ul><li><a href="https://developers.google.com/search/docs/appearance/core-web-vitals">Google’s Core Web Vitals Documentation</a></li><li><a href="https://pagespeed.web.dev/">PageSpeed Insights</a></li><li><a href="https://developers.google.com/speed/docs/insights/v5/about">PageSpeed Insights Docs</a></li><li><a href="https://developer.chrome.com/docs/lighthouse/performance/performance-scoring">Lighthouse Performance Overview</a></li><li><a href="https://developer.chrome.com/docs/crux/dashboard">CrUX Dashboard</a></li></ul><p>By understanding and optimizing Core Web Vitals, you ensure that your website meets Google’s standards and provides a superior user experience. This is crucial for maintaining competitive SEO rankings and driving long-term engagement.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9653717a23ae" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/understanding-core-web-vitals-cwv-why-they-matter-for-your-websites-seo-9653717a23ae">Understanding Core Web Vitals (CWV): Why They Matter for Your Website’s SEO</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Comprehensive Guide to Software Testing: Unit, Integration, and E2E Testing Explained]]></title>
            <link>https://medium.com/the-telegraph-engineering/a-comprehensive-guide-to-software-testing-unit-integration-and-e2e-testing-explained-43969493b831?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/43969493b831</guid>
            <dc:creator><![CDATA[Mo Montazerian]]></dc:creator>
            <pubDate>Wed, 22 Jan 2025 12:28:28 GMT</pubDate>
            <atom:updated>2025-01-22T12:28:28.909Z</atom:updated>
            <content:encoded><![CDATA[<p>In the world of software development, testing is a vital practice to ensure that applications perform as expected, maintain their reliability, and deliver a seamless user experience. However, not all testing methods are created equal. Unit testing, integration testing, and end-to-end (E2E) testing each plays a unique role in ensuring software quality. Understanding their distinctions and use cases is critical for designing an efficient testing strategy.</p><p>This post breaks down these three essential types of testing, exploring their descriptions, tools, advantages, disadvantages, and decision-making criteria for choosing the right mix for your project. Let’s demystify these testing layers and understand how they contribute to software quality.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L3SHBXfKXaBMDkwIt9fsRQ.png" /><figcaption>“Testing Layers Simplified: Understand the Speed, Scope, and Coverage of Each Test Type”</figcaption></figure><h3>Testing Layers Simplified: Speed, Scope, Coverage, and Cost</h3><p>Testing is often represented as a pyramid, as shown in the above figure, where the foundation consists of unit tests, followed by integration tests, and topped with E2E tests. This visual helps balance testing speed, scope, coverage — and cost. The cost of identifying and fixing bugs increases exponentially as you move up the testing pyramid.</p><ul><li><strong>Unit Tests:</strong> Fast, inexpensive, and numerous, targeting individual components. Bugs caught here are the easiest and cheapest to fix because the scope is limited, dependencies are minimal, and debugging is straightforward.</li><li><strong>Integration Tests:</strong> Moderate in speed and cost, focusing on the interactions between components. Bugs identified here cost more to fix than in unit tests due to increased complexity and dependencies.</li><li><strong>E2E Tests:</strong> Slow and costly to execute, replicating real-world workflows. Bugs discovered at this level are the most expensive to fix as they require debugging through multiple layers of the system and possibly redesigning workflows.</li></ul><p>Striking the right balance between these layers ensures efficient testing strategies. By addressing bugs as early as possible, particularly during unit testing, development teams can save significant time and money.</p><h3>Unit Testing: The Building Blocks of Software Quality</h3><h4>What is Unit Testing?</h4><p>Unit testing focuses on individual components of code, such as functions or methods, testing them in isolation from the rest of the system. It ensures that the smallest building blocks of an application behave as intended.</p><h4>Tools and Frameworks</h4><p>Popular tools for unit testing include:</p><ul><li><strong>JUnit:</strong> A widely used framework for Java applications.</li><li><strong>NUnit:</strong> A robust testing framework for .NET applications.</li><li><strong>Pytest:</strong> A flexible and powerful testing tool for Python.</li><li><strong>Jest:</strong> A popular framework for JavaScript and TypeScript, especially suited for React, Vue, and Node.js.</li></ul><h4>Use Cases</h4><p>Unit tests are ideal for verifying the following:</p><ul><li>Single functions or methods.</li><li>Classes and their associated behaviours.</li><li>Core algorithms or logic in the system.</li></ul><h4>Advantages</h4><ul><li><strong>Speed and Cost-Effectiveness:</strong> Unit tests execute quickly, providing immediate feedback. Early detection of bugs at this level is far cheaper compared to addressing issues discovered later in integration or E2E testing.</li><li><strong>Simplicity:</strong> Easy to write and maintain, enabling developers to efficiently cover large portions of the codebase.</li></ul><h4>Disadvantages</h4><ul><li><strong>Limited Scope:</strong> They focus on isolated components and may miss issues related to interactions between system parts.</li></ul><h4>Example</h4><p>Testing a function that calculates discounts for a shopping cart or validating an algorithm that filters search results.</p><h4>Challenges and Mitigation</h4><p>Dependency issues can arise when testing complex components. Mocking or stubbing external dependencies can resolve these problems.</p><h4>Connection to TDD</h4><p>Unit testing is integral to <strong>Test-Driven Development (TDD)</strong>, a methodology where tests are written before the actual code. TDD ensures code correctness and encourages developers to design testable, modular code. In TDD:</p><ol><li>Developers write a failing test that defines a new function or improvement.</li><li>They write just enough code to pass the test.</li><li>The code is refactored while ensuring the test still passes.</li></ol><p>This iterative process ensures that all code has corresponding tests, promoting better design, early bug detection, and robust software.</p><h3>Integration Testing: Connecting the Dots</h3><h4>What is Integration Testing?</h4><p>Integration testing examines how different components or modules of an application work together. It uncovers issues such as data mismatches, interface incompatibilities, and misconfigured dependencies.</p><h4>Tools and Frameworks</h4><p>Effective tools for integration testing include:</p><ul><li><strong>TestNG:</strong> Known for its flexibility and robust reporting capabilities.</li><li><strong>Spock:</strong> A powerful testing and specification framework for Java and Groovy.</li><li><strong>Pytest:</strong> Extensible enough to handle integration testing.</li><li><strong>Jest:</strong> Frequently used for testing interactions between components in JavaScript applications.</li></ul><h4>Use Cases</h4><p>Integration tests are commonly applied to scenarios like:</p><ul><li>Communication between microservices or distributed systems.</li><li>Database interactions to validate data consistency and correctness.</li><li>Verifying API integration with other components.</li></ul><h4>Advantages</h4><ul><li><strong>Broader Coverage:</strong> Catches issues that unit tests might overlook, such as problems with data flow or interface mismatches.</li><li><strong>Realistic Validation:</strong> Tests real-world interaction between components.</li></ul><h4>Disadvantages</h4><ul><li><strong>Complexity and Cost:</strong> Setting up integration tests can require significant effort to configure dependencies and environments, and issues uncovered at this stage can be costlier to address than those identified in unit tests.</li><li><strong>Performance:</strong> Slower than unit tests.</li></ul><h4>Example</h4><p>Testing the interaction between a payment gateway API and an internal order management system.</p><h4>Challenges and Mitigation</h4><p>Setting up integration tests can be complex. Use continuous integration (CI) pipelines to automate the setup and teardown of environments.</p><h4>Building and Maintaining a Regression Pack</h4><p>Integration tests play a critical role in a <strong>regression test pack</strong>, which ensures that new code changes do not break existing functionality. Best practices include:</p><ul><li>Automating the regression pack as part of the CI/CD pipeline for continuous feedback.</li><li>Periodically reviewing and updating the regression tests to keep them relevant.</li><li>Prioritising critical workflows in the regression suite to minimise maintenance costs while maximising impact.</li></ul><h3>E2E Testing: The Ultimate User Experience Validator</h3><h4>What is E2E Testing?</h4><p>End-to-end testing replicates real user scenarios to validate the entire application workflow from start to finish. It ensures that the system behaves as expected from the perspective of the end user.</p><h4>Tools and Frameworks</h4><p>Popular tools for E2E testing include:</p><ul><li><strong>Selenium:</strong> A widely used framework for automating web browsers.</li><li><strong>Cypress:</strong> Known for its developer-friendly features and debugging capabilities.</li><li><strong>Playwright:</strong> A modern E2E testing tool supporting cross-browser testing.</li></ul><h4>Use Cases</h4><p>E2E testing shines in scenarios like:</p><ul><li>Verifying user authentication flows, such as login and registration.</li><li>Ensuring seamless transaction workflows, such as shopping cart and checkout processes.</li><li>Testing visual interfaces (UI/UX) to validate overall application design and responsiveness.</li></ul><h4>Advantages</h4><ul><li><strong>Comprehensive Coverage:</strong> Validates the system’s functionality and reliability from the user’s perspective.</li><li><strong>High Confidence:</strong> Provides assurance that the application behaves as intended in real-world scenarios.</li></ul><h4>Disadvantages</h4><ul><li><strong>Slow Execution and High Cost:</strong> Takes longer to execute compared to other testing methods and is the most expensive phase due to the need for realistic setups and broad scope.</li><li><strong>Maintenance Overhead:</strong> Challenging to maintain for applications undergoing frequent updates.</li></ul><h4>Example</h4><p>Simulating the complete booking process for a flight reservation system, including search, seat selection, and payment.</p><h4>Challenges and Mitigation</h4><p>E2E tests can become brittle with frequent UI changes. To reduce maintenance overhead:</p><ul><li>Modularise tests and reuse components.</li><li>Regularly review E2E tests for relevance and adapt them to evolving workflows.</li></ul><h3>Striking the Right Balance in Your Testing Strategy</h3><h4>Layering Your Tests</h4><p>The pyramid visual highlights the importance of balancing test types:</p><ul><li><strong>Unit Tests (70%):</strong> The foundation, covering the majority of the codebase.</li><li><strong>Integration Tests (20%):</strong> Validating interactions between components.</li><li><strong>E2E Tests (10%):</strong> Ensuring critical workflows function as expected.</li></ul><h4>Decision Criteria</h4><ul><li><strong>Unit Tests:</strong> Ideal for projects with rapid iterations or a focus on algorithmic correctness.</li><li><strong>Integration Tests:</strong> Crucial for API-heavy architectures or systems with multiple dependencies.</li><li><strong>E2E Tests:</strong> Essential for applications where UI/UX is a critical success factor.</li></ul><h4>Automation Strategies</h4><p>Automate testing layers wherever possible. Use CI/CD pipelines to integrate testing into the development workflow for continuous feedback.</p><h3>Best Practices for Testing</h3><p>To create an efficient and maintainable testing strategy, follow these best practices:</p><ul><li>Write testable code with clear boundaries and separation of concerns.</li><li>Keep tests independent and reproducible.</li><li>Use descriptive names for tests to improve readability.</li><li>Regularly review and refactor tests to ensure relevance as the application evolves.</li></ul><h3>Conclusion</h3><p>Each type of testing — unit, integration, and E2E — serves a unique purpose in ensuring software quality. Unit testing provides quick feedback and focuses on individual components, while integration testing ensures that interconnected parts of the system work together. Finally, E2E testing replicates user workflows to validate the entire application’s functionality.</p><p>By leveraging these testing methods in a layered approach, you can achieve a balance between speed, coverage, confidence and cost. Whether you are a developer, QA engineer, or software architect, understanding and applying these testing practices will help you build robust, reliable, and user-friendly applications.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=43969493b831" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/a-comprehensive-guide-to-software-testing-unit-integration-and-e2e-testing-explained-43969493b831">A Comprehensive Guide to Software Testing: Unit, Integration, and E2E Testing Explained</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Importance of Defensive Programming]]></title>
            <link>https://medium.com/the-telegraph-engineering/importance-of-defensive-programming-d864570b6b44?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/d864570b6b44</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[defensive-programming]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Mitesh Sevani]]></dc:creator>
            <pubDate>Fri, 17 Jan 2025 11:39:15 GMT</pubDate>
            <atom:updated>2025-05-09T15:54:34.659Z</atom:updated>
            <content:encoded><![CDATA[<p>Engineers often code to meet the happy path, i.e. a default scenario featuring no exceptional or error conditions. A program or feature in software that only meets the happy path results in low-quality, less stable and less secure code. It is therefore good practice to use the <strong>defensive programming</strong> approach.</p><figure><img alt="Defensive Programming" src="https://cdn-images-1.medium.com/max/720/1*BLcjcEM5ExXQ5rWCeZS8GQ.png" /><figcaption>Defensive Programming</figcaption></figure><p>Defensive programming is a coding method where engineers anticipate potential issues, errors or misuse of their code and write software to handle these situations proactively.</p><p>It aims to improve the overall quality, stability and security of code by anticipating and handling potential errors or unexpected scenarios or failures, even if the input or environment is not ideal.</p><p>Let’s use an example to explain further. I will be using JavaScript as my example language, but the concepts apply to any software language.</p><h3>Example 1: Simple calculation</h3><p>Let’s take an example of a simple number calculation.</p><pre>function calc(a, b) {<br>  return a+b;<br>}<br><br>calc(1,1) // returns 2</pre><p>Tested, no issues here so it’s ready for production right? Wrong!</p><p>What happens when the input is not an integer, but a text or any other data type? Will it return the expected value?</p><pre>calc(a,1) // Uncaught ReferenceError: a is not defined</pre><p>This piece of code is not robust at all. We need to ensure the values are numbers and not any other datatype.</p><pre>function calc(a, b) {<br>  // Check if the input values are numbers<br>  if (isNaN(a) || isNaN(b)) {<br>    return &quot;You need to enter a number&quot;;<br>  } <br>  <br>  return a+b;<br>}</pre><p>This simple condition to check if the input values are numbers will now at least ensure the code is considering non-numerical input values and returning an appropriate message for that condition.</p><h3>Example 2: Selecting an element</h3><p>Let’s say you wish to get the value of an element on the page with the “foo” identifier.</p><pre>const elFoo = document.querySelector(&quot;[data-js=foo]&quot;);<br><br>elFoo.innerText;</pre><p>If the page has the element with that identifier with a value, it will work with no issues, however, what happens when the page running this code does not have that element?</p><pre>Uncaught TypeError: Cannot read properties of null (reading &#39;value&#39;)</pre><p>It will return the above error and the remainder of the JavaScript code will not execute.</p><p>The issue here is that the code was written <strong><em>assuming</em></strong> that element will always exist. A defensive programming approach will ensure the code is written such that even if the variable (in our case the element) does not exist, it will not break the execution of the code.</p><p>Simply adding a condition to check that the element exists before continuing is defensive programming.</p><pre>if (elFoo) {<br>  return elFoo.innerText || “Placeholder Text”;<br>}</pre><h3>Key aspects of defensive programming</h3><p><strong>1. Input validation</strong>: Thoroughly validating, verifying and sanitising all input data to prevent errors or security vulnerabilities.</p><p><strong>2. Error handling</strong>: Properly managing errors using try/catch blocks, exception handling or other mechanisms to ensure that the code can gracefully recover from or handle errors.</p><p><strong>3.</strong> <strong>Avoid assumptions</strong>: Not assuming that functions, inputs, or other parts of the system will always behave as expected. This includes being prepared for edge cases or incorrect usage and catching logical errors early in the development process.</p><p><strong>4. Secure coding practices</strong>: Implementing security measures to protect against common vulnerabilities like buffer overflows, SQL injection or cross-site scripting.</p><p><strong>5. Logging and monitoring</strong>: Incorporating comprehensive logging to aid in debugging and identifying issues in production.</p><p><strong>6. Fail-safe defaults</strong>: Designing systems to fail safely if something goes wrong, ensuring that critical systems remain secure or operational in a limited capacity.</p><p>7. <strong>Code clarity</strong>: Writing clear, maintainable code that is easy to understand and modify. This reduces the risk of future bugs when the code is updated or extended.</p><p><strong>8. Defensive data structures</strong>: Using immutable objects or implementing checks to maintain data integrity.</p><p><strong>9. Immutability and side effects</strong>: Limiting the use of global variables or mutable states, which can cause unexpected behaviour if not properly managed.</p><p><strong>10. Thorough testing</strong>: Employing unit tests, integration tests, and edge case scenarios to verify code behaviour.</p><p>By following defensive programming practices, developers can build systems that are more resilient and less prone to failure in unexpected circumstances. It makes the software safe, secure and robust.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d864570b6b44" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/importance-of-defensive-programming-d864570b6b44">Importance of Defensive Programming</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[News in Real Time: The Telegraph’s Approach to Publishing Velocity and Content Freshness]]></title>
            <link>https://medium.com/the-telegraph-engineering/news-in-real-time-the-telegraphs-approach-to-publishing-velocity-and-content-freshness-ad417cfe3c58?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/ad417cfe3c58</guid>
            <category><![CDATA[news]]></category>
            <category><![CDATA[digital-media]]></category>
            <category><![CDATA[news-delivery-systems]]></category>
            <category><![CDATA[reliability-engineering]]></category>
            <dc:creator><![CDATA[Youssef Mubarak]]></dc:creator>
            <pubDate>Tue, 07 Jan 2025 16:51:31 GMT</pubDate>
            <atom:updated>2025-02-12T11:40:20.240Z</atom:updated>
            <content:encoded><![CDATA[<p>Discover how The Telegraph ensures fast news delivery and up-to-date content.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kfapLs2aDoOg4e3aGTUXCg.png" /><figcaption>Photo by Lisa Fotios from Pexels</figcaption></figure><p>In today’s news world, timely and accurate information is very critical and breaking news and frequent updates are vital for media companies to maintain credibility and readership.</p><p>Thus, measuring the news publishing velocity, which is how quickly the publish-ready content is made available to our readers, and content<strong> </strong>freshness, which means that the most up-to-date content is always displayed, have become increasingly critical in today’s fast-paced world.</p><h3>Why Do Content Freshness and Publication Speed Matter?</h3><p>By tracking how quickly stories transition from <em>publication-ready</em> to <em>accessible</em> and ensuring the latest content is delivered, we enhance engagement, identify opportunities to improve operational efficiency and remain competitive. These advantages can be summarized as follows:</p><ul><li><strong>Boosting Visibility in the Media Landscape</strong>: Being the first to report on significant events enhances The Telegraph’s position as a leading news source.</li><li><strong>Building Reader Trust</strong>: Timely and transparent updates on new facts or corrections demonstrate journalistic integrity, strengthening trust and audience loyalty.</li><li><strong>Enhanced SEO rankings and search engine trust</strong>: Consistent updates signal to search engines that the site is active and <a href="https://www.conductor.com/academy/authority/">authoritative</a>, outperforming stagnant content and drawing in more readers.</li><li><strong>Dynamic site experience and Increased engagement</strong>: Frequent updates encourage readers to return, and create a vibrant, immediate feel, keeping the site lively and engaging.</li></ul><h3>How Does Content Publication Work?</h3><p>To understand The Telegraph’s approach to addressing this challenge, it’s important first to provide some context on the underlying technology. Since Telegraph’s content is managed via Adobe’s CMS: <a href="https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/overview/introduction">Adobe Experience Manager as a Cloud Service</a> (AEMaaCS), we need to explore how content propagates through the various layers of the system to ensure seamless publication and distribution.</p><h3>The Lifecycle of Article Publication</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u-M387g6_LlF4V1Fe00Ygg.png" /><figcaption>Figure 1: Content Publication Lifecycle</figcaption></figure><ol><li><strong>Telegraph Authoring</strong><br>The content creation process begins with our custom <strong>Telegraph</strong> <strong>Authoring</strong> tool. This provides an easy-to-use interface for editors to draft, revise, and finalise the article. The content itself is persisted in the Author layer of Adobe Experience Manager (AEM). After the content is crafted, it undergoes editorial workflows, including approvals and revisions, ensuring the quality and accuracy of the article. Once approved, it’s ready for publication.</li><li><strong>AEM Author:</strong><br>This is where the article content and associated assets are stored. In Adobe Experience Manager, the <strong>Author</strong> instance hosts the content repository. In our case, it also acts as the intermediary that receives publish requests from the Telegraph Authoring and initiates a replication request to publish the content to the <em>Publisher</em>.</li><li><strong>Publisher:</strong><br>After the author finalises the content and hits the “Publish” button, the published article gets replicated from the authoring environment to the <strong>Publisher</strong> instance. In other words, the Publisher instance in AEM handles the initial steps of making the content live and ensuring it becomes accessible to further layers.</li><li><strong>Dispatcher:</strong><br>The Dispatcher caches content to reduce server load and speed up delivery to our readers. It ensures that frequently accessed articles are quickly served, reducing the load on the backend and improving readers&#39; response times. In addition, this is where the resolution of Server-Side Includes (SSI) takes place, which we will mention later.</li><li><strong>Fastly CDN:</strong><br>It acts as a layer that further optimises the speed and scalability of content delivery by caching it at edge servers close to our readers. This reduces latency and ensures that readers, regardless of their location, experience fast load times for the latest articles.</li><li><strong>External</strong> <strong>CDN:</strong><br>To enhance global reach and reliability, the content is also distributed through another external CDN. This provides an additional layer of global distribution, ensuring redundancy, fast loading speeds, and protection from traffic spikes. Together with Fastly, it ensures the smooth, fast, and secure delivery of content to readers worldwide.</li></ol><p>In summary, when an article has passed all editorial workflows, including revisions and approvals, and the ‘Publish’ button is clicked in our content authoring platform, the content gets distributed across various layers of the system. Each of these layers works in harmony to ensure that articles are published efficiently, cached appropriately, and delivered quickly to a global audience, maintaining both performance and reliability.</p><h3>Measuring Publishing Velocity</h3><p>We follow a multifaceted approach that starts with the implementation of timestamp-based versioning to ensure each change is accurately recorded and tracked over time. This enables us to maintain a clear history of updates. Once a page is published, we utilise an event-driven approach that checks the live version of the page to confirm it reflects the most recent changes. The sections below provide more information along with the key challenges of this approach.</p><h4>Timestamp-based Versioning</h4><p>At a high level, to distinguish the latest content from previous versions on the client side, we mark each update with a timestamp in the article’s HTML using a predefined format. For example, if we publish an article about a breaking political event on <em>November 1, 2024, at 3:00 PM</em>, and later update it at <em>3:15 PM</em>, our system ensures that the updated timestamp is reflected in the article’s markup, signalling the change.</p><h4>Event-driven Approach</h4><p>We leverage Google Cloud Platform (GCP) offerings, utilising a Pub/Sub topic to hold the publish event messages alongside a serverless Cloud Function that acts as our monitoring bot. This process works as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O8dt4lJNAecTyVj7HBubxQ.png" /><figcaption>Figure 2: A simplified view of using GCP and Datadog for measuring Publishing Velocity</figcaption></figure><ol><li><strong>Listening to Publish Events</strong>: The Cloud Function subscribes to the Pub/Sub topic to receive notifications whenever new articles are published.</li><li><strong>Making Requests</strong>: Upon receiving a publish event, the Cloud Function sends HTTP requests to the published article page, simulating how a real reader would access it.</li><li><strong>Checking Versions</strong>: The function verifies whether the article has been updated by checking the latest timestamp version and matching it with the expected one received in the publish event.</li><li><strong>Monitoring</strong>: The function logs metrics such as publish times, errors, and any discrepancies. These are then reported to our Datadog dashboard for real-time monitoring and analysis.</li></ol><h4><strong>Key Challenges</strong></h4><p>While this approach may seem straightforward, it is not without its challenges. The main ones are:</p><ol><li><strong>Impact on SEO</strong>: Improperly managed timestamps in the article’s HTML, which may already contain other metadata such as the latest modification date and <a href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data">structure data</a>, could lead to confusion about the content’s recency and negatively affect search engine optimisation (SEO).</li><li><strong>Outdated Cache</strong>: As the CDNs may cache the article page, this can result in our monitoring bot seeing outdated content instead of fresher content at the previous layers.</li><li><strong>Content Propagation Bottlenecks</strong>: In our multi-layered system, content propagation can encounter bottlenecks at various stages. As a result, the absence of the latest updates at the outer layer provides limited insight into where the content update may have stalled along its journey to the final destination.</li><li><strong>Independently Updatable SSI Content</strong>: Some pages exist within a parent-child structure, where the publicly available parent page includes references to one or more child pages via server-side inclusion (SSI). For example, a Live Blog may have references to Posts, though Posts are not independently accessible. These posts can be updated and republished separately from the parent. However, we want to ensure that the publicly visible parent page reflects the latest content from its child pages as well as measures how quickly it integrates these updates.</li></ol><h4><strong>Addressing the challenges</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YkSZpyy4f6vyUA3XO6hkww.png" /><figcaption>Figure 3: Integrated Components Overview</figcaption></figure><p>To tackle these challenges, we must carefully evaluate both our use of timestamp-based versioning and the effectiveness of our event-driven approach.</p><p><strong>1. SEO Protection: Embed Timestamps in Comments</strong><br>To mitigate any potential issues when adding metadata related to the page’s recency, we insert the timestamp information within an HTML comment. Comments are ignored by browsers and generally disregarded by most web crawlers. This ensures that they do not interfere with page rendering or impact search engine optimisation.</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html lang=&quot;en&quot;&gt;<br>   &lt;!-- &lt;timestamp-key&gt;: &lt;timestamp-value&gt; --&gt;<br>&lt;/html&gt;</pre><p><strong>2. Outdated Cache: Cache Bypass with Allowlists</strong><br>Bypassing cache via allowlists is a strategy used in Content Delivery Networks to allow specific requests or clients to bypass the cache entirely based on defined criteria. This is typically done by creating an “allowlist” of conditions, such as IP addresses, user agents, or request headers, that should always fetch fresh content directly from the origin server instead of the cached version. This approach ensures our Cloud Function can make requests while ensuring the latest version of the content is fetched, bypassing the cache.</p><p><strong>3. Content Propagation Bottleneck Detection</strong>: <strong>Granular Hop Times</strong><br>By configuring the requests in our Cloud Function to bypass CDN caches and target deeper layers directly, we can make two types of requests: one that bypasses the cache and one that doesn’t. This allows us to measure content propagation times both before and after the cache, providing insights into latency at each stage. We’ve identified several key timing points for tracking. These include:</p><p>a. <strong><em>time-at-author</em></strong>: the timestamp when the authoring instance initiates a publish event.</p><p>b. <strong><em>time-at-pubsub</em></strong>: the timestamp when the Cloud Function is triggered upon the publish event’s reception by Pub/Sub.</p><p>c. <strong><em>time-to-origin</em></strong>: the time it took for the content to be available at Fastly.</p><p>d. <strong><em>time-to-edge</em></strong>: the time it takes for content to reach the edge CDN.</p><p>By adding these time markers in addition to the total publish time, we can gain valuable insights into the latency at each stage of the delivery pipeline if we face any issues during our monitoring of the publish velocity.</p><p><strong>4. Independently Updatable SSI Content: Retrieve Parent Page When Child Pages are Published</strong></p><p>When a Post page (a child page) is published, we retrieve the URL of its parent Blog page and create a request for that URL. Then, we ensure the parent page displays the latest updates from its associated child pages by looking at the timestamp marker of the latest updated child page within the parent page. Eventually, we compute the speed of child page updates by measuring the time elapsed between the publish event (see <em>Figure </em>3) and when the updates are reflected on the parent page.</p><h4>Leveraging Real-Time Data in Datadog</h4><p>All metrics gathered by the Cloud Function are visualized in real time on our Datadog dashboards. We leverage Datadog to define and monitor <strong>SLIs (Service Level Indicators) </strong>based on the publish time calculations.</p><p>Publish time thresholds differ by content type. For example, for <strong>live articles</strong> (such as reporting football matches, elections, and breaking news), the publish time must be almost instant to ensure updates are available to readers promptly. On the other hand, for regular articles, slightly more relaxed thresholds are acceptable as the content doesn’t require frequent updates.</p><p>Alerts are triggered if any SLI falls below the defined thresholds, and our on-call is notified immediately. This ensures rapid identification and resolution of issues, maintaining the performance standards of our publishing workflow.</p><h4>Summary</h4><p>The publication process leverages Adobe Experience Manager for content creation and distribution, ensuring efficient and timely delivery to readers through caching and content delivery networks.</p><p>In this multi-layered system, we employ timestamp-based versioning and an event-driven approach to track updates across each layer, identifying key measurement points to detect potential bottlenecks. This ensures our metrics accurately reflect publish velocity and workflow efficiency, enabling us to proactively address any potential issues.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ad417cfe3c58" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/news-in-real-time-the-telegraphs-approach-to-publishing-velocity-and-content-freshness-ad417cfe3c58">News in Real Time: The Telegraph’s Approach to Publishing Velocity and Content Freshness</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Leveraging serverless Google Cloud Platform features for fun and profit]]></title>
            <link>https://medium.com/the-telegraph-engineering/leveraging-serverless-google-cloud-platform-features-for-fun-and-profit-3ec0b7e938b0?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/3ec0b7e938b0</guid>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <dc:creator><![CDATA[Georgios Makkas]]></dc:creator>
            <pubDate>Wed, 06 Dec 2023 08:35:42 GMT</pubDate>
            <atom:updated>2023-12-06T08:35:42.546Z</atom:updated>
            <content:encoded><![CDATA[<h4>How Telegraph Engineering used the benefits of the serverless paradigm to get rid of technical debt and reduce operational costs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6g6pbaSI4Q4S55OvRyOtRw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@hazelz?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Hazel Z</a> on <a href="https://unsplash.com/photos/a-computer-screen-with-a-cloud-shaped-object-on-top-of-it-FocSgUZ10JM?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a>. Used under the <a href="https://unsplash.com/license">Unsplash License</a></figcaption></figure><h3>Just a simple service</h3><p>When object cache is mentioned, engineers tend to think of static assets. Images, videos, text. All of which can be combined to make reports, stories, opinion pieces and much more. Put that all together and it is easy to see an online newspaper on the other end.</p><p>As a news organisation, the Telegraph relies on layers upon layers of caches to serve content all around the world.</p><p>As several people have observed (including <a href="https://martinfowler.com/bliki/TwoHardThings.html">Martin Fowler</a>), cache invalidation is a real challenge. In the Telegraph’s context, certain actions require the cache to be invalidated on demand. For that purpose, the Platforms team constructed a cache flush service to clear the cache of several layers on demand.</p><p>Seems simple enough; a service that clears caches on request. Yet the years have not been kind to it. Feature creep, dead code and quick patches took their toll and maintaining the service was becoming a real chore.</p><h3>Tech debt is never fun</h3><p>A rolling stone gathers no moss, goes the old proverb, and there is no better saying to express the need for an organisation to be fast-moving, lest it be left behind with no hope of catching up to competitors and, more importantly, customers. The Telegraph is no different in that regard. Just as the torrent of news never stops, the organisation needs to be on the cutting edge of technology to secure and improve upon the competitive advantage that makes this news organisation unique and successful.</p><p>Striving to be ahead of the current has great benefits, but there are a lot of challenges as well, readily apparent for anyone who has worked in technology for a while. One of the most glaring ones is the accumulation of technical debt.</p><p>Every engineer who has been around the block knows the feeling. The next task arrives and there is a need to improve upon a project with no commit in years. Documentation is non existent. A defeated sigh, a couple hours (or days) of struggling and the new feature is there. The feature is shipped, and the project is forgotten for a while. A new feature request comes. Now, the changes take a bit longer. A patch here and there, no reason for a full solution now. Then, a new feature request.</p><p>A couple of feature requests down the line, patch upon quick hack, it becomes literally impossible to modify the functionality without re-writing the whole thing. And new feature requests keep coming.</p><h3>In hindsight, we should …</h3><p>One of the benefits of working at the Telegraph is that when such a situation is detected, it is dealt with as a serious concern. As such, engineers are encouraged to re-evaluate architectural decisions of the past and, more importantly, request resources to deal with those issues.</p><p>Of course, no organisation wants to be bogged down by the constant modernisation of the technical stack, which is truly an exercise in futility; technical debt is part of the reality of software development. However, great organisations take into account concerns of such nature and, when there is an opportunity, give engineers the go-ahead to fix those issues and bring the technical stack up to speed.</p><p>A fresh technical solution, time-boxed, with undeniable benefits, is hard to turn down.</p><h3>Examining the old</h3><p>Re-architecture starts, as one would expect, by examining the service in question.</p><p>One must approach the old service with respect, trying to understand what made that service successful in the first place. It is important to keep the good parts and avoid the not-so-good ones.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jeMyUdwPujyEzZseKitOLw.png" /><figcaption>A microservice deployed on Kubernetes, details abstracted for clarity</figcaption></figure><p>A RESTful Springboot microservice with a MySQL database is as standard a microservice as you can get. But even that basic design needs to be re-examined.</p><p>As clients communicate with the service using REST, that should be expected to remain the same for the new design as well. After all, communication contracts should only change if there is an absolute need for it.</p><p>Regarding the MySQL database, examining the service code reveals that the need for it is the communication with 3rd-party cache providers. Rate limits are always a concern; hence, there is a need to keep a steady rate of requests. To achieve that, the database works as a queue, with the service polling the database for stored jobs. From this, we can infer two points. One, rate limits are a concern and two, some clients do not mind asynchronous communication.</p><p>Other issues become apparent if one is inclined to observe the operation of the service. The daily requests are not a lot, 30 to 200; however, the service operates 24/7, consuming resources and accumulating costs. As such, the MySQL database queue remains empty for most of the time, with the maximum amount of queue size a measly 2 items. Maintaining a full MySQL database for this load seems like a waste of resources.</p><p>Infrastructure-wise, the service itself is deployed on a Kubernetes cluster, with the database deployed using the CloudSQL product. The Platforms team is doing an excellent job in maintaining an operational, up-to-date cluster, but as any DevOps team would attest, the inherent complexity of maintaining a Kubernetes cluster can be frustrating at times. Avoiding that complexity would be ideal.</p><p><strong>To recap</strong>:<br>+ RESTFull<br>+ Rate Limits<br>+ Async<br>- 24/7 Operation<br>- Database Queue<br>- Infrastructure complexity</p><h3>Who needs servers?</h3><p>An important part of the day-to-day operations at the Telegraph is the Google Cloud Platform. As the cloud provider of preference, many of our services and operations rely on Google&#39;s building blocks to streamline development and operations.</p><p>Evaluating the offerings available, we realised we could leverage the serverless offerings to turn our requirements into a modern, low-cost architecture.</p><h3>A new perspective</h3><p>The low rate of daily requests meant that the service did not need to run 24/7. For that purpose, the team decided to turn the deployment into a <a href="https://cloud.google.com/run">Cloud Run service</a> that scales down to zero. In that way, compute resources would only be used when needed. As an added benefit, it meant no more struggling with Kubernetes major version upgrades.</p><p>However, going that route meant that the Springboot application needed reconsidering. Springboot has a notoriously slow startup time and the JVM is not well suited to the strict cold-start requirements that the scaling down to zero paradigm requires. The decision was made to re-write the service in Python using <a href="https://fastapi.tiangolo.com/">Fast API</a> since the team is experienced in Python development and the cold-start and response times are well within the acceptable limits. Also, re-writing the service would give the team the opportunity to simplify the software design and do away with any functionality that had outlived its use.</p><p>The next challenge to tackle was the rate limits of the 3rd-party APIs. As the investigation of the original service showed, the daily requests are not nearly close to reaching the rate limits, but the design needs to be secure against a burst of requests coming in. Such a scenario can easily happen on a breaking news day.</p><p>Given that clients are fine with asynchronous requests, meaning they can request a clear cache and not wait for the result, an asynchronous part can be added to the design that takes care of the rate-limiting issue. To avoid using a database as the old architecture did, an offering called <a href="https://cloud.google.com/tasks">Cloud Tasks</a> was used to hold a processing queue. Cloud Tasks acts as a buffer queue, where the rate of delivery can be defined, along with a default behaviour to slow down requests when a <strong>429 Too many requests</strong> error surfaces. All that remained was a small additional service that took care of the scheduling in the queue, which would also be implemented in Cloud Run using Fast API.</p><p>Finally, clients should have the option of calling the cache clear service directly or going through the asynchronous path. For that purpose, both services would be exposed using <a href="https://cloud.google.com/load-balancing">Load Balancers</a> configured to handle TLS and drop unauthenticated traffic.</p><p>After careful consideration of the points above, here is the resulting design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mKLo-JMr4HrFxsaOTvsB8w.png" /><figcaption>Simple, modern, cost-effective design</figcaption></figure><h3>Out with the old one, in with the new</h3><p>After the new design was reviewed and implemented, the implementation was moved to production for a dry run. When that was verified, the proxy was pointed to the new services, diverting the traffic to the new infrastructure. Monitoring using <a href="https://cloud.google.com/logging">Cloud Logging</a>, we verified that everything was operating as expected.</p><p>As expected, the requests are scarce, proving that the scale to zero Cloud Run design was an fitting choice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L69x_ydwenQhmKF_BD8p3g.png" /><figcaption>Cloud Run — Cache Clear service</figcaption></figure><p>The Cloud Tasks queue demonstrates that our assumption of 1–2 concurrent tasks was accurate and easily manageable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7bwsFf-bMEUhCukwZuEe_Q.png" /><figcaption>Cloud Tasks — Queue</figcaption></figure><p>With the new design, we were able to:</p><ul><li>Reduce the cost of operation for the service by scaling compute to zero</li><li>Reduce the maintenance overhead of the service by leveraging Google-managed infrastructure</li><li>Shed most of the technical debt of the old service</li></ul><p>Moving forward, we will consider all opportunities that the serverless paradigm offers to design architectures that are more reliable, modern and cost-effective, all the while keeping an eye out for old services in need of a new coat of paint.</p><p><a href="https://uk.linkedin.com/in/georgios-paris-makkas-981340a1"><em>Georgios Makkas</em></a><em> is a Senior Platform Engineer at The Telegraph Media Group</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ec0b7e938b0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/leveraging-serverless-google-cloud-platform-features-for-fun-and-profit-3ec0b7e938b0">Leveraging serverless Google Cloud Platform features for fun and profit</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</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 set up a dead-letter for an Eventarc trigger using gcloud CLI and track your serverless…]]></title>
            <link>https://medium.com/the-telegraph-engineering/how-to-set-up-a-dead-letter-for-an-eventarc-trigger-using-gcloud-cli-and-track-your-serverless-599a3fd36fd5?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/599a3fd36fd5</guid>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[g-cloud]]></category>
            <category><![CDATA[pub-sub]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[eventarc]]></category>
            <dc:creator><![CDATA[Irfan Durrani]]></dc:creator>
            <pubDate>Mon, 24 Jul 2023 07:45:33 GMT</pubDate>
            <atom:updated>2023-07-24T07:45:32.940Z</atom:updated>
            <content:encoded><![CDATA[<h4>Failsafe: building more reliable serverless applications</h4><h3>How to set up a dead-letter for an Eventarc trigger using gcloud CLI and track your serverless exceptions</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cs44Rqv28ptGxSZi6s7YcQ.png" /><figcaption>Attaching a dead-letter to Eventarc trigger using gcloud CLI</figcaption></figure><blockquote>Welcome to the first of a 2-part series on how you can set up dead-letter policies for Eventarc triggers on serverless applications. This time we look at creating one using gcloud commands. Next time, we will guide you on doing the same using Terraform.</blockquote><p>Serverless has presented a big opportunity in <em>The Telegraph</em>’s quest for more efficient and environmentally-friendly services. Instead of a server or Kubernetes-based microservice running 24 hours a day, we can leverage GCP (Google Cloud Platform) Cloud Functions that only execute code for a small fraction of that time. One of the crucial pieces of building out a reliable serverless-based service is how and when you pull the trigger on the code executions and what happens when the code throws an exception.</p><p>Enter Eventarc triggers, which offer breadth and depth. Breadth in what can act as a trigger. Do you need to run code based on logging events, a pubsub topic, write events on a bucket, or changes to specific file or filetypes? They can all be triggers. And depth in what they can execute. Eventarc triggers can fire up Cloud Run containers or Cloud Functions, giving you the choice of container-based or serverless code executions that are suitable for a great deal of tasks.</p><p>But like many out-of-the-box solutions, Eventarc triggers are also a closed box with little control over them. In this blog, we’ll explore how to configure the Eventarc trigger’s behaviour in a way that gives us more control.</p><p>At its core, Eventarc events consist of a simple pubsub architecture. If a trigger is set to fire on a bucket object write event, it would essentially send a message to its pubsub topic, and a subscriber would consume the message and act on it.</p><p>Every pubsub subscription can be configured to have a dead-letter policy. Messages are sent to a dead-letter topic if a number of delivery attempts are exhausted with no acknowledgement from the subscription. This provides us with a way of exposing and managing failures of the code to complete.</p><p>Below, we will show you how to create your dead-letter policy using gcloud CLI.</p><h3>The initial setup</h3><h4>Prerequisites</h4><p>To perform the following steps, you will need to ensure the following:</p><ul><li>You have the <a href="https://cloud.google.com/sdk/docs/install">gcloud CLI</a> installed.</li><li>You have a GCP account and have configured its access to a GCP project with gcloud CLI.</li><li>Your account must have the requisite permissions to create the resources detailed below in your project.</li></ul><h4>Getting started</h4><p>In thefunction-deploy branch of <a href="https://github.com/durranee/gen2-pubsub-function-gcloud/tree/function-deploy"><strong>this repository</strong></a>, you will find instructions on deploying a simple cloud function. The cloud function is set to trigger a pubsub message to a topic and will print a greeting message containing the message.</p><p>If the message=&quot;fail&quot;, the code is set to raise an exception, which will cause the function to exit ungracefully.</p><h4><strong>Create the pubsub topic and function</strong></h4><pre>## create pubsub topic<br>gcloud pubsub topics create demo-pubsub-topic<br><br>## create cloud function<br>gcloud functions deploy demo-pubsub-function \<br>    --gen2 \<br>    --runtime=python311 \<br>    --region=europe-west2 \<br>    --source=./src \<br>    --entry-point=subscribe \<br>    --trigger-topic=demo-pubsub-topic</pre><h4><strong>Trigger function (print greeting)</strong></h4><pre>gcloud pubsub topics publish demo-pubsub-topic --message=&quot;World&quot;</pre><p>This will cause the function to execute and print the greeting Hello World, and we can verify this by looking at function logs and running the following command.</p><pre>gcloud beta functions logs read demo-pubsub-function — region=europe-west2 — gen2</pre><h4><strong>Trigger function (fail)</strong></h4><pre>gcloud pubsub topics publish demo-pubsub-topic --message=&quot;fail&quot;</pre><p>This message will cause the function code to throw an exception, which will cause the function to exit ungracefully. As before, we can verify this by checking the function logs.</p><h4>Enable retry</h4><p>At this point, the function is set to not retry upon failure. We can change that by adding a <strong>— retry</strong> flag to our function deploy command:</p><pre>gcloud functions deploy demo-pubsub-function \<br>    --gen2 \<br>    --runtime=python311 \<br>    --region=europe-west2 \<br>    --source=./src \<br>    --entry-point=subscribe \<br>    --trigger-topic=demo-pubsub-topic \<br>    --retry</pre><p>If you now open your GCP console and check the function information, and go to the trigger tab, you’d see that the retry-on-failure is enabled.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*pcpdaiyeLbrx63qpiwmVsw.png" /><figcaption>Eventarc trigger with retry enabled</figcaption></figure><p>Also, if you head over to the <a href="https://console.cloud.google.com/cloudpubsub/topic/list">Pubsub page</a> and click on the topic we created, you will see that it has a phantom pubsub subscription attached to it. We never created that subscription; instead, the gcloud functions deploy command took the liberty of creating and attaching that subscription to the topic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b634efSLuPPIBlKTFhLPZA.png" /><figcaption>The gcloud functions deploy command automatically creates a subscription for the topic</figcaption></figure><p>By clicking on the subscription and then the Details tab, you’d see that the dead-lettering is disabled on that, but back-off and retry are enabled because we added the--retry flag.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_PpiH3_5tRU6hbTy4Nr-mw.png" /><figcaption>Subscription without dead-letter</figcaption></figure><h3>Dead-letter Setup</h3><p>First thing we’d need is a pair of pubsub topic and subscription to use as dead-letter. A dead-letter topic is just another pubsub topic.</p><h4>Create a dead-letter topic/subscription</h4><p>The following commands will get us the pubsub topic and subscription.</p><pre>gcloud pubsub topics create demo-deadletter-topic<br>gcloud pubsub subscriptions create demo-deadletter-subscription --topic=demo-deadletter-topic</pre><h4>Attaching the dead-letter topic</h4><p>From the UI, it’s easy for us to get the Eventarc subscription name, but where’s the fun in that? We will instead use the gcloud command to get the subscription id and then use that. Since it’s not straightforward, we’d have to fetch this information in two different steps:</p><ul><li>Get the function info and grab the trigger name from that</li><li>Using the trigger name, get trigger info which contains the subscription name</li></ul><p>The following commands will help us achieve that:</p><pre>trigger_name=$(gcloud functions describe demo-pubsub-function --region=europe-west2 --format=&#39;value(eventTrigger.trigger)&#39;)<br>trigger_subscription=$(gcloud eventarc triggers describe $trigger_name --location europe-west2 --format=&#39;value(transport.pubsub.subscription)&#39;)</pre><p>We can run echo $trigger_subscription to confirm whether we have the correct subscription id.</p><h4>Update subscription to attach the dead-letter</h4><p>Let&#39;s update the Eventarc subscription and attach the dead-letter topic to it.</p><pre>gcloud pubsub subscriptions update $trigger_subscription \<br>    --dead-letter-topic=demo-deadletter-topic</pre><h4>Grant required permissions to the project service account</h4><p>One last and necessary step is to give the GCP project’s pubsub service account the roles/pubsub.subscribe permission on the Eventarc subscription and roles/pubsub.publisher to the dead-letter publish. This is very important and it will ensure the project service account has all the permissions required to be able to read the failed messages and forward them to the dead-letter topic.</p><p>The project’s pubsub service account email format is as below:<br>service-<strong>&lt;GCP_PROJECT_NUMBER&gt;</strong>@gcp-sa-pubsub.iam.gserviceaccount.com</p><p>For example, if your project number is 1234567890, the service account would be <strong>service-1234567890@gcp-sa-pubsub.iam.gserviceaccount.com</strong></p><p>We can give the service account the required permissions by running:</p><pre>## assign pubsub subscriber role to read messages from trigger subscription<br>gcloud pubsub subscriptions add-iam-policy-binding $trigger_subscription \<br>    --member=&quot;serviceAccount:service-&lt;GCP_PROJECT_NUMBER&gt;@gcp-sa-pubsub.iam.gserviceaccount.com&quot; \<br>    --role=&quot;roles/pubsub.subscriber&quot;<br><br>## assign pubsub publisher role to allow publishing the dead letter topic<br>gcloud pubsub topics add-iam-policy-binding demo-deadletter-topic \<br>    --member=&quot;serviceAccount:service-&lt;GCP_PROJECT_NUMBER&gt;@gcp-sa-pubsub.iam.gserviceaccount.com&quot; \<br>    --role=&quot;roles/pubsub.publisher&quot;</pre><p>That’s it, we’re done! We can confirm that by checking our Eventarc subscription.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r4T8WqBLp4JJM2QRjzB8UQ.png" /><figcaption>deadletter attached to Eventarc subscription</figcaption></figure><p>We can also confirm that the entire setup is configured correctly by checking the <strong>DEAD LETTERING</strong> tab.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Oj80fzJLKrROtAgowYe7dQ.png" /></figure><h3>Test the dead-letter functionality</h3><p>Send a message to the pubsub topic that will make the function code raise an exception.</p><pre>gcloud pubsub topics publish demo-pubsub-topic --message=&quot;fail&quot;</pre><h4><strong>Check pubsub dead-letter for failed messages</strong></h4><p>Due to the retry and backoff mechanism, this might take a couple of minutes to come through.</p><pre>gcloud pubsub subscriptions pull demo-deadletter-subscription</pre><p>The final code can be found in the <a href="https://github.com/durranee/gen2-pubsub-function-gcloud">main branch of this repo</a>.</p><blockquote>Stay tuned for part 2 of our guide, where we will walk you through how to configure a dead-letter to Eventarc using Terraform</blockquote><p><em>Irfan Durrani is a lead platform engineer at The Telegraph. You can follow him on </em><a href="https://www.linkedin.com/in/durranee/"><em>LinkedIn</em></a><em>. You can also follow The Telegraph Engineering team on </em><a href="https://www.linkedin.com/groups/13828540/"><em>LinkedIn</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=599a3fd36fd5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/how-to-set-up-a-dead-letter-for-an-eventarc-trigger-using-gcloud-cli-and-track-your-serverless-599a3fd36fd5">How to set up a dead-letter for an Eventarc trigger using gcloud CLI and track your serverless…</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The “Snowball” Effect in Kubernetes]]></title>
            <link>https://medium.com/the-telegraph-engineering/the-snowball-effect-in-kubernetes-7e93dabd67e8?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/7e93dabd67e8</guid>
            <category><![CDATA[sre]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[gcp]]></category>
            <category><![CDATA[site-reliability-engineer]]></category>
            <category><![CDATA[troubleshooting]]></category>
            <dc:creator><![CDATA[Johnny Ooi]]></dc:creator>
            <pubDate>Thu, 01 Dec 2022 08:02:41 GMT</pubDate>
            <atom:updated>2022-12-01T08:02:41.093Z</atom:updated>
            <content:encoded><![CDATA[<h4>How one bad call can lead to hundreds of unwanted pods</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*ajR5QPBkFGUlvja4BUFJAQ.png" /><figcaption>Smooth sailing? GKE deployments don’t always go to plan</figcaption></figure><p>Kubernetes puts the mantra of “fail fast, recover faster” into practice: one thing fails, and another seamlessly pops up to replace it. But what happens when that guiding principle works against it? We’d like to share one such scenario we encountered in GKE, our findings and how we overcame it.</p><p>While we first encountered this issue some 2 years ago, I have seen it crop up on StackOverflow, so it’s not a rare occurrence.</p><p>I <a href="https://github.com/kubernetes/kubernetes/issues/93783">raised it</a> in the Kubernetes project, and have also seen it referenced in other issues, too.</p><h3><strong>Symptoms</strong></h3><p>One day we noticed that Jobs and CronJobs in our cluster were acting strangely; multiple Jobs had spawned and sat there for more than an hour without creating any pods.</p><h3>Digging into the Problem</h3><p>Investigating other jobs, we found that a single CronJob in one of our namespaces was responsible for creating more than 900 pods. These pods had completed but had not been removed.</p><p>The CronJob was scheduled to run every minute, and the definition of the CronJob had valid values for the history — sensible values for .spec.successfulJobsHistoryLimit and .spec.failedJobsHistoryLimit were set. Even if they weren’t, the defaults would (or should) be used.</p><p>Why did we have over 900 cron pods, and why weren’t they being cleaned up upon completion? Just in case the number of pods were causing problems, we cleared out the completed pods:</p><p>kubectl delete pods -n {namespace} $(kubectl get pods -n {namespace} | grep Completed | awk &#39;{print $1}&#39; | xargs)</p><p>Even after that, new jobs weren’t spawning pods. In fact, more CronJob pods were appearing in this namespace. So we disabled (suspended) theCronJob</p><p>kubectl patch cronjobs -n {namespace} {cronjob-name} -p &#39;{&quot;spec&quot; : {&quot;suspend&quot; : true }}&#39;</p><p>That also didn’t help; pods were still being generated. Which is weird — why is a CronJob <strong>still</strong> spawning pods, even when it’s suspended?</p><h3>The Lightbulb Moment</h3><p>CronJobs generate Job objects when their schedules trigger. On checking the Job objects, we found <strong>more than 3,000 </strong>Job objects; a lot more than there should for something that runs once a minute. So we deleted all the CronJob related Job objects</p><p>kubectl delete job -n {namespace} $(kubectl get jobs -n {namespace} | grep {cronjob-name} | awk &#39;{print $1}&#39; | xargs)</p><p>This reduced the pod count, but did not help us determine why the other Job objects were not spawning pods.</p><h3>Bringing In Reinforcements</h3><p>We raised a support ticket with Google, who initially sent us this logs snippet (redacted):</p><p>2020-08-05 10:05:06.555 CEST - Job is created</p><p>2020-08-05 11:21:16.546 CEST - Pod is created</p><p>2020-08-05 11:21:16.569 CEST - Pod (XXXXXXX) is bound to node</p><p>2020-08-05 11:24:11.069 CEST - Pod is deleted</p><p>2020-08-05 12:45:47.940 CEST - Job is created</p><p>2020-08-05 12:57:22.386 CEST - Pod is created</p><p>2020-08-05 12:57:22.401 CEST - Pod (XXXXXXX) is bound to node</p><p>Spot the problem? The time between “Job is created” and “Pod is created” is about 80 minutes in the first case, and 12 minutes in the second one. It took <strong>80 minutes</strong> for the Pod to be spawned.</p><h3>It All Becomes So Clear…</h3><p>This is where it dawned on me about what was possibly going on.</p><ul><li>The CronJob spawned a Job object. It tried to spawn a pod, and that took a significant amount of time, far more than the 1 minute between runs.</li><li>The next cycle, the CronJob looks to see if it has a running pod due to the .spec.concurrencyPolicy value.</li><li>The CronJob does not find a running pod so generates another Job object, which also gets stuck waiting for pod generation.</li><li>And ad infinitum.</li></ul><p>Each time, a new Job gets added, gets stuck waiting for pod generation for an abnormally long time, which causes another Job to be added to the namespace which also gets stuck…</p><p>Eventually, the pod will generate but by then there’s a backlog of Jobs, meaning that even if I suspended the CronJob, it won’t have any effect until the Jobs in the backlog are cleared or deleted.</p><h3>The Cause</h3><p>Google investigated further, and found the culprit:</p><p>Failed calling webhook, failing open www.up9.com: failed calling webhook &quot;www.up9.com&quot;: Post <a href="https://up9-sidecar-injector-prod.up9.svc/mutate?timeout=30s:">https://up9-sidecar-injector-prod.up9.svc:443/mutate?timeout=30s:</a> net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)</p><p>We were testing up9 and this configuration was using a webhook, so it looked like a misbehaving webhook was causing this problem. We removed the webhook and the webhookconfigs, and everything started working again.</p><h3>Lessons Learnt</h3><p>So where does this leave us? Well, a few thoughts:</p><ul><li>A misbehaving/misconfigured webhook can cause a snowball effect in the cluster, causing multiple runs of a single CronJob without cleanup — successfulJobsHistoryLimit and failedJobsHistoryLimit values are seemingly ignored.</li><li>This could break systems where the CronJob is supposed to be run mutually exclusively, since the delay in pod generation could allow two cron pods to spawn together, even though the CronJob has a concurrencyPolicy set as Forbid.</li><li>If someone managed (whether intentionally or maliciously) to install a webhook that causes this pod spawning delay, and then adds a CronJob that runs once a minute — and then maliciously crafts the job to never finish, this snowball effect will cause the cluster to run out of resources and/or scale up nodes forever or until it hits the max allowed by your configuration. Fortunately, this is now known by the Kubernetes team.</li></ul><p><em>Johnny Ooi is a Senior Site Reliability Engineer at The Telegraph. You can follow him </em><a href="https://mobile.twitter.com/blenderfox"><em>@Blenderfox</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e93dabd67e8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/the-snowball-effect-in-kubernetes-7e93dabd67e8">The “Snowball” Effect in Kubernetes</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Taking the grind out of article history investigation through Pub/Sub centered architecture]]></title>
            <link>https://medium.com/the-telegraph-engineering/taking-the-grind-out-of-article-history-investigation-through-pub-sub-centered-architecture-9ae3850683af?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/9ae3850683af</guid>
            <category><![CDATA[event-driven-design]]></category>
            <category><![CDATA[pub-sub]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Georgios Makkas]]></dc:creator>
            <pubDate>Tue, 11 Oct 2022 08:03:17 GMT</pubDate>
            <atom:updated>2022-10-12T12:58:16.460Z</atom:updated>
            <content:encoded><![CDATA[<h4>How The Telegraph used an event-driven system to save time and keep track of our stories’ publication</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d6rg3PD99WdY7TjF0lAoHg.jpeg" /><figcaption>Credits to <a href="https://unsplash.com/@krystagrusseck">https://unsplash.com/@krystagrusseck</a>. Used under the <a href="https://unsplash.com/license">Unsplash License</a></figcaption></figure><h3>When old news is bad news</h3><p>A major, multi-week event was underway when a call came in from Editorial: it looked like an old version of a story was appearing on a syndication partner’s feed, but which version?</p><p>A bit of context. At The Telegraph, as well as publishing news across in-house print and digital platforms, syndication means that our stories appear in publications around the world. A vital job of the Platforms team is to make sure that our articles reach our syndication partners safely. With stories evolving on a 24-hour basis, it’s also imperative that the content we are sending out keeps pace with our own reporting.</p><p>On receiving the call from Editorial, we found 2 things; firstly, the article appeared to be out of sync, and secondly, getting to the error’s root cause lay behind a myriad of logs and we could not provide immediate answers. At the same time, this scenario highlighted the need for an altogether better solution. It marked the birth of the Content Status project.</p><h3>A simple event-driven solution</h3><p>Keen to move on from a web of log entries, we decided to keep the design simple. Events would be emitted from each microservice with metadata information about the articles being published to our partners. Those events would be captured by a service that would store them in the proper format in a storage space. The same service would provide the relevant endpoints to expose the information.</p><p>Having worked with Google Cloud’s Pub/Sub before, we felt confident that it would serve as an event queue that would allow us to decouple the event processing from the article publishing. Such a decoupling was crucial; we did not want to impede the high performance of the microservices serving our syndication partners.</p><p>For storage, we opted for an Elasticsearch cluster. With the amount of events expected, Elasticsearch could scale without issue, handling this considerable amount of documents and at the same time providing the search capabilities that Elasticsearch is famous for.</p><p>As for the event processing service, we went with the familiar Springboot project, deployed in a Kubernetes cluster. The horizontal scaling capabilities native in Kubernetes would allow us to handle the message load (or so we thought at that moment. More on that later…).</p><p>To expose the information, we decided to use an internal tool called the Toolbox. It is an in-house solution used to display all kinds of information regarding our articles, as well as provide several functionalities for different departments.</p><p>The following is the finalised system design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vx4JLxyLHx9iKXCUsIf46A.png" /><figcaption>Content Status System Design</figcaption></figure><p>To accommodate the publishing of events, we created a simple library and put it to use in our microservices. With a simple interface, information about article processing could be sent along with any useful metadata (success/failure, error message, etc).</p><p>All of the events were published in one particular topic, to which the event processing microservice was subscribed. Google Cloud Console provides excellent visibility when it comes to the amount of messages published, acknowledged, failed and others.</p><h3>Too much information? Multithreading to the rescue</h3><p>All seemed ready, so we flipped the switch.</p><p>At that moment, a major issue became apparent.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*EYeMI5-nxXZC0WXgD2ywWg.png" /><figcaption>Events waiting to be processed. Count in millions.</figcaption></figure><p>The load on the event processing microservice was huge. Even multiple replicas of the service were not able to handle the amount of events being published. Production conditions can be a very unpleasant surprise.</p><p>We decided to increase the number of processing threads. For those of you familiar with multithreading, you now realise that the number of threads is not as apparent. To play it safe, we simulated an approximation of the traffic on our staging environment and were able to find the golden ratio.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/1*93Ai9Cq0Q76WOILZUKpZEQ.png" /><figcaption>Events actually being processed. Count no longer in the millions.</figcaption></figure><p>After the change, the number of unacknowledged events started to drop sharply. Soon, the service was operating without issues.</p><h3>The answers we need in one place</h3><p>With the service and UI implemented, tracking an article’s syndication history became a breeze. Using an article Id, under the History tab, users can easily track what has happened.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vD2vvqJ-WlSQwd8rdz0xyA.png" /><figcaption>Capture from our internal Toolbox</figcaption></figure><p>Using the tool, we are able to identify:</p><ul><li>If the article was published to one of our Syndication partners</li><li>The latest version of the article that was published</li><li>An initial indication of any failures</li><li>Immediate feedback on the state of an article regarding our Syndication partners</li></ul><p>Now, if Editorial or a Syndication partner needs to know what happened to an article, we can provide a much quicker and more precise answer. On a happy side-note, we are much more able to verify that a release is not affecting article processing.</p><p>So from the pain of trawling through logs, we have managed to implement a system that now provides at-a-glance clarity and reassurance for The Telegraph and its partners, while giving any insights for any potential errors down the line.</p><p><a href="https://uk.linkedin.com/in/georgios-paris-makkas-981340a1"><em>Georgios Makkas</em></a><em> is a Platform Engineer at The Telegraph</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9ae3850683af" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/taking-the-grind-out-of-article-history-investigation-through-pub-sub-centered-architecture-9ae3850683af">Taking the grind out of article history investigation through Pub/Sub centered architecture</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Slack and JIRA to make releases seamless but safe in a world of microservices]]></title>
            <link>https://medium.com/the-telegraph-engineering/using-slack-and-jira-to-make-releases-seamless-but-safe-in-a-world-of-microservices-c554f80328c9?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/c554f80328c9</guid>
            <category><![CDATA[slack]]></category>
            <category><![CDATA[releases]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[jira]]></category>
            <category><![CDATA[github-actions]]></category>
            <dc:creator><![CDATA[Adam Gaudry]]></dc:creator>
            <pubDate>Fri, 13 May 2022 09:02:53 GMT</pubDate>
            <atom:updated>2022-05-13T13:31:09.818Z</atom:updated>
            <content:encoded><![CDATA[<h4>RELEASE MANAGEMENT IMPROVED</h4><h4>How The Telegraph built a smoother release management solution that keeps pace with a busier schedule of changes, while ensuring accountability every step of the way</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CjyTReMuaVnhdW1cSNBD3g.jpeg" /><figcaption>Change in the palm of your hand: an approved release request on the Slack mobile app</figcaption></figure><p><strong>Overview<br></strong><a href="#6c4d">Introduction</a><br><a href="#a3a2">How it works </a><br><a href="#20f1">The user journey in Slack</a><br><a href="#7c63">Automated record-keeping in JIRA</a><br><a href="#0737">Adding Github Action functionality</a><br><a href="#ecd2">The results</a><br><a href="#00ff">Useful links</a></p><p>Microservices sit at the heart of what and how we build software at The Telegraph. This has made for improvements to performance, resilience and the maintenance of our applications. But as the volume of services swells over time, so too does the number of releases we need to make. Every month we perform dozens of releases to our systems. Our dilemma? Ensuring that these changes are properly reviewed, approved and documented, whilst removing any unnecessary friction.</p><p>The right solution for us laid in tools that were already at our disposal. The Telegraph has been using Slack for several years and its <a href="https://api.slack.com/start/building#frameworks">Bolt SDKs</a> make it relatively easy to write custom applications. Likewise, JIRA has long been our primary means of accounting for work, including change requests.</p><p>We found that, by building an API to handle the flow of information and requests between users, Slack and JIRA, we could seek and co-ordinate releases in a more convenient and more visible manner. In addition, we were able to take advantage of <a href="https://github.com/features/actions">Github Actions</a> to add further improvements to the process when making changes to project repositories.</p><p>What follows is truly a joint effort; this project’s creation and continual improvement has been the work of the whole team coming together and contributing ideas, to forge a system that meets our needs brilliantly.</p><h4>How it works</h4><p>This diagram tries to convey the lifecycle of a change request using our system. I have numbered the steps to help lay out the basic chronology.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sfc0oisP6pnFRqUaRrbBAQ.png" /><figcaption>An overview of our release management system</figcaption></figure><h4>The user journey in Slack</h4><p>One of the key functions of our API is to return json strings to Slack that it uses to populate the <a href="https://api.slack.com/surfaces/modals">modal screens</a> for our request process, as well as parse the data being sent over Slack and use it to create and update tickets in Jira. This being the case, I will illustrate just what a release request looks like in Slack from start to finish. Some fields have been obscured because they bear no relevance to our setup.</p><p>1. The process is initiated either by a Slack user entering a slash-command to bring up the release-request form, or triggered by a Github Action.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/165/1*_ArAva8UKW9Yjg1FUy49Mw.png" /><figcaption>An example slash-command</figcaption></figure><p>2. After this is executed, Slack will post a message in a channel that specifically handles this process. The message will prompt them to Review their request or Cancel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/350/1*WAgvDe_5ozUKlEzMvVQP2w.png" /></figure><p>3. On clicking Review, Slack will contact our API and request the json for the modal screen to create a release request. This will include all the details we need to progress the request and create a ticket in Jira. The image below contains some example text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/502/1*AGuDpPSvHvJGRcCZ4INuwA.png" /></figure><p>4. On clicking submit, the request will be posted to the channel with an @here, to alert all members of the channel so someone can tech review and approve it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/538/1*c4sYMb3Tck-pvcW79N8OPQ.png" /></figure><p>5. Once this has been completed the request will appear in a separate channel where management can perform a final review and approval of the change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/535/1*GPVsjhEFjuiGa5PW2WPU9g.png" /></figure><p>6. The management approver can click on More Details, which will result in Slack hitting our API to request the modal screen json that displays the request’s details.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/526/1*Tdl2SGRyded5ZdI6wNT0sw.png" /></figure><p>7. Once management has approved or denied the request it will then send the decision back to the tech approval channel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/704/1*thUeJKT7CHDIMckIs8ZdbQ.png" /></figure><p>8. However, even after approving the request, management can still cancel it later if a scheduling conflict or other reason occurs. They just do this by clicking on the Cancel Release button, as seen below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*lK3U4N7LSiAAcjG62-B0ng.png" /></figure><p>9. After clicking the Cancel Release button, it sends a request to our API for a simple one field screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*VLgz1iHZ057mhKVtT1XYpg.png" /></figure><p>10. This cancellation will then update the initial channel with the cancellation and reason.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/652/1*dg6OHi1Pdo6Vz5YvnJ0BeQ.png" /></figure><h4>Automated record-keeping in JIRA</h4><p>Thanks to our API, the actions being committed in Slack are also being recorded in JIRA without any manual interaction required. I will now illustrate the tickets we create as part of the process.</p><p>1. Once the requester has submitted their release request, a ticket in Jira is created with its status kept accurate to its place in the workflow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AXOQVhPqh38FDg5__IuV8Q.png" /></figure><p>2. Once the ticket has been tech approved, the ticket status is updated.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QR4oxujSuRpHVYQn2if95A.png" /></figure><p>3. Finally, when it has been approved by management, we record it as approved and mark the request status as resolved.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gtz_K7JjpGuRdDGn5WfpxQ.png" /></figure><p>4. If the release is later cancelled, we also update its status and record the reason for cancellation in the ticket.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uHF-sg98bMILM-3_IzSKiA.png" /></figure><h4>Adding Github Action functionality</h4><p>As The Telegraph uses Github, we have added a <a href="https://github.com/features/actions">Github Action</a> that means you can initiate the release request process from a pull request.</p><p>By using this method, we can transpose the release description and other fields directly from the pull request into the release request.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ksaj4gcUxUexbjKllaDAUg.png" /><figcaption>The fields in Slack are automatically populated by the Github Action, partially using the PR description</figcaption></figure><p>We even have another Github Action that we use to template the pull request description, which is also triggered by adding a label to the PR.</p><p>This makes life just a little bit easier and ensures consistent data about changes across our platforms.</p><h4>JIRA calendar that puts changes in context</h4><p>Finally, we use a calendar-based dashboard in JIRA that is populated using a filter for all the changes we want to track. This gives crucial, at-a-glance context to what changes are happening and when, an important step in approving any new requests that may appear.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FIbA6XY8WUprifTslJmkhg.png" /><figcaption>A calendar view of all the Continuous Delivery changes for a sample month</figcaption></figure><h4>The results</h4><p>Our system has made it simpler for different teams to raise release requests in one place and get them reviewed, even from the comfort of the Slack mobile app. This convenience has made the release process far smoother for us and meant that we can keep pace with the high volume of releases we need to keep maintaining and improving our catalogue of services.</p><h4>Useful links</h4><p>Here are some links that will help you if you’re interested in replicating this kind of setup.</p><ul><li><a href="https://api.slack.com/start/building">Building an application for Slack</a></li><li><a href="https://developer.atlassian.com/cloud/jira/software/rest/intro/">JIRA (Cloud) Rest API Documents</a></li><li><a href="https://docs.github.com/en/actions">Github Actions documentation</a></li></ul><p><a href="https://twitter.com/16bithack"><em>Adam Gaudry</em></a><em> is a Platforms Engineer at The Telegraph.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c554f80328c9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/using-slack-and-jira-to-make-releases-seamless-but-safe-in-a-world-of-microservices-c554f80328c9">Using Slack and JIRA to make releases seamless but safe in a world of microservices</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Viafoura Conversations — Making Custom User Badges using Python]]></title>
            <link>https://medium.com/the-telegraph-engineering/viafoura-conversations-making-custom-user-badges-using-python-8ff3658d621d?source=rss----e6218a55f1b0---4</link>
            <guid isPermaLink="false">https://medium.com/p/8ff3658d621d</guid>
            <category><![CDATA[viafoura]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[custom-badge]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[commenting]]></category>
            <dc:creator><![CDATA[Wendy Cocksedge]]></dc:creator>
            <pubDate>Fri, 07 Jan 2022 08:27:37 GMT</pubDate>
            <atom:updated>2022-01-07T16:18:44.912Z</atom:updated>
            <content:encoded><![CDATA[<h3>Viafoura Conversations — Making Custom User Badges using Python</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*Fj3KSEcKXgiwve8S_RxlaQ.png" /><figcaption>Example of how Telegraph authors are displayed in a comments block.</figcaption></figure><p><em>This article looks at how The Telegraph are using the custom badge feature in our recently-integrated, new commenting system, ‘</em><a href="https://viafoura.com/conversations/"><em>Conversations</em></a><em>’ by Viafoura. It’s just one of the tools in their community-building suite, which we chose to implement for its automated moderation and real-time interaction capabilities, to help us drive user engagement. There are also some examples of how to create and assign badges to users by interacting with Viafoura’s API, and how to process a batch of users with a simple Python script.</em></p><p>On all news websites, there exists a never-ending drive to increase user engagement, and having a comments block at the end of an article certainly helps. What’s even better, and makes the comments block more like a conversation, is having your authors contribute to the thread.</p><p>Getting an author to stand out against other users in the comment thread is achieved by adding a label or badge next to their name.</p><p>In Viafoura Conversations, there are quite a few options you can use for labelling up different types of users, with varying results. ‘Trusted Users’ get an icon next to their name, which looks very similar to the Twitter ‘verified account’ status tick. A ‘Moderator’ user type outputs a similar icon in a different style (‘M’ on a green background), and there is also the capability to set up a basic-looking ‘AUTHOR’ badge by adding some meta tags to the page.</p><figure><img alt="Examples of Viafoura’s standard badges" src="https://cdn-images-1.medium.com/max/615/1*T0-yVJCuqrWOmcj8PIEmJA.png" /><figcaption>Examples of Viafoura’s standard badges.</figcaption></figure><p>These are all good features, but at The Telegraph we wanted to label our authors with a bespoke ‘Telegraph author’ label, so we needed a more flexible labelling option.</p><p><strong>Custom Badges</strong></p><p>We found we could achieve this by using Viafoura’s custom badge functionality. It allows you to create badges containing some arbitrary text, and then assign those badges to specific users, so you can label up as many users you like, with anything you like! You can even assign multiple badges to a single user.</p><figure><img alt="Example of how The Telegraph is using custom badges for Authors." src="https://cdn-images-1.medium.com/max/476/0*-2wgUJT6HCY1mco3" /><figcaption>Example of how The Telegraph is using custom badges for Authors.</figcaption></figure><p>Setting up custom badges for your users is not as straightforward as you might think. The functionality is somewhat hidden away and you won’t find it when you look inside Viafoura’s admin console in the User tab, as you might intuitively expect.</p><p>In the admin console, the only information you’ll see about a user is their name, email address and a link to the comments they have posted. You might expect to also be able to configure things like badges in here, but sadly (at the time of writing) there is currently no interface for doing this. Instead, you have to make use of Viafoura’s API.</p><p><strong>Using Viafoura’s API</strong></p><p>To start making calls to Viafoura’s API, you’ll need to know your ‘section_uuid’. This is a unique ID for your domain, provided to you by your client success representative.</p><p>Each time you make calls, you’ll need to generate an access token by sending your ‘section_uuid’ to their /authorize_client endpoint. Once you’ve generated your access token, which is valid for 5 minutes at a time, you can then make calls to the api endpoints that you need to create and assign a badge.</p><p><strong>First step — Create the badge</strong></p><p>To create a badge you need to make a PUT request to the /profile/badge endpoint with a json payload containing the badge label and badge description. The label is the unique identifier and the description is what will actually be displayed on the front-end. For example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*iCLEyxdxbUWlhuglN3u3Ag.png" /></figure><p>This same call will also update the description in an existing badge if the label matches an existing one. So, if you’ve created a badge by mistake and want to remove it, then just send a DELETE request to the same /profile/badge endpoint with just the label of the badge you want to get rid of in the json payload, for example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*p13UAerAwThIaxagy4kBWw.png" /></figure><p>Note that, at the time of writing, there is no endpoint for obtaining a list of all the current badges you have already created in Viafoura’s system, so it’s useful to keep your own record of the badges you’ve created.</p><p><strong>Second Step: Assign the Badge</strong></p><p>Once you’ve created the badge, you can move on to the next step of assigning it to a specific user. To do this, you’ll need to make a PUT request to the Viafoura API /users/profile/badge endpoint, with a json payload containing user id of the person you want to assign the badge to, their login type, and label of the badge you want to assign to them, for example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*5Ut6LXhHNNu8vdLaapAG0Q.png" /></figure><p>If a 200 response is received back, then you have successfully assigned the badge to the user. If you get a 400 response, then the badge doesn’t exist in Viafoura and will need to be created (see above).</p><p><strong>Third Step — Automate!</strong></p><p>But what if you have a lot of users that need to be assigned badges? You won’t want to waste time making individual API calls for each person when a simple Python script can do the job.</p><p>A Python script to assign badges to a list of users needs to have the following steps:</p><ol><li>Obtain a list of users to process (which could be stored in a separate file).</li><li>Make a Viafoura API call to get an Access Token.</li><li>For each user in the list, make a Viafoura API call to assign the badge.</li></ol><p>Note in the following example, the use of the <a href="https://docs.python-requests.org/">Python requests library</a> which will need to be installed first.</p><p><em>Example Python Script:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/771/1*RLvz_sFCcGBrLZipFH2RGQ.png" /></figure><p>That’s it. The last request will return a 200 status code if successful (response.status_code == 200) and your desired badge name will be assigned to the user.</p><p><strong>Multiple Users’ Badges</strong></p><p>To assign multiple badges to a list of users, you can expand your script and have it read a list of user Ids from a file, loop over the Ids and make the API assignment request.</p><p>To get Python to open and read from a plain text file, you can use the <a href="https://docs.python.org/3/library/urllib.html">Python urllib library</a>. The text file should be set up with each user’s ID on a new line. For example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/771/1*T1dZ_vzS2xOq4AkAWwduUg.png" /></figure><p>After getting the basic Python script working, you can add extras like checking the response codes of your requests, printing out helpful messages and allowing raw inputs for badge names and environments. You could also expand the script to include badge creation and deletion.</p><p>For more information and documentation on the badges API, you can refer to <a href="https://documentation.viafoura.com/reference/assignbadgetouser">Viafoura’s detailed API documentation</a>.</p><p><em>Wendy Cocksedge is a Senior Software Engineer at Telegraph Media Group. </em><a href="https://twitter.com/telegraph_wendy"><em>Follow her on Twitter</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8ff3658d621d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-telegraph-engineering/viafoura-conversations-making-custom-user-badges-using-python-8ff3658d621d">Viafoura Conversations — Making Custom User Badges using Python</a> was originally published in <a href="https://medium.com/the-telegraph-engineering">The Telegraph Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>