Recent Posts
Archives

Archive for the ‘en-US’ Category

PostHeaderIcon [AWSReInventPartnerSessions2024] Simulate Amazon Q query for code generation

generated_code = f"def process_data(data):\n    return sorted(data)\n"
return generated_code

def test_code(code, test_cases):
exec(code)
for case in test_cases:
input_data, expected = case
result = process_data(input_data)
if result != expected:
return False
return True

PostHeaderIcon [NDCMelbourne2025] Front End Testing with GitHub Actions – Amy Kapernick

In a dynamic session at NDC Melbourne 2025, Amy Kapernick, a seasoned front-end developer and advocate for automation, unveils a streamlined approach to front-end testing using GitHub Actions. With a focus on practicality, Amy guides developers through constructing a robust continuous integration and continuous deployment (CI/CD) pipeline, ensuring that front-end tests run seamlessly against live websites. Her presentation underscores the necessity of automation to maintain quality in web development, offering actionable insights for teams seeking to integrate testing into their workflows without manual intervention.

The Imperative of Front-End Testing

Amy begins by highlighting the unique challenges of front-end testing, emphasizing that unlike unit tests, which can operate with dummy data, front-end tests require a live, functioning website to evaluate real-world performance. For instance, assessing accessibility for visually impaired users or determining page load speeds demands an environment that mirrors production. Amy illustrates this with a CSS code snippet, questioning whether it can reveal unintended style bleed or performance bottlenecks without a live interface. By advocating for environments as close to production as possible, she ensures that tests yield accurate, actionable results, setting the stage for automation to eliminate manual testing inconsistencies.

Automating with GitHub Actions

The core of Amy’s approach lies in leveraging GitHub Actions to automate front-end testing within a CI/CD pipeline. She explains that GitHub Actions’ workflows, defined in YAML files, enable developers to trigger tests on specific events, such as pull requests to a production branch. Amy walks through creating a workflow with jobs like “build” and “test,” detailing steps such as checking out repository code, setting up Node.js, and installing dependencies. By using existing GitHub Actions packages, like those for checking out code and configuring Node, she simplifies the process, ensuring tests run consistently without manual effort. This automation, Amy notes, prevents code merges that fail tests, safeguarding application quality.

Deploying and Testing Live Websites

A pivotal aspect of Amy’s workflow involves deploying a live website for testing, using Netlify for its ease and deploy preview capabilities. She demonstrates a custom bash script to deploy to Netlify, addressing challenges like handling sensitive data, such as site IDs, which GitHub Actions may flag as secrets. Amy ingeniously encodes the deployment URL to bypass security restrictions, decoding it for testing with tools like Lighthouse and Playwright. These tools provide comprehensive reports on performance and UI functionality, respectively, which Amy configures to upload as artifacts, ensuring developers can review results and address issues before merging code.

Enhancing Workflows with Additional Automation

Beyond testing, Amy showcases GitHub Actions’ versatility by integrating a package that converts code comments into GitHub issues, ensuring tasks like “fix later” are tracked. This automation assigns issues to the code’s author and auto-closes them when resolved, streamlining project management. Amy also touches on other uses, such as linting, checking broken links, and generating assets like static tweet images for blog posts. These examples highlight how GitHub Actions can extend beyond testing to enhance overall development efficiency, making it a powerful tool for modern workflows.

Links:

PostHeaderIcon [PyDataGlobal2025] The SAT Math Gap: Gender Difference or Selection Bias? A Bayesian Investigation

Lecturer

Allen Downey is the author of several widely used books on Bayesian statistics and computational methods, including Think Bayes. He collaborates with PyMC Labs, a consulting group that maintains the PyMC package for Bayesian modeling in Python, and has worked with the American Institute for Boys and Men on questions related to educational outcomes and selection effects. His work emphasizes practical, computational approaches to statistical inference that remain accessible to practitioners familiar with Python and common probability distributions.

Abstract

Male test-takers have scored approximately thirty points higher than female test-takers on the mathematics section of the SAT for roughly five decades on a scale ranging from 200 to 800. Some commentators interpret the persistent gap as evidence of a genuine difference in mathematical ability; others attribute it primarily to differential selection into the test-taking population. This article presents a complete Bayesian hierarchical model that recovers latent distributions of efficacy and estimates selection probabilities as a function of that efficacy. The model accounts for score truncation at the extremes, year-specific scoring artifacts arising from the discrete combinatorics of the examination, and group differences. Validation proceeds through parameter-recovery experiments on synthetic data and posterior predictive checks on the observed histograms. Results indicate that selection bias can plausibly explain the majority of the observed gap, offering a quantitative framework for disentangling latent traits from observed outcomes.

Selection Bias as a Fundamental Challenge and the Poincaré Illustration

Selection bias ranks among the most intractable difficulties in observational research. By the time data have been collected under an unknown or only partially known sampling process, correction is frequently impossible. In favorable cases, however, the shape of the observed distribution retains a detectable signature of the underlying selection mechanism. The classic, if almost certainly apocryphal, story of the mathematician Henri Poincaré and the baker supplies an intuitive illustration. Poincaré allegedly weighed a loaf of bread every day for a year and found a mean of 950 grams rather than the legally required 1 000 grams. After a warning from the authorities the following year’s mean rose to exactly 1 000 grams, yet the shape of the distribution was no longer Gaussian. Instead it resembled the distribution that would arise if the baker systematically selected the heaviest of several loaves whenever Poincaré appeared. A Bayesian model that treats the number of loaves examined as a latent parameter can recover both the true mean weight of the bakery’s output and the intensity of the selection process from a single year of daily observations.

The same principle is applied to SAT mathematics scores. Roughly half of college-bound seniors in the United States take the examination; those who anticipate low performance are less likely to sit for it. If the propensity to take the test rises with underlying mathematical efficacy—a composite of aptitude, educational history, and test-taking acumen—the observed score distributions for the two gender groups will be differentially truncated. An apparent mean difference can therefore emerge even if the latent distributions of efficacy are nearly identical. The question is whether the observed histograms contain sufficient information to recover both the latent distributions and the selection functions.

Data Characteristics and Generative Model Construction

College Board reports supply the full frequency distributions of scores for male and female test-takers for the years 2011 through 2015. Scores range from 200 to 800 and are scaled so that the population mean typically lies near 500 and the standard deviation near 100. In a sample of several hundred thousand observations one would expect an approximately Gaussian shape, yet the empirical histograms exhibit two distinctive features. First, excess mass appears at the extreme scores of 200 and 800 because all latent efficacy values lying outside the observable range are folded into those endpoint bins. Second, pronounced year-specific spikes arise from the discrete combinatorics of a fifty-four-question examination that awards +1 for a correct answer, 0 for an omitted answer, and –0.25 for an incorrect answer. Certain raw-score totals are impossible; others are more or less probable depending on the relative difficulty of the items in a given year. These spikes are highly consistent between male and female test-takers within a single year yet vary markedly from year to year, providing an additional source of identifying variation.

The generative model therefore comprises three principal components. A latent Gaussian distribution of efficacy is characterized by mean (\mu) and standard deviation (\sigma). A logistic selection function whose slope (\beta) governs the probability of taking the test as a function of efficacy captures the differential participation. A zero-mean, detrended Gaussian random walk absorbs the year-specific scoring spikes without contaminating estimates of location or selection intensity. Truncation is handled by extending the support of the latent distribution beyond the observed range and folding the tail probabilities into the endpoint bins. Careful constraints are required to avoid non-identifiability: the random walk is forced to have mean zero and is detrended so that it does not compete with either the intercept of the efficacy distribution or the slope of the selection function.

Hierarchical Estimation, Validation, and Substantive Interpretation

A hierarchical specification pools information across the five years while allowing group-specific selection slopes. Location and scale parameters are constrained to be nearly constant over time; the scoring artifacts are constrained to be identical across gender within each year; the selection slopes remain unconstrained. Under this specification the estimated selection gradient for male test-takers is substantially steeper than that for female test-takers. The implied probability of taking the test rises from roughly 25 percent at the low end of the efficacy distribution to 75 percent at the high end for males, while the corresponding range for females is far narrower. The posterior standard deviation of efficacy is also higher for males, consistent with a broader pattern of greater male variability observed in many cognitive and educational measures.

The posterior means of latent efficacy are 508 for males and 502 for females—a difference of only six points. Given that the observed score gap is approximately thirty points, selection bias can account for as much as four-fifths of the disparity. Parameter-recovery experiments on synthetic data generated from known values confirm that the model can retrieve (\mu), (\sigma), and (\beta) with acceptable accuracy. Posterior predictive checks on the real histograms show that the generative process reproduces both the overall shape and the fine-scale spikes of the observed data.

The result remains sensitive to the modeling assumption that deviations from normality are produced by selection rather than by intrinsic non-Gaussianity of the male efficacy distribution. Nevertheless, the analysis demonstrates that a substantial selection effect is statistically plausible and supplies a quantitative language for discussing the relative contributions of latent differences and participation patterns. The broader methodological lesson is that carefully specified generative models can sometimes extract selection parameters from the very distributions that selection has distorted. When sample sizes are large and the data-generating process can be articulated with reasonable fidelity, Bayesian inference offers a principled route from observed histograms to latent traits and selection intensities, moving the conversation beyond simple affirmation or denial of group differences.

Links:

PostHeaderIcon [VoxxedDaysTicino2026] Why Hexagonal and Onion Architectures Are Answers to the Wrong Question

Lecturer

Oliver Drotbohm is a senior principal software engineer at Broadcom, formerly part of the Spring engineering team at VMware for over 15 years. He has contributed significantly to Spring Data, focusing on repository abstractions, and more recently on architectural topics like Spring Modulith. Oliver is an advocate for modular software design and has spoken extensively on domain-driven design and system architecture. Relevant links include his GitHub profile (https://github.com/odrotbohm) and X account (https://x.com/odrotbohm).

Abstract

This article delves into Oliver Drotbohm’s critique of popular separation-of-concerns architectures like hexagonal and onion models, arguing they often prioritize decoupling over cohesion, leading to suboptimal code structures. Through theoretical analysis and practical examples, it explores software design principles rooted in coupling, cohesion, and anticipated changes. The discussion highlights trade-offs, the role of tools like Spring Modulith, and advocates for functional decomposition to achieve maintainable systems.

Fundamental Principles of Software Design and Cost

Software development’s primary cost lies in modifications rather than initial creation, as most efforts involve evolving existing systems. Oliver draws from Kent Beck’s interpretation of Edward Yourdon and Larry Constantine’s work, positing that change costs are tied to coupling between code elements—classes, packages, or modules. Coupling manifests when alterations in one area necessitate changes elsewhere, with its nature depending on the change type (e.g., database migration versus UI enhancement).

To minimize costs, decoupling is essential, but it introduces its own overhead, such as additional interfaces and implementations. Oliver emphasizes cohesion as the counterbalance: intentional coupling in appropriate places to collocate elements for common changes. Effective design creates cohesive units loosely coupled to others, essentially betting on future change patterns.

Systems emerge not just from parts but their interactions, per Russell Ackoff’s philosophy. Thus, design involves defining cohesive elements, promoting entry points, and establishing connections. This foundational view critiques architectures that overlook these dynamics.

Critique of Separation-of-Concerns Architectures

Hexagonal architecture, coined by Alistair Cockburn in 2005, centers domain logic, shielding it from infrastructure via ports and adapters. Ports are neutral entry points, with adapters depending on them, inverting dependencies to isolate the core. Onion architecture, by Jeffrey Palermo in 2008, similarly layers domain, application, and infrastructure, omitting explicit ports but maintaining inward dependencies.

Oliver compares these to layered architectures from domain-driven design (DDD), where presentation, business, and persistence layers interact, with business potentially depending on infrastructure. The key difference is dependency inversion, but terminology shifts obscure similarities. Spring applications historically embodied this: controllers (presentation/adapters), services (business/ports), repositories (persistence).

Yet, these models often yield complexity, with excessive folders for adapters, contradicting their goal of clarifying business logic. Oliver argues they answer the wrong question—focusing on technical separation rather than business cohesion.

Alternative Approaches: Prioritizing Cohesion and Encapsulation

Instead of technical layers as primary packages or modules, Oliver advocates functional decomposition, grouping by business slices (e.g., order, customer). This avoids scattering related elements across layers, akin to organizing furniture by type rather than function.

In code, vertical slices encapsulate internals: controllers, services, repositories within one package, hidden by default visibility. Public interfaces expose only necessary surfaces, enhancing encapsulation over mere organization. For simple read-only scenarios, direct JDBC in controllers suffices, hidden from outsiders. Complex slices warrant internal abstractions.

This yields cohesive bases automatically decoupled, as inter-slice connections are minimal. Intrinsic complexity dictates accidental complexity—pragmatic layering per slice. Tools like Spring Modulith enforce this, using annotations for stereotypes (e.g., @AggregateRoot), integrating with IDEs to display architectural concepts beyond packages.

Trade-Offs, Tools, and Implications

Trade-offs include initial simplicity versus future adaptability: technical packages force public interfaces, risking violations, while functional ones hide more, supporting evolution. Oliver notes developers’ inclination toward technical structures stems from IDEs’ technology-centric views (e.g., source/main/java), lacking higher abstractions.

Spring Modulith and ArchUnit address this, verifying rules and visualizing modules. IDE integrations (VS Code, Eclipse) convey code via design stereotypes, reducing package reliance.

Implications favor cohesion-first design: functional decomposition aligns with change patterns, reducing scattering. It supports DDD aggregates and repositories naturally, without mandating architectures. As systems grow, this prevents tangled messes from entangled business logic, not just direct database calls.

In conclusion, reframing the question from decoupling infrastructure to fostering cohesive, change-resilient structures yields maintainable software, leveraging tools for integrity.

Links:

PostHeaderIcon [AWSReInforce2025] Redefining cybersecurity for modern threats with Armis Centrix (NIS122)

Lecturer

Steve Clark serves as Director of Cloud Alliances at Armis, orchestrating partnerships that extend cyber exposure management across cloud and edge environments. His expertise centers on asset intelligence platforms that provide real-time visibility into managed, unmanaged, and IoT devices.

Abstract

The presentation positions Armis Centrix as a cloud-native platform for comprehensive asset protection, demonstrating integration with AWS services to identify, prioritize, and remediate risks across the attack surface. Through customer examples in transportation, healthcare, and aviation, it establishes proactive exposure management as essential for modern threat defense.

Asset Discovery Beyond Traditional Boundaries

Modern environments contain thousands of unmanaged devices—IoT sensors, medical equipment, building controllers—that evade conventional inventory tools. Armis Centrix discovers assets through passive traffic analysis and active querying:

Network Traffic → Behavioral Fingerprint → Device Classification
                                  ↓
                            Risk Scoring Engine

The platform identifies device type, manufacturer, firmware version, and operational context without requiring agents.

Risk Prioritization and Business Context

Raw asset data becomes actionable intelligence through contextual scoring:

{
  "device": "GE MRI Scanner",
  "vulnerabilities": ["CVE-2023-4567"],
  "connectivity": "Internet-facing",
  "business_unit": "Radiology",
  "priority_score": 9.8
}

Integration with ServiceNow CMDB enriches discovery with ownership and criticality metadata, enabling precise remediation workflows.

Integration Patterns with AWS Services

Armis ingests VPC Flow Logs and GuardDuty findings to extend visibility:

connectors:
  - aws_vpc_flow_logs
  - aws_guardduty
  - servicenow_cmdb
  - palo_alto_firewall

EventBridge rules trigger automated responses—quarantining compromised IoT devices, creating Jira tickets, or notifying device owners.

Real-World Deployment Outcomes

Case studies demonstrate operational impact:

  • Transportation Provider: Discovered 40% more assets than ServiceNow inventory; achieved regulatory compliance ahead of DoT mandates
  • Healthcare System: Reduced mean time to patch critical medical devices from 90 to 14 days
  • Airport Authority: Identified rogue Wi-Fi access points and unauthorized Bluetooth beacons

These organizations leverage Armis within AWS environments, processing petabytes of traffic data with sub-second query response.

Proactive Exposure Management Framework

The platform implements continuous assessment:

  1. Discovery: Passive and active techniques
  2. Classification: ML-based device fingerprinting
  3. Risk Scoring: CVSS + business context
  4. Remediation: Automated playbooks and orchestration
  5. Verification: Continuous validation of control efficacy

This cycle operates 24/7, adapting to asset churn and emerging threats.

Conclusion: Comprehensive Asset Protection

Armis Centrix transforms asset visibility from periodic audits into real-time intelligence. By combining passive discovery, behavioral analysis, and AWS integration, organizations gain comprehensive protection across IT, OT, and IoT environments. The platform enables security teams to move from reactive incident response to proactive risk elimination.

Links:

PostHeaderIcon [reClojure2025] UI, Pure and Simple

Lecturer

Christian Johansen is a highly experienced software developer at the Norwegian Food Safety Authority, where he specializes in architecting robust systems using Clojure and Datomic. With a professional career spanning two decades, Christian has dedicated the last ten years to full-time Clojure development. His expertise is deeply rooted in web technologies, encompassing the entire delivery pipeline from infrastructure configuration and data modeling to sophisticated frontend implementation. Beyond his primary role, he is a prolific contributor to the Clojure ecosystem, maintaining various open-source libraries and frequently sharing insights through conference presentations, educational courses, and a collaborative professional blog.

Abstract

Modern frontend development is often plagued by the complexities of shared mutable state and pervasive side effects, which complicate testing and maintenance. This article examines the philosophical and technical foundations of achieving a truly functional user interface. By revisiting the original promise of React—that UI is a function of state—and refining it through the lens of Clojure’s immutability, we introduce a paradigm known as top-down rendering. Central to this discussion is Replicant, a small, dependency-free Clojure rendering library designed to treat UI as pure, deterministic data. We analyze the methodology of building modular UIs that decouple rendering from state management, utilize data-driven event handlers, and leverage declarative animations to create simpler, more testable applications.

Historical Context and the Pursuit of Purity

The evolution of modern web development reached a significant milestone in 2013 with the introduction of React. The framework proposed a revolutionary conceptual model: the user interface should be viewed as a pure function of application state. In this ideal scenario, developers would write code as if the entire UI were rendered from scratch with every update, leaving the heavy lifting of DOM manipulation to the framework. However, while React transformed the industry’s mental model, it did not fully deliver on the promise of functional purity. In practice, React applications often allow mutable state to proliferate throughout the component tree, leading to the very “side-effect-ridden” complexity it sought to solve.
The ClojureScript community recognized this gap early on. Developers sought a more rigorous adherence to functional principles. One notable advancement was the library Quiescent, which introduced the constraint of “top-down rendering.” In this model, components are prohibited from maintaining their own internal state or triggering their own re-renders. Instead, the entire UI is a literal projection of a central, immutable data structure. This approach aligns perfectly with Clojure’s core strengths, providing a foundation for UIs that are stateless, deterministic, and built entirely on data.

Methodology: Rendering with Replicant

Replicant serves as a realization of this top-down philosophy. It is a minimalist virtual DOM library that operates on Hiccup, a domain-specific language in Clojure that represents HTML structures as standard data vectors and maps. The core methodology involves creating pure functions that transform domain data into Hiccup data. Because these functions are pure, they are inherently predictable and easy to test in isolation.
To illustrate this, consider the rendering of a task card in a Kanban application. The developer defines a function that takes a task map and returns a Hiccup representation. Replicant’s render function then takes this data and a target DOM element to perform the initial mount. When the application state changes, the process is repeated: the pure function generates new Hiccup data, and Replicant calculates the minimal set of DOM mutations required to transition the view. This “diffing” process ensures efficiency without requiring the developer to manage state transitions manually.

Code Sample: Pure Hiccup Transformation

(defn render-task [task tags-lookup]
  [:div.task-card
   [:h3 (:task/title task)]
   [:div.tags
    (map (fn [tag-id]
           (let [tag (get tags-lookup tag-id)]
             [:span {:class (str "tag-" (:tag/color tag))}
              (:tag/label tag)]))
         (:task/tags task))]])

Advanced UI Patterns: Events and Animations

Beyond static rendering, the “pure and simple” approach extends to interactivity. In traditional frameworks, event handlers are often opaque functions that execute side effects directly. Replicant encourages data-driven event handlers. Instead of passing a callback function to an onClick attribute, the developer can pass a data structure—a vector or a map—representing the intent of the event. A central coordinator then interprets this data to update the global state. This decoupling makes the UI’s behavior as inspectable and testable as its appearance.
The same principle applies to complex UI requirements like animations and timed effects. By treating time and transitions as part of the data flow, developers can create declarative animations. These are not imperative commands to “fade in an element” but rather state-based descriptions of how an element should appear at a given point in the application lifecycle. This approach dramatically simplifies the creation of interactive features like drag-and-drop or live data streaming, as the UI remains a consistent reflection of the underlying store regardless of where the data originates.

Consequential Benefits and Conclusion

Adopting a stateless, data-centric approach to UI development yields significant benefits for software quality. Because the UI is composed of pure functions, it is highly modular and testable. Tools like Portfolio (similar to Storybook for ClojureScript) allow developers to render “scenes” in isolation by passing mock domain data to their rendering functions. This facilitates rapid prototyping and visual regression testing without the need to navigate through a live, stateful application.
Ultimately, the shift toward pure and simple UIs represents a move away from the “nashing of teeth” associated with shared mutable state. By leveraging Clojure’s immutable data structures and Replicant’s minimalist rendering engine, developers can build systems that are not only more robust and maintainable but also more enjoyable to create. The decoupling of rendering from state management allows for a degree of architectural clarity that is often missing in contemporary frontend development.

Links:

PostHeaderIcon [PyConUS2025] Why `len(‘😶‍🌫️’) == 4` and Other Unexpected Behaviors of Python Strings

Lecturer

Marie Roald is a researcher, data scientist, and educator affiliated with the Norwegian Language Bank at the National Library of Norway. She has more than eight years of experience teaching Python to secondary-school students, teachers, and professionals, and is a co-founder and organizer of PyLadies Oslo. Yngve Mardal Moe is an experienced Python educator, developer, and data-science consultant who previously led the redesign of an introductory Python course at the Norwegian University of Life Sciences; he currently serves as tech lead on automation projects for the Norwegian power grid. Together they bring complementary perspectives from language technology and software engineering to the practical difficulties of Unicode handling.

Abstract

Python strings appear simple until everyday operations—length measurement, equality testing, case conversion, and slicing—produce counter-intuitive results. This presentation traces those surprises to the underlying Unicode encoding model, the distinction between code points and grapheme clusters, the existence of multiple normalized forms, and the incomplete implementation of locale-sensitive operations in the language. The speakers supply concrete recommendations for robust comparison, normalization, and length measurement that avoid the most common pitfalls.

Encoding, Code Points, and the Limits of Naïve Operations

A computer stores only bits; any text representation is therefore a mapping from abstract characters onto sequences of numbers called code points. Early seven-bit ASCII proved insufficient for the world’s writing systems, prompting a proliferation of national encodings and, eventually, the Unicode standard. Unicode presently defines more than a million code points and is transmitted most commonly as the variable-length UTF-8 encoding. Python itself stores strings in one of three internal widths—1, 2, or 4 bytes per code point—chosen according to the highest code point present in the string.

Because a single visible character (a grapheme) may be composed of several code points, the built-in len function counts code points rather than user-perceived characters. The rainbow-flag emoji, for example, comprises a white flag, a variation selector, a zero-width joiner, and a rainbow emoji—four code points that render as one glyph. The same phenomenon appears in ordinary text: the Norwegian letter “å” may be stored either as the precomposed code point U+00E5 or as the sequence “a” plus a combining ring (U+030A). Equality tests and slicing that operate on the raw sequence therefore diverge from human expectations.

Case conversion is similarly subtle. The German sharp S (“ß”) upper-cases to “SS”, so a naïve round-trip through str.upper and str.lower fails to restore the original spelling. The Unicode-recommended solution is case folding (str.casefold), which maps characters to a canonical caseless form and correctly handles the 297 known special cases. Even case folding, however, is incomplete for languages such as Turkish, whose dotted and dotless “I” require locale-aware rules that Python does not implement.

Normalization, Security, and Practical Recommendations

Unicode defines four normalization forms. NFC and NFD perform canonical composition and decomposition; NFKC and NFKD additionally map compatibility characters (superscripts, stylistic variants, fractions) onto their plain counterparts. Normalization is essential before comparison or hashing: two strings that look identical to a user may otherwise compare unequal. Python’s identifier parser already applies NFKC, which is why “fancy” mathematical letters are silently rewritten to ordinary ASCII identifiers—an amusing demonstration of the same machinery.

Homoglyphs (characters that look alike but occupy distinct code points) introduce security considerations. The Unicode Consortium publishes confusable lists that applications may consult when validating user names or domain names. Because there is no fixed upper bound on the number of code points that may form a single grapheme cluster, length limits expressed solely in graphemes remain vulnerable to pathological input; a practical defense is to impose both a grapheme limit and a modest code-point ceiling.

For everyday work the speakers recommend a short checklist: always exchange text as UTF-8; compare caselessly with casefold; normalize to a chosen form (usually NFC) before equality tests or storage; treat len and slicing as code-point operations and, when visual length matters, employ a library such as regex or PyICU that understands extended grapheme clusters; and remain aware that Unicode is still evolving and that Python’s support, while extensive, is not exhaustive. Written language is inherently complex; the apparent oddities of Python strings are simply the language’s honest reflection of that complexity.

Links:

PostHeaderIcon [GopherConUK2025] How Just Eat Uses Tooling to Deploy Go Micro-services in Minutes

Lecturer

Ainsley Clark is a Senior Software Engineer at Just Eat, working within the Jet Connect team. He has been with the organisation for just over two years and maintains a strong professional focus on Go. His work centres on the design and operation of the internal microservice development toolkit that underpins large-scale order and menu processing across hundreds of partner integrations.

Abstract

This article describes the evolution and capabilities of GoKit, the internal microservice development toolkit developed by Just Eat’s Jet Connect team. Confronted with the maintenance burden of hundreds of independently forked services, the team replaced a template-based approach with a centralised code-generation and infrastructure-as-code system. The resulting tool scaffolds services, generates event consumers and producers, provisions cloud resources, produces continuous-integration workflows and emits operational metrics with minimal engineer effort. A concrete pizza-order example illustrates how a fully instrumented, event-driven service can be created and extended in minutes rather than days, allowing engineers to concentrate on business logic rather than infrastructure boilerplate.

From Monolith and Templates to a Centralised Toolkit

Jet Connect began life as Flight, an integration platform founded in 2013. Its purpose is to unify order and menu processing across restaurants, groceries and electronics partners so that a single point-of-sale interaction replaces multiple device-specific payloads. Today the platform serves approximately 731 000 partners across seventeen countries and processes hundreds of millions of orders annually. The Jet Connect engineering group itself comprises roughly fifty people and owns more than one hundred Go microservices.

The journey to that estate began with a PHP monolith that became increasingly difficult to change. Integrations were subsequently extracted into TypeScript services that spoke gRPC to the monolith. A GitHub template repository accelerated the creation of new integrations: an engineer could fork the template and obtain environment files, Helm charts and build workflows in minutes. The approach delivered speed in the early days yet exacted a heavy maintenance cost. A bug fix or standardisation change had to be applied manually to every fork. Inconsistent folder structures and coding patterns made context-switching expensive. End-to-end testing was absent, reducing confidence in releases.

The decision was therefore taken to move the entire integration layer to Go and to replace the template model with a purpose-built toolkit. The requirements were exacting: generate or update a repository in seconds; treat OpenAPI documentation as a first-class artefact; allow an engineer to subscribe to events by writing only a handler; hide infrastructure details such as databases, event buses and object storage; auto-generate continuous-integration and continuous-delivery pipelines; guarantee safe production deployment on merge to main; support capability testing across the full service graph; and provide a consistent local development experience with minimal setup. The resulting system is known internally as GoKit.

Scaffolding, Event Handling and Infrastructure as Code

GoKit meets those requirements through a combination of code generation and a declarative service description. The command gokit new <service-name> presents a short interactive questionnaire: does the service consume events, produce events, expose an HTTP server, require a database or object store? On the basis of the answers it scaffolds a consistent folder structure whose most important directories are cmd/app (containing a generated main) and internal (the sole location for custom business logic). A file named service.json acts as the single source of truth for infrastructure; it is consumed by Terraform templates that provision the necessary cloud resources.

A typical event handler receives an HTTP client, an event-bus producer and the incoming event (typed via reflection performed by GoKit). After performing domain work—calling a partner API, writing analytics, storing a payload—the handler emits a successor event. Registration consists of a single method call that associates the handler with a concrete event type. A subsequent gokit update rewrites service.json, updates generated code and refreshes documentation. The resulting README lists every consumed and produced topic, giving any engineer an immediate, accurate overview of the service’s responsibilities without requiring manual documentation effort.

Because the same service.json also drives resource provisioning, adding a DynamoDB table or an S3 bucket is a matter of inserting a few lines of JSON and re-running the update command. Generated interfaces for read/write operations and object-store upload/download encourage dependency injection and make unit testing straightforward. Should the underlying technology later change (for example from DynamoDB to PostgreSQL), only the implementation behind the interface needs to be altered; every consuming service continues to compile and run unchanged. The same mechanism supports vertical and horizontal scaling declarations—minimum replica counts, CPU and memory class—again expressed as simple keys in service.json.

Continuous Integration, Capability Testing and Observability

All continuous-integration workflows are themselves generated by GoKit. A change to a workflow template is made once in the central repository; every service inherits the update the next time gokit update is run. Capability tests spin up the entire relevant service graph under Docker, inject a correlation identifier into every request and event, and assert final outcomes. The approach scales to capability chains that involve ten or twenty intermediate services and provides high confidence before production deployment. Drift detection prevents accidental divergence: if an engineer edits a generated file without running the update command, continuous integration fails the pull request. Version pinning of GoKit itself ensures that services cannot merge while they lag behind a required toolkit version, producing a natural, incremental migration path across the estate.

Operational metrics appear automatically. Grafana dashboards display event rates, HTTP status codes, latency distributions, DynamoDB read/write performance and S3 operation counts without any additional instrumentation code. The same consistency that simplifies development also simplifies observation. When a product request arrives for analytics storage or an order-ready notification endpoint, the engineer adds a handful of lines to service.json or an OpenAPI specification, runs the update command, implements a short handler, and obtains a fully instrumented, tested and documented service ready for review.

Outcomes and Lessons

In the six years of its existence GoKit has allowed the Jet Connect team to update the entire service estate with a single pull request, to maintain uniform folder structures that eliminate costly context switches, and to keep documentation accurate without manual effort. Engineers spend their time on business problems—partner-specific payloads, analytics requirements, notification flows—rather than on Terraform, Helm or continuous-integration boilerplate. The toolkit has been instrumental in scaling the platform to hundreds of millions of orders while keeping the cognitive load on individual developers manageable.

The most transferable lessons are structural rather than technological. A single source of truth for service shape, aggressive code generation of repetitive artefacts, enforcement of consistency through continuous integration, and the deliberate abstraction of infrastructure behind stable interfaces together convert the chronic maintenance burden of a large microservice estate into a manageable, largely automated background process. The result is that complex event-driven workflows can be designed, implemented, tested and deployed in minutes rather than days, freeing engineering capacity for the differentiated work that actually delivers value to partners and customers.
The pizza-service walkthrough, though simplified for presentation, captures the essential rhythm of day-to-day work. An engineer begins with a short questionnaire, receives a fully structured repository, writes a handful of domain-specific lines, runs an update command, and obtains a service that already possesses continuous-integration pipelines, infrastructure declarations, metrics dashboards and capability-test scaffolding. Subsequent product requests—analytics storage, partner callbacks, new event types—are accommodated by small, localised edits rather than by the recreation of entire deployment artefacts. The cognitive load remains focused on the business problem; the mechanical work of packaging, provisioning and observing has been systematically removed from the critical path.

The same pattern scales. Whether the service handles a single partner’s CSV feed or participates in a multi-stage order-reconciliation flow involving a dozen intermediate services, the surrounding machinery remains identical. Consistency of structure, generation of repetitive artefacts and enforcement of hygiene through continuous integration together produce an estate that can grow without a proportional increase in operational friction. That is the practical payoff of the investment in a centralised toolkit.
Looking ahead, the same principles that make GoKit effective inside Just Eat are portable to any organisation that maintains a large collection of similarly structured services. The precise implementation will differ—different cloud providers, different event buses, different continuous-integration systems—but the underlying ideas remain constant: centralise the definition of service shape, generate everything that can be generated, enforce consistency automatically, and keep the engineer’s attention on the business problem. When those ideas are applied with discipline, the cost of creating and operating microservices falls dramatically, and the organisation’s capacity to respond to new partner or product requirements rises correspondingly.
In the end the value of a toolkit such as GoKit is measured less by the number of lines it generates than by the number of decisions it removes from the critical path of feature delivery. Every database, every topic subscription, every continuous-integration step that an engineer no longer has to configure by hand is a unit of attention that can be redirected toward the unique requirements of a partner or a product. When that redirection is systematic and reliable, the organisation as a whole becomes more responsive, more consistent and more capable of sustaining growth without a proportional increase in operational complexity.
The pizza-service narrative also illustrates a secondary benefit that is easy to overlook: the progressive enrichment of operational visibility. Because metrics, dashboards and capability tests are generated rather than hand-crafted, every new service automatically participates in the organisation’s observability and quality regimes. There is no opportunity for a service to be “forgotten” or to ship without the standard instrumentation. Consistency of tooling produces consistency of operational posture, which in turn reduces the cognitive load on both developers and on-call engineers.
Taken together, the practices embodied in GoKit demonstrate that the apparent tension between rapid delivery and long-term maintainability can be resolved by investing in the right abstractions at the platform level. When the platform absorbs the repetitive work of scaffolding, provisioning, testing and observing, individual service teams are free to move quickly without accumulating the structural debt that eventually slows every organisation that scales through pure copy-and-paste. The result is an engineering culture that can sustain high throughput while preserving the coherence and reliability required for a production system that processes hundreds of millions of orders.
The same principles that enabled Jet Connect to move from a maintenance-heavy template model to a coherent, generated estate are available to any organisation facing a similar proliferation of services. The precise technology choices—Terraform versus another infrastructure-as-code system, Kafka versus another event bus, OpenAPI versus another interface description—matter less than the architectural decision to centralise the definition of service shape and to generate the repetitive surrounding machinery. Once that decision is made and enforced, the cost of each additional service falls and the organisation’s ability to respond to new requirements rises. In an environment that processes hundreds of millions of orders, that difference is decisive.
In practical terms the toolkit converts what would otherwise be a multi-day or multi-week effort—creating a repository, wiring continuous integration, declaring infrastructure, adding metrics, writing documentation—into a sequence of minutes. The engineer’s attention remains on the unique aspects of the partner integration or the product feature. Everything else is supplied by generation and enforced by pipeline. That separation of concerns is the essential achievement, and it is the reason the platform can continue to scale without a corresponding explosion in operational overhead.
The experience of Jet Connect demonstrates that the investment in a carefully designed internal platform pays continuing dividends. Each new service inherits the accumulated learning of the entire estate; each improvement to the toolkit propagates automatically; each engineer inherits a consistent, well-instrumented starting point. The result is not merely faster delivery of individual features but a durable increase in the organisation’s capacity to absorb complexity without sacrificing reliability or developer effectiveness.
In short, GoKit is less a code generator than a deliberate architectural intervention that realigns incentives and removes friction from the path of delivery.

Links:

PostHeaderIcon CPU vs GPU: Why GPUs Dominate AI Workloads: A Practical, Code-Driven Explanation for Developers

Modern artificial intelligence workloads—particularly those associated with deep learning—have reshaped the way computation is structured and executed. While CPUs remain indispensable for general-purpose tasks, GPUs have become the de facto standard for training and running machine learning models.

This shift is not incidental. It is driven by a deep alignment between the mathematical structure of AI and the architectural characteristics of GPUs. In this article, we examine this alignment and illustrate it with representative code commonly found in real-world AI systems.

The Computational Nature of AI

At its core, modern machine learning is an exercise in large-scale numerical optimization. Whether training a convolutional network or a transformer, the dominant operations are:

  • Matrix multiplications
  • Tensor contractions
  • Element-wise transformations
  • Non-linear activations

These operations are instances of linear algebra applied at scale. Crucially, they exhibit a high degree of data parallelism: the same operation is applied repeatedly across large datasets.

From Mathematical Abstraction to Code

To understand why GPUs excel, it is instructive to look at how AI code is written in practice.

Example 1: A Simple Neural Network Layer (PyTorch)

import torch
import torch.nn as nn

# Define a simple linear layer
layer = nn.Linear(in_features=1024, out_features=512)

# Simulated batch of input data
x = torch.randn(64, 1024)  # batch size = 64

# Forward pass
y = layer(x)

The operation above is fundamentally a matrix multiplication followed by a bias addition. Each output element is computed independently, making the workload inherently parallel.

Example 2: Training Step in a Neural Network

import torch
import torch.nn as nn
import torch.optim as optim

model = nn.Sequential(
    nn.Linear(1024, 512),
    nn.ReLU(),
    nn.Linear(512, 10)
)

optimizer = optim.Adam(model.parameters())
criterion = nn.CrossEntropyLoss()

# Dummy input and labels
inputs = torch.randn(64, 1024)
targets = torch.randint(0, 10, (64,))

# Forward pass
outputs = model(inputs)

# Compute loss
loss = criterion(outputs, targets)

# Backward pass
loss.backward()

# Update weights
optimizer.step()
optimizer.zero_grad()

Both the forward and backward passes are dominated by tensor operations applied across entire batches, reinforcing the highly parallel nature of AI workloads.

Example 3: Convolutional Operation (Core of CNNs)

import torch
import torch.nn as nn

conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)

# Batch of images: (batch_size, channels, height, width)
images = torch.randn(32, 3, 224, 224)

# Apply convolution
features = conv(images)

Convolutions apply the same kernel across spatial dimensions, resulting in a massive number of independent computations—ideal for parallel execution.

Example 4: Attention Mechanism (Transformer Core)

import torch
import torch.nn.functional as F

def attention(Q, K, V):
    scores = Q @ K.transpose(-2, -1)
    scores = scores / (Q.size(-1) ** 0.5)
    weights = F.softmax(scores, dim=-1)
    return weights @ V

# Simulated query, key, value tensors
Q = torch.randn(32, 8, 128, 64)  # batch, heads, seq_len, dim
K = torch.randn(32, 8, 128, 64)
V = torch.randn(32, 8, 128, 64)

output = attention(Q, K, V)

This pattern—matrix multiplication followed by normalization and weighted aggregation—is central to modern transformer architectures and exemplifies the computational intensity of AI workloads.

Architectural Alignment

A clear pattern emerges from these examples:

  • Uniform operations applied across large tensors
  • Minimal branching or complex control flow
  • Heavy reliance on linear algebra primitives

These characteristics align closely with GPU design, which emphasizes throughput and parallel execution.

Memory Throughput and Data Movement

AI workloads are not only compute-intensive but also data-intensive. Large tensors must be moved efficiently between memory and compute units. GPUs provide significantly higher memory bandwidth than CPUs, enabling sustained performance for such operations.

The Role of Frameworks

Modern frameworks abstract away hardware complexity while exposing high-level primitives such as tensor operations and automatic differentiation. This allows developers to write expressive code while leveraging specialized hardware.

Conclusion

The preference for GPUs in AI is a consequence of structural compatibility between workload and architecture. AI code is inherently parallel, tensor-centric, and dominated by linear algebra operations.

GPUs are designed precisely to execute such workloads efficiently at scale. For software developers, understanding this alignment is essential to building performant and scalable machine learning systems.

Further Exploration

  • Computational graphs and automatic differentiation
  • Transformer architectures
  • Mixed-precision training
  • GPU execution models

PostHeaderIcon [AWSReInvent2025] Amazon S3 Performance: Architecture, Design, and Optimization for Data-Intensive Systems

Lecturer

Ian Heritage is a Senior Solutions Architect at Amazon Web Services, specializing in Amazon S3 and large-scale data storage architectures. With deep expertise in performance engineering and distributed systems, Ian Heritage helps organizations design and optimize their storage layers for high-throughput and low-latency applications, including machine learning training and real-time analytics. He is a prominent figure in the AWS storage community, known for his technical deep-dives into S3’s internal mechanics and best practices for performance at scale.

Abstract

This article explores the internal architecture and performance optimization strategies of Amazon S3, the industry-leading object storage service. It provides a detailed analysis of the differences between S3 General Purpose and the newly introduced S3 Express One Zone storage class, highlighting the architectural trade-offs between regional durability and sub-millisecond latency. The discussion covers advanced request management techniques, including prefix partitioning, request routing, and the role of the AWS Common Runtime (CRT) in maximizing throughput. By examining these technical foundations, the article offers practical guidance for architecting storage solutions that can handle millions of requests per second and petabytes of data for modern AI and analytics workloads.

S3 Storage Class Selection for High Performance

The performance of an S3-based application is fundamentally determined by the selection of the storage class. For over a decade, S3 General Purpose (Standard) has been the default choice, offering 99.999999999% (11 9s) of durability by replicating data across at least three Availability Zones. While this provides extreme reliability, the regional replication introduces a baseline latency that may be too high for certain “request-intensive” applications, such as machine learning model checkpoints or high-frequency trading logs.

To address these needs, AWS introduced S3 Express One Zone. This storage class is designed for workloads that require consistent, single-digit millisecond latency. By storing data within a single Availability Zone and utilizing a new, purpose-built architecture, Express One Zone can deliver up to 10x the performance of S3 Standard at a 50% lower request cost. This class is ideal for applications that perform frequent, small I/O operations where the overhead of regional replication would be the primary bottleneck. The choice between Standard and Express One Zone is thus a strategic decision between geographic durability and extreme performance.

Request Routing, Partitioning, and the Scale-Out Architecture

At its core, Amazon S3 is a massively distributed system that scales out to handle virtually unlimited throughput. The key to this scaling is “partitioning.” S3 automatically partitions buckets based on the object keys (names). Each partition can support a specific number of requests: 3,500 PUT/COPY/POST/DELETE requests and 5,500 GET/HEAD requests per second per prefix. For many years, users were advised to use randomized prefixes to ensure even distribution across partitions.

Modern S3 architecture has evolved to handle this automatically, but understanding prefix design remains crucial for performance. When an application’s request rate increases, S3 detects the hot spot and splits the partition to handle the load. However, this process takes time. For workloads that burst from zero to millions of requests instantly, pre-partitioning or using a wide range of prefixes is still a best practice. By spreading data across multiple prefixes (e.g., bucket/prefix1/, bucket/prefix2/), an application can linearly scale its throughput to accommodate massive concurrency, limited only by the client’s network bandwidth and CPU.

Client-Side Optimization with AWS CRT and SDKs

While the S3 service is designed for scale, the performance experienced by the end-user is often limited by the client-side implementation. To bridge this gap, AWS developed the Common Runtime (CRT) library. The CRT is a set of open-source, C-based libraries that implement high-performance networking best practices, such as automatic request retries, congestion control, and most importantly, multipart transfers.

'''
Conceptual example of enabling CRT in the AWS SDK for Python (Boto3)
'''
import boto3
from s3transfer.manager import TransferConfig

'''
The CRT allows for automatic parallelization of large object transfers
'''
config = TransferConfig(use_threads=True, max_concurrency=10)
s3 = boto3.client('s3')

s3.upload_file('large_data.zip', 'my-bucket', 'data.zip', Config=config)

The CRT automatically breaks large objects into smaller parts and uploads or downloads them in parallel. This utilizes the full network capacity of the EC2 instance and mitigates the impact of single-path network congestion. For applications using the AWS CLI or SDKs for Java, Python, and C++, opting into the CRT-based clients can result in a significant throughput increase—often double or triple the speed of standard clients for large files. Additionally, the CRT handles the complexities of DNS load balancing and connection pooling, ensuring that requests are distributed efficiently across the S3 frontend fleet.

Case Study: Optimization for Machine Learning and Analytics

Machine learning training is a premier use case for S3 performance optimization. During the training of large language models (LLMs), hundreds or thousands of GPUs must simultaneously read training data and write model “checkpoints.” These checkpoints are multi-gigabyte files that must be saved quickly to avoid idling expensive compute resources. By combining S3 Express One Zone with the CRT-based client, researchers can achieve the throughput necessary to saturate the high-speed networking of P4 and P5 instances.

In analytics, the use of “Range Gets” is a critical optimization. Instead of downloading an entire 1GB Parquet file to read a few columns, an application can request specific byte ranges. This reduces the amount of data transferred and speeds up query execution. S3 is optimized to handle these range requests efficiently, and when combined with a partitioned data layout (e.g., partitioning by date or region), it enables sub-second query responses over petabytes of data. This architectural synergy between storage class, partitioning, and client-side logic is what allows S3 to serve as the foundation for the world’s largest data lakes.

Links: