<?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[Valcon - Medium]]></title>
        <description><![CDATA[Valcon is a European powerhouse in AI and data-driven business transformation. We bring this to life by integrating consulting, technology and data capabilities. - Medium]]></description>
        <link>https://medium.com/valcon-consulting?source=rss----9ba0a8d8e953---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Valcon - Medium</title>
            <link>https://medium.com/valcon-consulting?source=rss----9ba0a8d8e953---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 07:26:36 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/valcon-consulting" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[The cloud migration paradox: faster migration, slower transformation]]></title>
            <link>https://medium.com/valcon-consulting/the-cloud-migration-paradox-faster-migration-slower-transformation-b20885301f25?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/b20885301f25</guid>
            <category><![CDATA[digital-transformation]]></category>
            <category><![CDATA[modernisation]]></category>
            <category><![CDATA[cloud-migration]]></category>
            <category><![CDATA[technical-debt]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Johnson Elejofi]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 12:14:03 GMT</pubDate>
            <atom:updated>2026-11-04T12:14:01.839Z</atom:updated>
            <content:encoded><![CDATA[<p>In the past, cloud migration was a technology initiative. Today, it is often a race against time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*14QBIXFD4zdt5a-zrAu1ug.jpeg" /><figcaption>Cloud migration</figcaption></figure><p>Move the workloads. Modernise what you can. Keep the business running. Exit the data centre. Demonstrate progress.</p><p>Cloud migration can create a paradox when we become better at migrating legacy architecture than modernising it. Technical debt is easier to carry into the future when organisations migrate more quickly. Instead of being redesigned, legacy systems are moved. New infrastructure preserves outdated operational models. Complexity survives the move.</p><p>There is nothing inherently wrong with moving an existing application into the cloud.</p><p>In many cases, it is exactly the right decision. However, the problem comes when “temporary” compromises quietly become the new architecture.</p><p>A legacy database is migrated rather than redesigned. An old integration survives behind a new API. A batch process becomes a cloud-native scheduled job. Familiar reporting structures are recreated on a modern platform.</p><p>And because the new environment is faster, more scalable, and easier to provision, the underlying debt becomes harder to see, not less significant.</p><p><strong>Why this matters now</strong></p><p>Cloud migration has matured. The question is no longer simply, <em>“Should we move?”</em> It is increasingly, <em>“What should we change while we move?”</em></p><p>I saw this tension in a recent project where business applications were migrated from on-premises infrastructure to AWS.</p><p>The priority was to migrate successfully while minimising disruption. So, while the technology underneath changed, the business processes around it remained largely untouched. Staff continued using the same customer onboarding and approval workflows they had used before.</p><p>On the surface, that made sense. Changing the applications and the way people worked at the same time could introduce unnecessary risk. Keeping familiar processes helped the business maintain continuity while the migration took place.</p><p>But one problem remained: <strong>customer onboarding was still slower than it needed to be.</strong></p><p>The migration hadn’t removed the underlying bottlenecks in the workflow. The same steps still had to be completed, the same approvals still had to happen, and customers still experience delays while their applications moved through the process.</p><p>The applications were now running in AWS, but the business outcome hadn’t fundamentally changed.</p><p>If customer onboarding is still too slow after migration, the next question should be why. Which steps genuinely add value? Where do approvals get stuck? What could be automated, simplified or removed altogether?</p><p>Cloud migration creates an opportunity to ask those questions. It doesn’t answer them for us.</p><p><strong>Three questions worth asking</strong></p><p><strong>1. Are we migrating workloads or capabilities?</strong></p><p>A workload is easy to count. A capability is harder to measure.</p><p>A programme can proudly report hundreds of applications migrated while the business experiences very little meaningful change.</p><p>Before moving anything, ask what business capability it supports and whether that capability should work differently in the future.</p><p><strong>2. Which debt are we deliberately carrying?</strong></p><p>Technical debt is not automatically bad. In many cases, taking on debt is a rational trade-off that allows the business to move faster.</p><p>The problem is not the debt. The problem is pretending it does not exist.</p><p>If an application is being migrated unchanged because speed matters more than redesign, document the decision. Assign ownership. Set a review date.</p><p><strong>3. Are we measuring migration speed or transformation?</strong></p><p>Speed is attractive because it produces a number. Transformation is harder because it produces outcomes.</p><p>A successful migration should eventually tell a story beyond workloads moved and servers decommissioned.</p><p>Can teams release changes faster? Can data be shared and used more effectively?</p><p>Can the organisation adapt products and processes without rebuilding technology every time? Has operational complexity genuinely decreased?</p><p>Those are the measures that determine whether migration created transformation or simply relocated existing systems.</p><p>Slowing down before migrating is sometimes the most beneficial thing a cloud program can do. Not everything needs to be modernised. However, not all things are worthy of preservation.</p><p>Cloud platforms provide extraordinary technical flexibility. They make it easier to scale, deploy, automate, and innovate. What they do not provide is architectural discipline.</p><p>That still comes from people who are willing to challenge assumptions, question long-standing dependencies, and ask whether yesterday’s design decisions still serve today’s objectives.</p><p><strong>Takeaway</strong></p><p>The next time someone celebrates how quickly an organisation has migrated to the cloud, the most important question may not be:</p><p>“How fast did you move?” It may be: “How much of the old thinking came with you?”</p><p>The best cloud migrations do not simply relocate technical debt. They expose it. They create the opportunity to decide what is worth keeping, what should be modernised, and what should finally be retired.</p><p>Because transformation is not measured by how much infrastructure reaches the cloud. It is measured by how much unnecessary complexity is left behind.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b20885301f25" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/the-cloud-migration-paradox-faster-migration-slower-transformation-b20885301f25">The cloud migration paradox: faster migration, slower transformation</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[You survived your Agentic AI pilot. Now what?]]></title>
            <link>https://medium.com/valcon-consulting/you-survived-your-agentic-ai-pilot-now-what-d191c1c0c7bd?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/d191c1c0c7bd</guid>
            <category><![CDATA[adoption]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[digital-transformation]]></category>
            <category><![CDATA[leadership]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Quique Pantoja]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 07:58:33 GMT</pubDate>
            <atom:updated>2026-10-21T07:58:31.965Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rUSLnYCWCECKs_QauLed9Q.png" /></figure><p>Congratulations. You survived your pilot.</p><p>The demo landed well. The numbers looked promising. Stakeholders nodded approvingly. Leadership agreed there was something worth pursuing and authorised the next phase.</p><p>And then… not much happened.</p><p>Six months later, the pilot is still being referenced in presentations. It occasionally resurfaces during innovation discussions. Maybe it has even expanded to a second use case. But it hasn’t become a core business capability. It hasn’t changed how the organisation operates at scale.</p><p>If that sounds familiar, you’re not failing at Agentic AI. According to BCG, 74% of organisations have yet to develop the capabilities needed to move beyond proofs of concept and generate tangible value from AI. The bottleneck is rarely the technology itself. More often, it’s the absence of the operating model, governance, ownership and change required to scale. <a href="https://www.bcg.com/press/24october2024-ai-adoption-in-2024-74-of-companies-struggle-to-achieve-and-scale-value">[1]</a></p><p>You’re failing at something much older, and much harder: organisational change.</p><h3><strong>Passing the pilot was never the finish line — It was the beginning of the journey</strong></h3><p>One of the biggest mistakes organisations make is treating a successful pilot as proof that they are ready for scale and immediately moving on to the next agent they want to build.</p><p>In reality, three very different milestones exist. A Proof of Concept demonstrates that the technology works. A Proof of Value demonstrates that the technology creates measurable business outcomes, whether that’s reducing effort, improving service, accelerating decisions, or lowering risk. Scaling into production proves something entirely different: it proves an organisation can operate, govern, maintain, and continuously improve AI solutions as part of business as usual.</p><p>Most organisations successfully complete the first stage. Many complete the second. Only a small number successfully make the transition to the third. And when they fail, it is rarely because the technology stopped working.</p><p>The excitement is understandable. The first pilot delivers results, stakeholders see the potential, and attention quickly turns to identifying the next opportunity. But scaling Agentic AI isn’t about building more agents. It’s about building the capability to run, govern, adopt, and continuously improve them across the organisation. It’s about making success repeatable by creating a framework that works for your organisation.</p><h3><strong>The real challenges start after the demo</strong></h3><p>Across the Agentic AI programmes I have reviewed, the technology has almost never been the primary constraint. The agents performed as expected, the models generated useful outputs, and the automation delivered measurable improvements. What was missing was everything around the technology.</p><p>In many cases, no capabilities existed to support scaling. There was no operating model, no governance structure, no intake process, no standards, and no clear ownership for what happened after deployment. Just as importantly, there was little focus on organisational readiness. Teams were expected to adopt new ways of working without understanding how the agent would affect their roles, responsibilities, or performance measures.</p><h3><strong>The technology was ready. The organisation wasn’t.</strong></h3><p>No one owned the agent once the project team disbanded. No one had a process to decide which use case got built next, or why. There was no forum to catch a bad decision before it reached a customer, an employee, or a regulator. The teams whose work the agent touched were never brought into the design and simply inherited a fait accompli. Unsurprisingly, some resisted it. In more than one case, the people closest to the process were still being measured on the manual work the agent was meant to remove.</p><p>None of that shows up in a pilot’s success metrics. All of it determines whether the pilot survives contact with the rest of the organisation.</p><h3><strong>Why successful pilots stall</strong></h3><p>During the pilot phase, a dedicated project team provides structure, sponsorship, decision-making, and momentum. Problems get solved quickly because everyone involved is focused on a single objective: proving the concept. Once the pilot concludes, that temporary structure disappears and a new set of questions begins to emerge.</p><p>Who owns the agent? Who is responsible for monitoring performance? Who approves changes? What happens when regulations change? How are new use cases prioritised? How do you ensure different teams are building agents in a consistent and controlled way?</p><p>Another challenge often emerges at this point: adoption.</p><p>Building an agent and getting people to use it are two very different things. Successful organisations actively manage adoption from day one. They engage business users in the design process. They communicate the purpose of the solution early and transparently. They align incentives and measures with the future-state process rather than the current one.</p><p>Most importantly, they help people understand how AI will augment their work rather than simply replace activities.</p><p>When adoption is treated as an afterthought, resistance fills the gap. Even the best-designed agent will struggle to deliver value if the people expected to use it do not trust it, understand it, or see a place for themselves in the future state.</p><p>Executive sponsorship and clear, consistent communication across the business are critical to overcoming that resistance. People need to understand not only what is changing, but why it is changing, how it affects them, and what role they play in the future state. When leaders actively champion the change and business areas are engaged throughout the journey, adoption increases, trust grows, and the value promised in the pilot is far more likely to be realised in practice.</p><p>Without clear answers, pilots enter a state of limbo. They are technically successful but organisationally unsupported. The result is a growing portfolio of disconnected AI experiments that demonstrate potential but fail to generate enterprise-wide impact.</p><h3><strong>What “ready to scale” actually looks like</strong></h3><p>Recently, I helped design and establish an Agentic AI Centre of Excellence for a professional services organisation that had already demonstrated promising results through several AI initiatives.</p><p>The organisation did not need another pilot. It needed a framework for scaling what was already working. The objective was straightforward: to move from isolated experimentation to a repeatable, governed, and value-driven capability.</p><p>That required several foundational components.</p><p>First, ownership and accountability needed to be clearly defined. Every agent required a named business owner accountable for outcomes, risks, adoption, and ongoing performance.</p><p>Second, a structured intake and prioritisation process was introduced. New use cases would be assessed against strategic alignment, business value, feasibility, and risk rather than competing for attention based on visibility or stakeholder influence.</p><p>Third, a Design Authority was established to review solutions before they entered production. This created an opportunity to address governance, architecture, compliance, and operational considerations early rather than reacting after deployment.</p><p>Finally, a value realisation framework was implemented to ensure success could be measured consistently. “The agent works” ceased to be the benchmark. The focus shifted to measurable business outcomes and sustainable value creation.</p><p>Alongside the creation of these capabilities, two Agentic AI Proof of Value initiatives were delivered in Finance and People &amp; Culture. The use cases successfully demonstrated how Agentic AI could streamline activities, reduce manual effort, and improve the employee experience.</p><p>Those outcomes were important, but the more important achievement was creating the conditions for success to be repeated. The agents mattered, but the operating model around them is what made them scalable.</p><h3><strong>The questions every leadership team should be asking</strong></h3><p>Before launching the next wave of Agentic AI initiatives, organisations should pause and assess whether they are truly ready to scale.</p><p>A few questions can quickly reveal the answer.</p><ul><li>Who owns each agent once the implementation team has moved on?</li><li>How are new use cases identified, assessed, and prioritised?</li><li>What governance exists before solutions reach customers, employees, regulators, or critical business processes?</li><li>How are risks monitored and managed throughout the lifecycle of an agent?</li><li>How is value measured after deployment, and who is accountable for delivering it?</li><li>What investment has been made in change management, communications, training, and adoption?</li></ul><p>And perhaps the most revealing question of all:</p><p><strong>If your current pilot expanded to ten times its size tomorrow, would your existing operating model still work?</strong></p><p>If the honest answer is no, then the organisation is not yet scaling Agentic AI. It is simply extending a pilot.</p><h3><strong>The speed of scaling is the speed of change</strong></h3><p>One lesson has become increasingly clear across every AI transformation programme I’ve been involved in.The ability of a Centre of Excellence to scale an AI programme is directly proportional to the ability of the organisation to change.</p><p>Not the quality of the models, not the sophistication of the agents and not the size of the technology investment.</p><p>Change readiness, leadership alignment, user adoption, trust, and the willingness to redesign the way work gets done are ultimately the factors that determine how quickly value can be realised at scale.</p><h3><strong>The exam isn’t over</strong></h3><p>A successful pilot proves an idea has merit. It does not prove an organisation is prepared to operationalise that idea across teams, functions, and business units.That requires a different kind of readiness.It requires ownership, governance, capability building, and, most importantly, people adopting new ways of working.</p><p>The most common obstacles to scaling Agentic AI are rarely technical. They are organisational. They are rooted in change management, adoption, incentives, trust, organisational politics, competing business priorities, internal pressures, conflicting goals, and resistance to change.</p><p>The organisations generating the greatest value from AI are not necessarily building better agents than everyone else. They are building stronger mechanisms to help their people adopt and scale those agents.</p><p>And there is another reality leaders should recognise.AI is moving exponentially. Humans do not.</p><p>We are naturally wired to think in linear terms. We expect progress to happen gradually and predictably. Agentic AI does not behave that way. Capabilities that seem experimental today can become mainstream far faster than organisations are prepared for.</p><p>Ironically, AI’s biggest scaling challenge is not the technology itself.: It’s us.</p><p>We are still the ones making investment decisions, approving budgets, defining policies, redesigning processes, and deciding whether new ways of working are adopted or rejected. We are still the ones acquiring solutions, signing contracts, and operationalising change.</p><p>For better and for worse, humans remain the bottleneck. But that is also good news. If people sit at the centre of the problem, they must also sit at the centre of the solution.</p><p>The organisations that succeed over the next few years will not be those that build the most agents. They will be the ones that help their people adapt, trust, and evolve alongside them, turning isolated AI successes into sustainable business capabilities.</p><p><strong>Because surviving the pilot was never the destination. It was simply the beginning of the journey.</strong></p><p>Enrique Pantoja</p><p>Agentic AI and Automation Technology Director</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d191c1c0c7bd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/you-survived-your-agentic-ai-pilot-now-what-d191c1c0c7bd">You survived your Agentic AI pilot. Now what?</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sovereign data & AI platforms — a path forward for European organisations]]></title>
            <link>https://medium.com/valcon-consulting/sovereign-data-ai-platforms-a-path-forward-for-european-organisations-de2dd9d80e76?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/de2dd9d80e76</guid>
            <category><![CDATA[data-sovereignty]]></category>
            <category><![CDATA[european-cloud]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[cloud-sovereignty]]></category>
            <category><![CDATA[sovereign-ai]]></category>
            <dc:creator><![CDATA[Tim Ellens]]></dc:creator>
            <pubDate>Wed, 14 Oct 2026 15:08:12 GMT</pubDate>
            <atom:updated>2026-10-14T15:08:11.456Z</atom:updated>
            <content:encoded><![CDATA[<p>European organisations want to be able to innovate with <a href="https://valcon.com/services/data-and-ai/">data &amp; AI</a>, but they also want to stay in control of their data environment. And this is particularly pertinent in data-sensitive environments like the public sector, defence and regulated industries like financial services. In client conversations, we are hearing this question more and more: “Can we build a data environment and retain sovereignty?”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/724/1*pRYZcj7TOu-zWssGdbMxeA.jpeg" /></figure><p>We can. And in fact, we already do. But sovereignty is not a checkbox. It is a whole spectrum. Different data sets require different levels of sovereignty, and every organisation needs to decide what level of sovereignty is required for each workload — and the trade-offs it is willing to accept. A Power BI dashboard with public data is very different from a platform that processes classified case files or sensitive citizen data, for example.</p><p><strong>Evaluating sovereignty</strong></p><p><a href="https://commission.europa.eu/news-and-media/news/sovereign-cloud-framework-explained-2026-06-01_en">The European Commission’s Cloud Sovereignty Framework</a> defines sovereignty objectives and Sovereignty Effectiveness Assurance Levels (SEALs) to make cloud sovereignty more measurable in procurement and risk assessment. Instead of relying on broad claims such as ‘European cloud’ or ‘sovereign cloud,’ organisations can assess concrete dimensions such as strategic alignment, legal and jurisdictional exposure, data and AI control, operational independence, supply-chain transparency, technology openness, security and compliance, and environmental dependency. This is especially relevant for public-sector organisations and regulated industries. Sovereignty requirements are becoming part of tenders and board-level risk discussions. The question is no longer only whether a platform is secure or scalable, but also whether the organisation can explain and defend its sovereignty decisions. This is a vital consideration for clients, shareholders, employees and regulators.</p><p><strong>Realistic sovereignty</strong></p><p>Full European digital sovereignty (SEAL 4) across all dimensions is difficult to achieve today. Not because the idea is wrong, but because modern technology and hardware are deeply interconnected in a global supply chain and depend on resources not found in the EU and chips not manufactured in the EU.</p><p>This does not mean that sovereignty is impossible, but it does mean that organisations need to be precise. Which risk are we trying to reduce, for which data, under which regulation, and at what cost? For most workloads, a major public cloud provider remains the best choice because it offers mature services, strong security capabilities, advanced AI features, and a fast developer experience. For other workloads, especially those involving classified, sensitive, or strategically important data, a more sovereign architecture may be required.</p><p><strong>Three practical routes for data &amp; AI platforms</strong></p><p>At <a href="https://valcon.com/">Valcon</a>, we work from data and AI strategy to end-to-end implementation. We help clients assess sovereignty risks and translate them into practical architecture choices, after which we implement, together with the client, a data &amp; AI platform in their environment of choice.</p><p>For data and AI platforms, we typically see three realistic routes:</p><ol><li><strong>Public cloud for speed and innovation:</strong> platforms such as Databricks provide a strong developer experience, mature data and AI capabilities and continuous innovation. This can be the right choice when the data classification and risk profile allow it.</li><li><strong>A </strong><a href="https://valcon.com/insights/news/valcon-databricks-secure-data-platform/"><strong>disconnected data platform</strong></a><strong> for highly restricted data:</strong> some organisations work with classified or extremely sensitive data that cannot be stored or processed in a public cloud. In those cases, a disconnected data platform that can run air-gapped (with locked-down access to the internet or any other digital environment) within the perimeter of the client’s organisation can be the right solution. This increases infrastructure and operational complexity, but it also enables the organisation to process data safely within its own network boundaries.</li><li><strong>A sovereign data and AI platform for controlled flexibilit</strong>y: when a US public cloud is not acceptable, but a fully disconnected platform is too heavy, a sovereign data and AI platform can provide a middle ground. It is based on open-source technology, is designed to be portable, and can run in a private cloud, on European cloud providers such as STACKIT, Scaleway or OVHcloud, or on dedicated infrastructure.</li></ol><p>A client may decide to keep general analytics workloads on a hyperscaler, for example. While moving sensitive AI inference workloads to a controlled European environment. That is often more realistic than trying to make the entire IT landscape sovereign overnight.</p><p><strong>Sovereign data &amp; AI platform architecture</strong></p><p>A sovereign data and AI platform should avoid unnecessary lock-in while still offering a modern engineering experience. Valcon builds on proven open-source components by <a href="https://www.databricks.com/">Databricks</a> such as Apache Spark, Delta Lake, Unity Catalog and MLflow, and combines them with technologies such as vLLM and open-source AI inference models. The platform can run on Kubernetes, uses S3-compatible object storage and supports vector storage for AI workloads. This architecture supports both an exit strategy from public cloud, a hybrid scenario, and a standalone setup.</p><p><strong>One size doesn’t fit all</strong></p><p>Valcon already has considerable experience of creating data sovereignty within the financial, public and defence sectors. This is where Valcon can help: not by pushing one default platform, but by helping clients decide which workloads need which level of control and then building the platform to match. That can be in a client’s own environment, on a European cloud provider, or on a public cloud platform where that is the right fit.</p><p>Sovereignty is not about choosing one technology forever. It is about understanding your risks, making conscious trade-offs, and building a platform strategy that gives you the right level of control.</p><p><strong>Come and speak to Valcon about data sovereignty</strong></p><p>If you are having similar discussions, feel free to reach out to speak to us. As a European company, we feel the responsibility to help European clients with their sovereignty challenges and solve them. Please contact: <a href="/service/mailto:tim.ellens@valcon.com">tim.ellens@valcon.com</a> and <a href="/service/mailto:sander.de.jongh@valcon.com">sander.de.jongh@valcon.com</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=de2dd9d80e76" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/sovereign-data-ai-platforms-a-path-forward-for-european-organisations-de2dd9d80e76">Sovereign data &amp; AI platforms — a path forward for European organisations</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Performance tuning AI — lessons from the front line]]></title>
            <link>https://medium.com/valcon-consulting/performance-tuning-ai-lessons-from-the-front-line-a36278b5fb75?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/a36278b5fb75</guid>
            <category><![CDATA[ai-performance]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai-architecture]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[enterprise-ai]]></category>
            <dc:creator><![CDATA[Martyn Gurr]]></dc:creator>
            <pubDate>Tue, 06 Oct 2026 10:25:22 GMT</pubDate>
            <atom:updated>2026-10-06T10:25:21.430Z</atom:updated>
            <content:encoded><![CDATA[<p><strong><em>By Martyn Gurr, senior technology principal, Valcon UK</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ph35V8YyRrretlJzoY6piQ.png" /></figure><p>Artificial intelligence is often positioned as a silver bullet: faster decisions, smarter experiences, step‑change productivity. The reality, particularly in large enterprise environments with complex legacy data, is far more nuanced.</p><p>Recently, our team worked with a global organisation facing a deceptively simple challenge: how to help frontline specialists find the right technical information quickly, reliably and safely.</p><p>What followed was a multi‑month journey through performance bottlenecks, architectural trade‑offs, and some hard‑won lessons about where AI genuinely adds value — and where it should be kept firmly on a leash. And valuable knowledge on how to scale enterprise AI through performance tuning.</p><p><strong>The client challenge: knowledge at scale, under pressure</strong></p><p>The client operates in a highly regulated, safety‑critical environment. Their frontline workforce relies on vast volumes of technical documentation: repair manuals, diagnostic guides, service bulletins and procedural updates accumulated over decades.</p><p>Two pressures were colliding. The first was information overload — for even relatively standard tasks, documentation could span thousands of pages. Finding the <em>right</em> section often required deep expertise and time-consuming navigation. The second issue was shrinking experience levels — as experienced specialists retired, newer staff had to handle increasing technical complexity with less tacit knowledge to fall back on.</p><p>Traditional keyword search was no longer sufficient. The documents were structured for <em>display</em>, not meaning. Semantic relationships were weak, terminology inconsistent and the same concept could appear under different names depending on context.</p><p>The ambition was clear: provide a conversational, context‑aware interface that allows specialists to ask questions in natural language and receive <em>actionable, trustworthy guidance</em> — grounded entirely in authorised source material.</p><p><strong>The solution: retrieval</strong>‑<strong>augmented AI, built for the real world</strong></p><p>The solution combined modern AI techniques with deliberately conservative engineering choices.</p><p>At its core was a retrieval‑augmented generation (RAG) architecture. Rather than asking a large language model (LLM) to ‘know’ the answers, the system retrieves relevant source documents first and then asks the model to synthesise an answer strictly from those sources.</p><p>This distinction mattered. In safety‑critical environments, hallucinations are unacceptable. Every generated answer needed to be traceable back to official documentation, with clear signalling of what was retrieved versus what was generated.</p><p>The front end was designed around the realities of the user context: minimal distraction, emphasis on safety information, clear step-by-step flows, and support for hands‑free interaction such as voice input and read‑back.</p><p>Behind the scenes, however, the real challenge wasn’t functionality — it was performance.</p><p><strong>Performance is the product</strong></p><p>Early prototypes worked functionally but failed a basic user test: initial response times were taking 50–60 seconds and in a workshop or operational setting, that’s an eternity. Response times would need to be reduced to single seconds.</p><p>It quickly became clear that AI performance was being impeded by the <em>cumulative cost of many small decision</em>s, such as:</p><ul><li>Keeping it ‘simple’ with a single LLM call for entire answer generation</li><li>Ensuring the full breadth of relevant content was featured in a ‘rich’ answer</li><li>Traditional separation of functions, i.e. generate answer first and then translate.</li></ul><p>Individually, each of these steps appeared reasonable. But together, they pushed response times far beyond acceptable non‑functional requirements.</p><p>The team ultimately reduced end‑to‑end response times to around 12–15 seconds through leveraging detailed content and domain knowledge for aggressive parallelisation — the process of breaking one big job down into smaller independent units that can be run at the same time. They did this for content processing, careful model selection and ruthless placement of function to move AI features that added latency into code wherever possible.</p><p>One example stood out. Even asking a model to maintain consecutive numbering of references significantly increased the processing time. Seemingly trivial output constraints can impose surprising cognitive and computational overhead. In this case, it was almost trivial to handle this in code, but doing so started moving us away the sort of ‘simple’ implementations most initial software builds strive for.</p><p><strong>The myth of ‘just upgrade the model’</strong></p><p>A common executive instinct is to assume newer models will automatically fix performance or quality problems. In this case, the experience was the opposite.</p><p>Upgrading between models — even within the same family — produced materially different outputs. Prompts that previously yielded concise, technician‑friendly answers suddenly exploded into verbose explanations. In some cases, older models outperformed more advanced ones simply because they adhered more literally to instructions and generated less text with less reasoning. Unless it is constrained, more reasoning means more text which means bigger answers and slower performance.</p><p>The implication is important: model upgrades are infrastructure upgrades. They require prompt re‑engineering, regression testing, and often architectural changes. Treating them as infrastructure swaps is a costly mistake.</p><p><strong>Where AI helps — and where it hurts</strong></p><p>Perhaps the most important lesson was philosophical rather than technical.</p><p>AI was invaluable where the problem space was fuzzy: extracting ‘interesting values’ from messy documents, understanding how humans phrase questions, or summarising complex procedures for different experience levels. This is where strong prompt engineering and a domain knowledge layer come in — to place controls around interpretation and to guide output towards intended outcomes.</p><p>It performed poorly where deterministic behaviour was required. Tasks such as classification, filtering, exclusion rules and prioritisation often worked better — and faster — when implemented in conventional code.</p><p>Similarly, when asked to do multiple activities, for example when generating an answer, often the AI would ‘helpfully’ infer rules about one activity from another leading to unexpected results based on a minor change in the source material put before it and unpredictability when amending the prompt for one activity would alter the output for another.</p><p>Over time, a clear design principle emerged:</p><p><strong><em>If a rule can be expressed as a simple conditional statement, write it in code. Use AI only where genuine interpretation is required on an activity-by-activity basis.</em></strong></p><p>This hybrid approach reduced latency, improved consistency and made the system easier to reason about and maintain.</p><p><strong>Economics, scale, and the illusion of speed</strong></p><p>At enterprise scale — tens of thousands of users — even small inefficiencies become expensive. Token usage, caching strategies, provider‑specific behaviour and request orchestration all have real cost implications.</p><p>The team found that prompt caching and reuse of static context dramatically reduced both cost and latency, but only with a proper understanding of the caching capabilities offered by different model providers. Benefits can still be derived from all-or nothing caching rather than more dynamic caching, but more attention to this is required up front.</p><p>Another important insight was that perceived speed often matters as much as actual speed. Carefully designed status updates and progress indicators transformed user tolerance, even when the underlying processing time remained unchanged.</p><p>Streaming, in other words, is not magic — it is theatre. But sometimes, that theatre is necessary.</p><p><strong>What executives should take away</strong></p><p>This project reinforced several truths about enterprise AI:</p><ul><li>AI is not slow because it is immature; it is slow because it is <em>doing a lot of different activities humans normally do implicitly</em></li><li>Architectural discipline matters more than model choice</li><li>Performance tuning is not an optimisation phase — it is core product design</li><li>Determinism and transparency are as important as intelligence in regulated environments; strong prompt engineering and the application of domain knowledge into prompt intent are key</li></ul><p>Above all, success came not from chasing ‘more AI’, but from being deliberate about <em>where</em> intelligence was applied and <em>where it was deliberately constrained</em>. For organisations embarking on similar journeys, that may be the most valuable lesson of all.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a36278b5fb75" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/performance-tuning-ai-lessons-from-the-front-line-a36278b5fb75">Performance tuning AI — lessons from the front line</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enforcing Data Contracts on Databricks]]></title>
            <link>https://medium.com/valcon-consulting/enforcing-data-contracts-on-databricks-3802fc873668?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/3802fc873668</guid>
            <category><![CDATA[data-governance]]></category>
            <category><![CDATA[data-contract]]></category>
            <category><![CDATA[data-architecture]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[databricks]]></category>
            <dc:creator><![CDATA[Ivan Medrano Velazquez]]></dc:creator>
            <pubDate>Wed, 23 Sep 2026 13:56:31 GMT</pubDate>
            <atom:updated>2026-09-23T14:03:17.352Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><p>For the past year, we have been building a data product for a large retail client that has to comply with the EU Deforestation Regulation (EUDR). The short version of the regulation is this: for products containing in-scope commodities that cross the EU border, the company must file a Due Diligence Statement with the EU’s central system, including geolocation data for the plots where the raw material was produced.</p><p>For an operational compliance pipeline, failure does not look like dashboard numbers that are incorrect. The consequences are financial and reputational. The design we created revolved around the core principle of trust and transparency. The goal was not to get 100% accuracy; it was to build a system that could explain why a certain piece of data was not processed. The result is a pipeline that can answer the question of why without much effort.</p><p>This post describes how that works in practice. The stack is Databricks (Unity Catalog + Delta Lake) with PySpark pipelines, but the pattern transfers to any Spark platform.</p><p>Each contract is a YAML file in the repository, loosely following the Open Data Contract Standard (<a href="https://bitol-io.github.io/open-data-contract-standard/">https://bitol-io.github.io/open-data-contract-standard/</a>). It includes contract metadata, a description block, an ownership section, and one or more schemas. We keep one contract per layer or pipeline: a silver contract, a gold contract, and a handful of pipeline-specific ones, such as item scope, tariff codes, and supplier flows.</p><p>A trimmed example:</p><pre>domain: supply-chain<br>dataProduct: eudr-compliance<br>kind: DataContract<br>version: 1.0.0<br>status: active<br>description:<br>purpose: Supply chain data models for EUDR compliance analysis<br>limitations: Limited to supply chain operations for specific business units<br>usage: Track and analyse supply chain operations for regulatory compliance<br>notes: Every table has a staging counterpart with the same model.<br>Data lands in staging first, then is merged into the gold table.<br>team:<br>  - username: data.engineer.one@client.example <br>    role: Owner<br>    dateIn: 2024–04–04<br>  - username: data.engineer.two@client.example<br>    role: Backup<br>    dateIn: 2025–04–04<br>  - username: product.leader@client.example<br>    role: Data Product Leader<br>    dateIn: 2025–04–04<br>schema:<br>  - name: commodities<br>    physicalName: commodities<br>    physicalType: table<br>    description: Master record of regulated commodities linking products to<br>    their tariff classifications and validity periods<br>  properties:<br>    - { name: id, physicalType: string, required: true,<br>    description: Unique identifier, source: generated at run time }<br>    - { name: item_no, physicalType: string, required: true,<br>    description: Item number, source: upstream item master }<br>    - { name: tariff_no, physicalType: string, required: false,<br>    description: Tariff number, source: derived in tariff mapping step }<br>    - { name: valid_from, physicalType: date, required: true,<br>    description: Start date of validity, source: upstream item master }<br>    - { name: valid_to, physicalType: date, required: true,<br>    description: End date of validity, source: upstream item master }<br>    - { name: insert_date, physicalType: timestamp, required: false,<br>    description: Record insert timestamp, source: pipeline at run time }</pre><p>There are three key values in our process:</p><p>● Ownership is in the contract. Every contract names an owner, a backup, and a data product leader, with the date they took on the role. When something breaks at 4 pm on a Friday, nobody has to search through an outdated wiki. The line of responsibility is clear and easy to understand.</p><p>● Every column documents its source. The source annotation records where a field comes from: an upstream system or a derivation step. It is not machine-parsed lineage; it is human-readable lineage that lives in the one file people actually open.</p><p>● Conventions are written down where they bind. The notes field documents the staging-then-merge pattern that every table in the file follows. The contract is the starting point when beginning to work with this data.</p><h3>The core concept</h3><p>A contract that is only documentation starts rotting the day it is created. The way we keep ours honest is to make everything downstream dependent on it. The same YAML file feeds four consumers:</p><pre>                    ┌─────────────────────────────┐<br>                    │    data contract (YAML)     │<br>                    │    one per layer / feed     │<br>                    └──────────────┬──────────────┘<br>                                   │<br>       ┌─────────────────┬─────────┴─────────┬─────────────────┐<br>       ▼                 ▼                   ▼                 ▼<br>runtime schemas    DDL deployment      catalog docs      test fixtures<br>(PySpark Struct-   (create &amp; evolve    (table + column   (unit tests build<br> Types for frames   tables to match     comments synced   their frames from<br> and API payloads)  the contract)       on every deploy)  the same schemas)</pre><p>If the contract changes, the tables change, the runtime schemas change, the catalogue documentation changes, and the tests verify it all from one pull request.</p><h3>1. Runtime schemas for the pipelines</h3><p>A small custom class parses the YAML and converts each schema into a PySpark StructType. Pipelines never hand-write schemas:</p><pre>loader = DataContractLoader(&quot;../model/data_contracts&quot;, logger)<br>commodities_schema = loader.get_schema(&quot;commodities&quot;, &quot;gold_data_contract.yml&quot;)<br>df = spark.createDataFrame(rows, schema=commodities_schema)</pre><p>The conversion is simple:</p><pre>def _convert_to_struct_type(self, schema_def):<br>    fields = []<br>    for prop in schema_def.get(&quot;properties&quot;, []):<br>        fields.append(StructField(<br>            prop[&quot;name&quot;],<br>            self._get_field_type(prop),<br>            nullable=not prop.get(&quot;required&quot;, False),<br>            metadata={k: v for k, v in prop.items()<br>                      if k in (&quot;businessName&quot;, &quot;description&quot;, &quot;primaryKey&quot;)},<br>        ))<br>    return StructType(fields)</pre><h3>2. Deploying tables from a contract</h3><p>The second consumer is a deployment step that treats the contracts the way Databricks treats an asset bundle file: as the desired state. On every environment deployment, a deploy_tables() routine:</p><p>1. Loads all contract files and merges schemas that target the same physical table.</p><p>2. Runs CREATE TABLE IF NOT EXISTS for anything new.</p><p>3. Diffs the live table against the contract with DESCRIBE TABLE.</p><p>4. Adds missing columns with ALTER TABLE … ADD COLUMNS.</p><p>5. Migrates type changes (more on that below).</p><p>6. Drops columns that are no longer in the contract, and can optionally drop whole tables that no contract claims.</p><p>Because it is a diff-and-converge loop rather than a one-shot DDL script, it is idempotent: running it against an up-to-date environment is a no-op, and dev, test, and production cannot drift apart because none of them is ever touched by hand.</p><p>The one difficult part is type changes. Delta Lake will not alter a column’s type in place for most conversions, so the deployer does a four-step process through a staging column:</p><pre>spark.sql(f&quot;ALTER TABLE {table} ADD COLUMN {col}_staging {new_type}&quot;)<br>spark.sql(f&quot;UPDATE {table} SET {col}_staging = CAST({col} AS {new_type})&quot;)<br>spark.sql(f&quot;ALTER TABLE {table} DROP COLUMN {col}&quot;)<br>spark.sql(f&quot;ALTER TABLE {table} RENAME COLUMN {col}_staging TO {col}&quot;)</pre><p>It is written this way because of Databricks’ limitations around altering columns in place. We decided early on that it was worth implementing because it gave us a true source of truth for every table. If we left this use case out, we could experience a correctness leak, and developers could directly alter the table state.</p><h3>3. Documentation that lives in the catalogue</h3><p>Analysts do not read YAML in a repository; they browse the data catalogue. So the deployment step also syncs every table and column description from the contract into Unity Catalog:</p><pre>COMMENT ON TABLE catalog.schema.commodities IS &#39;Master record of regulated commodities…&#39;;<br>ALTER TABLE catalog.schema.commodities ALTER COLUMN tariff_no COMMENT &#39;Tariff number&#39;;</pre><p>The sync is diff-based and only writes when the contract and the catalogue disagree. Descriptions are written once, in the contract, and show up in Unity Catalog, including in the catalogue’s search. When a description improves in a pull request, the catalogue improves on the next deploy.</p><h3>4. Tests that break when the contract does</h3><p>Our unit tests build their fixture DataFrames from the same loader:</p><pre>contract_loader = DataContractLoader(&quot;../model/data_contracts&quot;, logger)<br>schemas = contract_loader.load_contract_schemas(&quot;gold_data_contract.yml&quot;)</pre><p>If someone changes a contract in a way the pipeline code cannot handle, the tests constructing fixtures from that contract fail in CI. There is no second version of the schema inside the test suite, which is where schema drift goes to hide.</p><h3>Why not just use DQX?</h3><p>Alongside the deployment of tables based on the contracts, we had a few use cases where DQX did not fit, as of August 2026.</p><p>Several of our physical tables are fed by more than one flow, each producing a slightly different shape. Rather than copy and paste near-identical schemas, contracts support an extends property, which is resolved by the loader. This is a custom property and is not supported by DQX’s current implementation. I believe schema inheritance is important for consistency and accuracy:</p><pre>- name: measures_base_schema<br>  physicalName: measures<br>  physicalType: table<br>  properties:<br>    - { name: commodity_id, physicalType: string, required: true }<br>    - { name: item_no,      physicalType: string, required: true }<br><br>- name: measures_qty_schema<br>  physicalName: measures<br>  customProperties:<br>    - property: extends<br>      value: measures_base_schema<br>  properties:<br>    - { name: sum_plan_qty, physicalType: string, required: false }<br><br>- name: measures_vol_schema<br>  physicalName: measures<br>  customProperties:<br>    - property: extends<br>      value: measures_qty_schema<br>  properties:<br>    - { name: dds_net_weight, physicalType: &quot;decimal(22,2)&quot;, required: false }<br>    - { name: dds_net_volume, physicalType: &quot;decimal(22,2)&quot;, required: false }</pre><p>Chains are allowed (base extended by qty extended by vol), a child can override a parent’s property by redeclaring the same name, and new properties are appended. Note the separation between the logical schema name and the physicalName: three logical schemas here describe one physical table.</p><p>The flip side of that separation is that when several contract files each declare schemas for the same physicalName, in our case an EU-supplier flow and a non-EU-supplier flow that both write producers and measures, the deployer merges their properties into a superset before converging the table. Each flow’s pipeline builds frames against its own narrower schema; the physical table accommodates the union. Neither table contract needs to know about the other’s columns.</p><h3>Next steps</h3><p>Features that we maintain manually, such as contracts as state for tables and schema inheritance, are things I hope Databricks introduces as part of DQX. Schema inheritance is vital for the correctness of schemas and coherence during deployments. State-based tables are long overdue, not just from Databricks but as a standard practice in the industry. With current technology, there is no excuse for having so much hidden with regard to data models and data consistency.</p><p>We are also working on a new version of the custom utilities. Although we wish we could wait for new tools to come to us, at a certain point we have to start building them ourselves.</p><p>1. We have introduced contract versions and plan to enforce contract versions as breaking changes through our CI process.</p><p>2. Combining the DQX tools with our enhanced data contract utilities through a wrapper.</p><p>3. Centralising the data contract repository.</p><h3>Conclusion</h3><p>If you are introducing data contracts on a similar platform, this is what I would advise you to do:</p><p>1. <strong>Make the contract executable on day one.</strong> The difference between a contract and a document is that something breaks when the contract is wrong. Deriving runtime schemas and DDL from it is what turns documentation into an interface.</p><p>2. You do not need a platform purchase to start. Our entire implementation is YAML files, two Python classes of a few hundred lines, and a deployment step. Git and pull-request review are the governance mechanism. That said, I am a fan of Unity Catalog, and this would enrich whatever UC implementation you already have.</p><p>3. <strong>Put ownership and lineage in the file people open.</strong> A team block and per-column source annotations cost minutes to write and answer the two questions every incident starts with: <em>who owns this</em> and <em>where does this field come from</em>.</p><p>4. <strong>Let the physical and logical models diverge deliberately.</strong> Inheritance and merge-by-physical-name kept our contracts DRY while letting one table serve multiple flows.</p><p>5. <strong>Sequence the rollout by risk.</strong> Structure first (schemas, tables, docs), then contract linting, then quality rules and breaking-change checks. Structure is where the regulatory risk lived for us; your order may differ.</p><p>Most of the value showed up in human review and during the process, not at runtime. A schema change on this product is a one-file diff that a data engineer, a tester, and a product leader can all read, and everything downstream of that diff is a machine’s job.</p><p>One thing I have learned from the advent of AI is that organisations want accountability and ownership. Despite all of the code flying around, there will always be a documented state of your data if you enforce it; do not make it optional. Companies and people want somebody to speak to. Do not neglect the ownership parts of the document just because they do not break your pipeline.</p><p>My LinkedIn DMs are open if you’re interested in chatting about this more. Code and data standards are things I am genuinely interested in discussing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*usQ2bGZhURO-_eA5D6Sbog.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3802fc873668" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/enforcing-data-contracts-on-databricks-3802fc873668">Enforcing Data Contracts on Databricks</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vibe coding, AppGen, and AI augmented delivery: speed vs. scale in the age of AI]]></title>
            <link>https://medium.com/valcon-consulting/vibe-coding-appgen-and-ai-augmented-delivery-speed-vs-scale-in-the-age-of-ai-855d8f25cdb9?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/855d8f25cdb9</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[digital-transformation]]></category>
            <category><![CDATA[low-code]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <dc:creator><![CDATA[Rick Bekker]]></dc:creator>
            <pubDate>Thu, 10 Sep 2026 15:04:39 GMT</pubDate>
            <atom:updated>2026-09-10T15:04:38.122Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wJgc1OrK8iKPL43MNn7qVg.png" /></figure><p>Generative AI is transforming software development. Tools such as Cursor, Lovable, Bolt, and Replit can generate applications from simple prompts, while low-code platforms such as Appian, Mendix, Pega, Power Platform, and UiPath are embedding AI to automate application delivery. As a result, organisations are increasingly choosing between three approaches: Vibe coding, AI-augmented<strong> </strong>development and AppGen (AI-driven low-code development). AI-augmented development sits between these extremes, combining professional software engineering practices with AI-powered coding assistants such as GitHub Copilot and Claude Code to accelerate development while maintaining architectural control, code quality, and governance. Vibe coding, AppGen and AI-augmented AI are used to accelerate analysis, design, coding, testing, and delivery.</p><p>Although all delivery methods use AI to accelerate development, they are designed for different goals. Vibe coding prioritises rapid creation, while AppGen focuses on delivering enterprise-ready applications that are secure, maintainable, and governed.</p><p>Dark factory AI development is a fully autonomous software process where AI agents write, test, review, and deploy code based on text specifications without human intervention on individual changes. This is a part which is not covered in this article and mainly used for development of non-mission critical applications, mainly due to the EU AI Act.</p><h3>What is Vibe Coding?</h3><p>Vibe coding is a development style where users describe what they want in natural language and AI generates the code. The emphasis is on speed, experimentation, and creativity. A developer or even a business user can build a working application in minutes.</p><p>The benefits are clear:</p><ul><li>Extremely fast prototyping</li><li>Low barrier to entry</li><li>Rapid experimentation</li><li>Ideal for proofs of concept</li><li>Reduced need to write code manually</li></ul><p>However, as applications become larger and more business critical, challenges emerge. AI-generated code can be difficult to review, maintain, test, and secure. Organisations often struggle with governance, architectural consistency, compliance requirements, and long-term ownership. The developer may not be able to fully explain the AI-generated code or predict how it will behave in new scenarios, creating a dependency on AI not only for code generation but also for understanding, modifying, and maintaining the application.</p><h3><strong>What is AI-Augmented Development?</strong></h3><p>AI-Augmented Development is a professional software engineering approach in which AI assists developers by generating code, tests, documentation, architectural suggestions, and implementation accelerators. Unlike vibe coding the code is accessible for the developer when it is ready to be deployed. AI is used to increase productivity, while developers remain responsible for solution design, code reviews, testing, security, compliance, governance, and operational quality. This approach applies established software engineering best practices throughout the development lifecycle, making it suitable for enterprise-grade production systems where reliability, maintainability and scalability are applied.</p><h3>What is AppGen?</h3><p>To explain AppGen, it is important to first understand low-code, the development platform that provides the foundation for AI-assisted application development. Low-code is a software development approach that uses visual modelling, prebuilt components, and configuration to create applications within a structured development environment.</p><p>AppGen is an AI-driven application development approach that combines generative AI with a low-code platform to automatically create and refine enterprise applications from business requirements and natural language prompts. The key difference is that applications remain governed by the platform. Low-code platforms provide built-in capabilities such as:</p><ul><li>Security and access management</li><li>Reusable components</li><li>Governance and audit trails</li><li>CI/CD and deployment management</li><li>Monitoring and operational controls</li><li>Integration with enterprise systems</li></ul><p>This allows teams to achieve AI-driven productivity while maintaining enterprise standards.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XyW1vCq2KSAojzL8bR-RsQ.png" /></figure><h3>The key difference</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/875/1*vkWoA1M9uzQj9b56o7-MMw.png" /></figure><p>In short, Vibe coding delivers maximum speed but lacks the governance, security, and maintainability required for enterprise environments. AI-augmented development accelerates professional software engineering, but testing, review, and validation remain largely manual and time-consuming. AppGen (Low-Code) combines AI-driven productivity with built-in governance, enabling organisations to scale applications safely and efficiently.</p><h3>Why Enterprises Need More Than Generate Code</h3><p>Many organisations have successfully adopted AI assistants and coding tools. Yet relatively few have embedded AI into their operational core. The challenge is not creating software, it is integrating AI into business processes, systems, governance frameworks, and compliance requirements.</p><p>Several common challenges emerge:</p><p>• <strong>Context Gap</strong>: AI can generate functionality, but without access to connected business data and process context, its business value remains limited.</p><p>• <strong>Execution Gap</strong>: AI can provide recommendations, but applications are needed to orchestrate processes, systems, and people to turn recommendations into actions.</p><p>• <strong>Governance Gap</strong>: Organisations require built-in auditability, compliance, security, and policy controls to deploy AI safely and at scale.</p><p>• <strong>Fragmentation Gap</strong>: Independent adoption of AI tools can create disconnected solutions that are difficult to govern, support, and scale.</p><h3>Total Cost of Ownership: The Hidden Cost Behind Speed</h3><p>While all three approaches accelerate software delivery, their long-term Total Cost of Ownership (TCO) differs significantly. Initial development costs are only a small part of the equation. Maintenance, testing, security, governance, compliance, infrastructure, and future enhancements often represent the majority of the costs over an application’s lifetime.</p><p>Vibe Coding (Lovable, Bolt, Replit) typically has the lowest cost to create a prototype, but often the highest long-term TCO. As applications grow, organisations face increasing costs related to code review, testing, security remediation, architectural refactoring, documentation, and ongoing maintenance. The absence of built-in governance can also create technical debt and shadow IT, making ownership expensive over time.</p><p>AI-Augmented Development (Claude Code, GitHub Copilot, Codex) reduces developer effort and improves productivity, but organisations remain responsible for architecture, testing, quality assurance, security, deployment pipelines, monitoring, and maintenance. Development costs are lower than traditional coding, but long-term ownership still depends heavily on engineering discipline and skilled development teams. As a result, AI-Augmented Development typically delivers a lower TCO than traditional software development, but a higher TCO than AppGen platforms, as organisations must still manage much of the operational, architectural, and governance burden themselves.</p><p>AppGen (Low-Code) generally introduces platform and licensing costs upfront, but often delivers the lowest TCO for enterprise applications. Security, governance, deployment management, reusable components, monitoring, and compliance capabilities are provided by the platform, reducing maintenance effort and operational overhead. As a result, organisations can scale applications with fewer resources and more predictable long-term costs.</p><h3>The Future Is Both; AppGen and AI-Augmented Development</h3><p>The future is unlikely to be a choice between AI-Augmented Development and AppGen. Instead, organisations will use both.</p><ul><li><strong>Vibe coding</strong> for exploration and rapid innovation — for non-enterprise environments.</li><li><strong>AI-Augmented Development </strong>for expert developers building complex custom solutions.</li><li><strong>AppGen (low-code)</strong> for enterprise execution, governance, and scalability.</li></ul><p>As AI continues to democratise software creation, competitive advantage will not come from generating applications faster. It will come from turning those applications into reliable, governed, and maintainable business solutions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jtUh_zQUv9L2W656mNn6hQ.png" /></figure><p>For enterprises, the challenge is no longer building applications with AI. The real challenge is governing, operating, and scaling them across the organisation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MPGXAPrgJkFyjOBfLJouAw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=855d8f25cdb9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/vibe-coding-appgen-and-ai-augmented-delivery-speed-vs-scale-in-the-age-of-ai-855d8f25cdb9">Vibe coding, AppGen, and AI augmented delivery: speed vs. scale in the age of AI</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We stopped building data pipelines. Databricks started doing it for us.]]></title>
            <link>https://medium.com/valcon-consulting/we-stopped-building-data-pipelines-databricks-started-doing-it-for-us-c4f046f899cb?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/c4f046f899cb</guid>
            <category><![CDATA[data-architecture]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[databricks]]></category>
            <category><![CDATA[lake-house]]></category>
            <category><![CDATA[data-platforms]]></category>
            <dc:creator><![CDATA[Yash Shah]]></dc:creator>
            <pubDate>Thu, 03 Sep 2026 14:47:58 GMT</pubDate>
            <atom:updated>2026-10-13T09:37:51.484Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/885/1*MAhNQmXfpgusgMyXAkR9mg.png" /></figure><blockquote><strong>The first Databricks notebook is exciting.</strong></blockquote><blockquote><strong>The fiftieth notebook is a warning sign.</strong></blockquote><p>Every organisation starts its Databricks journey with a vision to modernise and unlock value from its data. The first few notebooks solve an important problem. The solution works, so the pattern gets repeated. Another team adopts it. New use cases arrive, and more notebooks follow.</p><p>Soon a data <em>platform </em>is born.</p><p>Initially, this approach works remarkably well. New datasets are onboarded quickly, teams move independently and business value is delivered fast.</p><p>However, as adoption grows, success begins to create its own challenges. More notebooks are created, more patterns emerge, and more custom logic is introduced. Gradually, a large share of engineering effort shifts from <strong><em>building </em></strong>new capabilities<em> </em>to<em> </em><strong><em>maintaining </em></strong>existing ones.</p><p>This was a reality we faced with a client I recently worked with. The business wanted to move fast across strategic initiatives, but the platform was struggling to keep pace. Every new capability introduced additional complexity, and every new dataset seemed to require more effort than the last.</p><p>Eventually, the same question kept resurfacing:</p><blockquote><strong>Are we still delivering business value, or are we spending most of our time maintaining capabilities that Databricks can now provide natively?</strong></blockquote><h3><strong>The existing platform and its challenges</strong></h3><p>At the time, the platform consisted of nearly fifty pipeline notebooks spread across multiple business units. The implementation was built around custom <em>PySpark </em>transformations and reusable notebook patterns.</p><p>As business adoption increased, there was a growing need to introduce platform-wide capabilities such as:</p><ul><li>Change data capture (CDC)</li><li>Schema enforcement</li><li>Slowly Changing Dimension (SCD) Type 2 handling</li><li>Governance tagging</li><li>Row-level security</li><li>Operational monitoring</li></ul><p>Individually, none of these requirements were particularly difficult to implement. The challenge lay in the architecture itself.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FTi9Qn9OARbSThohcRCC7g.png" /><figcaption>Figure: Old setup — Siloed, notebook-driven with duplicated logic and difficult to maintain</figcaption></figure><p>Every new enhancement required repeated implementation effort across multiple pipelines. Features such as governance, CDC handling and schema validation could not simply be introduced once and reused consistently.</p><p>As a result, platform maturity slowed, operational complexity increased, and maintaining consistency across datasets became increasingly challenging.</p><blockquote><strong>Perhaps most importantly, architectural standards started relying more on tribal knowledge than on the platform itself.</strong></blockquote><p>That became the catalyst for a broader platform redesign.</p><h3>The upgrade</h3><p>As <strong>Valcon</strong>, our goal was to enable developers to spend most of their productive time developing business transformations, while platform capabilities such as governance, schema management, orchestration and deployment should be handled consistently and automatically.</p><p>To achieve this, we separated the implementation into two parts:</p><h4><strong>The framework (the “how”)</strong></h4><p>A reusable, installable Python package containing:</p><ul><li>Table abstractions</li><li>Schema management</li><li>CDC validation</li><li>Governance enforcement</li><li>Shared utilities</li></ul><h4><strong>The Pipeline Layer (the “what”)</strong></h4><p>A Declarative Pipelines implementation with:</p><ul><li>Domain-specific business logic</li><li>Table definitions</li><li>Pipeline registration</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*66LaQ2U9-yD-L3I8hsO4tg.png" /><figcaption>Figure: New setup — Standardised, declarative, governed and maintainable</figcaption></figure><h4><strong>Lakeflow Declarative Pipelines (<em>LDP</em>): <em>Letting the platform manage the DAG</em></strong></h4><p>The most significant change was the introduction of LDP. Previously, execution order was explicitly managed through workflow design and dependency configuration.</p><p>With domain-specific LDP, we turned existing notebooks into series of dependable units, each with its custom transformations while the platform constructed and managed the execution graph automatically.</p><p>This significantly <strong>reduced orchestration overhead</strong> as platform concerns such as managing dependencies, checkpointing, retries and lineage were handled natively.</p><p>LDP helped turn architectural principles into platform capabilities, enabling teams to focus on business transformations rather than pipeline management.</p><h4><strong>Auto CDC: removed an entire category of Custom Code</strong></h4><p>Our historical SCD1 and SCD2 processing required significant custom merge logic. Every implementation introduced opportunities for subtle differences in behavior.</p><p>By adopting Auto CDC flows, historical tracking became a platform concern rather than an application concern.</p><p>It removed existing custom merge implementations, brought a <strong>consistent CDC pattern</strong> across the platform, improved maintainability, and reduced the engineering effort needed to evolve alongside platform requirements.</p><p>Citing our business roadmap, this was one of the strongest arguments for adopting modern Databricks capabilities and supercharging the development efforts.</p><h4><strong>Unity Catalog: governance moved closer to the data itself</strong></h4><p>During this migration, Unity Catalog became a key architectural building block.</p><p>Instead of managing governance as a separate operational activity, governance metadata became part of the schema definition itself.</p><p>Classifications, policies and row-level security were embedded directly and applied automatically to tables after pipeline execution.</p><p>With this, the platform automatically knew which columns contained sensitive information, which governance tags should be applied, and which policies should be validated.</p><p>By moving <strong>governance closer to the data itself</strong>, Unity Catalog helped transform governance from an operational burden into a scalable platform capability, while preparing the platform for future AI and analytics initiatives.</p><h4><strong>Databricks asset bundles: enabled platform consistency</strong></h4><p>Another major step was adopting Databricks Asset Bundles for deployment. Earlier, the deployments relied heavily on custom deployment logic and environment-specific configuration.</p><p>With the inclusion of Asset Bundles, deployment became <strong>declarative and repeatable</strong>. Development, test, pre-production and production environments all followed the same deployment model, with environment-specific configuration injected through bundle definitions.</p><p>Asset Bundles helped eliminate one of the most persistent challenges in data platforms:</p><blockquote><strong>It works in development, but not in production.</strong></blockquote><h3>What could be improved further?</h3><p>While data landscapes are constantly evolving, there is rarely an ultimate state of perfection. Several opportunities for further maturity remain:</p><ol><li><strong>Framework versioning</strong><br> Introduce support for running different framework versions across environments to reduce upgrade risk and improve release flexibility.</li><li><strong>More metadata-driven patterns</strong><br> Move more platform capabilities from code into configuration to simplify onboarding and improve scalability across domains.</li><li><strong>Continuously challenge custom implementations</strong><br> Regularly review custom components against the Databricks roadmap, as capabilities that once required custom development may now be available natively.</li></ol><h3>Key takeaways</h3><ol><li>Many data platforms gradually accumulate custom solutions for problems that modern platforms already solve.</li><li>Lakeflow Declarative Pipelines, Auto CDC, Unity Catalog and Asset Bundles helped us simplify the platform while improving consistency, governance and maintainability.</li><li>We realized that <strong><em>the most valuable code is often the code you no longer need to maintain.</em></strong></li></ol><p>As developers, our natural instinct is to see a problem and start building a solution. More often than not, that is exactly the right thing to do. However, as architects, it is equally important to occasionally step back and challenge our assumptions.</p><blockquote>Looking back, the challenge was never implementing CDC, governance or deployment patterns. We knew how to build those capabilities.</blockquote><blockquote><strong>The challenge was recognising when we should stop building them ourselves.</strong></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c4f046f899cb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/we-stopped-building-data-pipelines-databricks-started-doing-it-for-us-c4f046f899cb">We stopped building data pipelines. Databricks started doing it for us.</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Databricks Lakehouse Platform with Terraform Modules]]></title>
            <link>https://medium.com/valcon-consulting/building-a-databricks-lakehouse-platform-with-terraform-modules-f9bc9b65aa61?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/f9bc9b65aa61</guid>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[azure-databricks]]></category>
            <category><![CDATA[databricks]]></category>
            <category><![CDATA[terraform-modules]]></category>
            <dc:creator><![CDATA[Karlo Kotarac]]></dc:creator>
            <pubDate>Wed, 19 Aug 2026 08:15:10 GMT</pubDate>
            <atom:updated>2026-08-19T08:15:09.090Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This article was co-authored with <strong>Vedran Opančar</strong> (<a href="https://medium.com/@v.opancar">@v.opancar</a>).</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/1*nbrkTeBsZ4fXewfYbFUOdg.png" /></figure><p>Databricks is a rapidly evolving Data &amp; AI platform, and platform engineers need a manageable way to maintain it. This is where Terraform comes into the picture. In this blog, we present our vision for organising Azure and Databricks resources in a way that can help you build and manage a Lakehouse platform more effectively.</p><p>If you need assistance, <a href="https://valcon.com/"><strong>Valcon</strong></a>, a Databricks Gold Partner, can support you. This blog can be seen as a follow-up to the previous article, <a href="https://medium.com/valcon-consulting/managing-databricks-with-terraform-a-modular-approach-d5cbc62cfdea"><strong><em>Managing Databricks with Terraform: A modular approach</em></strong></a>. Similar to that blog, this one focuses on Azure Databricks, although most of the concepts described here are also relevant for other cloud providers. We recommend reading the previous article first, as this blog builds upon it and references it throughout. References to the previous article are marked with the abbreviation <strong>MDT</strong>.</p><p>Our main guidelines when building these Terraform modules were:</p><ul><li><strong>We should not mix different Terraform providers or provider configurations within a single module.</strong> This helps preserve clear authentication and security boundaries.</li><li><strong>All modules are designed with different operational roles in mind.</strong> Different teams often handle Azure administration and various aspects of Databricks administration, so modules are aligned with ownership boundaries.</li><li><strong>Different resources have different lifecycles, so the modules should respect that.</strong> Resources with similar rates of change should be grouped together.</li><li><strong>The modules should be simple to use</strong>. Usually, not all team members have Terraform experience, so we recommend using YAML and/or JSON files to define configuration wherever possible.</li><li><strong>Security is not an afterthought but is part of the platform by design.</strong> This includes network isolation, Unity Catalog permissions, workspace and account-level governance settings, and least-privilege access controls.</li></ul><p>The operations required to build and manage the platform can be separated into four categories, each requiring different privileges:</p><ul><li>Azure <strong>subscription </strong>operations (Required: <strong>Contributor</strong> and <strong>RBAC Administrator</strong> roles, or <strong>Owner</strong>, at the required scope)</li><li>Databricks<strong> account-level </strong>operations (Required: Databricks <strong>Account Admin</strong> role)</li><li>Databricks <strong>metastore</strong> operations (Required: Databricks <strong>Metastore Admin</strong> role or appropriate Unity Catalog privileges)</li><li>Databricks <strong>workspace</strong> operations (Required: Databricks <strong>Workspace Admin</strong> role)</li></ul><p>The remainder of this blog is organised around Terraform modules. For each module, we will describe its purpose, key assumptions, the resources that belong to it, and the most important design considerations. The modules represent logical ownership, lifecycle, and security boundaries rather than mandatory Terraform state boundaries. An overview of all modules is shown in Figure 1.</p><p>One of the key challenges that influenced this module structure was deploying Databricks in environments where private CI/CD runners could not reach the Databricks account endpoint. Solving this challenge without introducing excessive pipeline and Terraform state complexity influenced several of the design decisions discussed later in this article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/886/1*Oe8u-6Gvg6v-jwWl-j4gCg.png" /><figcaption><strong>Figure 1. Overview of Terraform modules and administrative boundaries</strong></figcaption></figure><h4><strong>Module 1: Azure resources — Deploys and configures Azure infrastructure.</strong></h4><p>Depending on your platform requirements, Azure resources can be organised into a single module or multiple Azure modules. As the primary focus of this blog is Databricks, we keep all Azure resources in a single module and only cover the common Azure resources required to support the Databricks platform.</p><p><strong>Assumptions</strong></p><ul><li>Azure subscription is created.</li><li>Deployment CI/CD identity is created and granted Contributor and RBAC Administrator roles, or Owner, at the required scope.</li><li>Virtual network is created.</li></ul><p><strong>Resources</strong></p><p>Resource groups are logical containers for Azure resources that simplify organisation, access management, and separation of responsibilities. For example, network resources can be grouped together to simplify administration and permission management (resource: azurerm_resource_group).</p><p>Two subnets (container and host) are required for VNet-injected Databricks deployments for classic compute (resource: azurerm_subnet). VNet-injection is the recommended deployment model for classic compute as it provides greater control over networking and security. At least one additional subnet is typically required for private endpoints that enable secure connectivity to Azure resources that are not publicly accessible. Databricks recommends using a /26 or larger address space for each workspace subnet, and subnet sizing should be planned carefully to accommodate the expected cluster capacity.</p><p>Two key Databricks-related resources are deployed in this module: the Databricks Workspace (resource: azurerm_databricks_workspace) and the Databricks Access Connector (resource: azurerm_databricks_access_connector). Depending on the deployment approach, the creation order of these resources may be important. We will discuss this in more detail in a future blog.</p><p>The Databricks Access Connector provides a managed identity that Databricks can use to securely access Azure resources such as storage accounts, key vaults, and other services. Configuring access consists of two steps: granting the managed identity the required Azure permissions through role assignments (resource: azurerm_role_assignment) and granting Databricks principals access to these resources through Unity Catalog.</p><p>We recommend using separate access connectors for different resource domains. For example, if we create a storage account (resource: azurerm_storage_account) and an Azure Key Vault (resource: azurerm_key_vault), we should create two access connectors to improve security isolation and simplify permission management. If private access to these resources is required, private endpoints can also be created (resource: azurerm_private_endpoint).</p><p>When it comes to observability, there are two common options. Databricks system tables are often sufficient for Databricks-specific monitoring, while Log Analytics (resource: azurerm_log_analytics_workspace) together with diagnostic settings (resource: azurerm_monitor_diagnostic_setting) can be used when logs from Databricks and other Azure resources need to be stored centrally.</p><p>Finally, as a security best practice, separate identities should be used for Terraform infrastructure deployments and Databricks workloads. This helps split responsibilities and enforce the principle of least privilege. Depending on the use case, dedicated service principals or user-assigned managed identities (resource: azurerm_user_assigned_identity) can be used for Databricks jobs and other platform workloads.</p><h4><strong>Important considerations: Unity Catalog automatic enablement and identities</strong></h4><p>The usual workflow, marked with the blue line in Figure 1 and previously discussed in the MDT blog, is that after a Databricks workspace is created, Unity Catalog is enabled by attaching a metastore to the workspace at the account level. Once Unity Catalog is enabled, principals (users, groups, and service principals) are added to the workspace.</p><p>The challenge we faced at a client was that the private CI/CD runners used for Azure resource deployments did not have connectivity to the Databricks account endpoint. This would have required splitting the CI/CD pipeline into three parts: (1) private runners for Azure resource deployments, (2) public agents for Databricks account-level operations, and (3) private runners for Databricks workspace and Unity Catalog operations. In addition, this would have required maintaining three separate Terraform states, significantly increasing the complexity of the solution.</p><p>To keep the CI/CD process as simple as possible, we decided to avoid Databricks account-level operations during this phase (see the red line in Figure 1) and instead use a dedicated pipeline for Databricks account administration. This approach was possible because Databricks now supports automatic metastore assignment during workspace creation. With this option, Unity Catalog was enabled automatically, and principals could subsequently be added from the workspace itself, provided that automatic identity management was enabled at the account level. In this configuration, Entra ID principals become automatically available within Databricks.</p><p>However, there is an important catch. Although any principal can be added to the workspace through the Databricks UI, the same approach does not work directly through Terraform. The reason is that Entra ID identities must first be assigned a Databricks identity before they can be referenced in Terraform resources.</p><p>Fortunately, Databricks now provides identity resolution APIs that can be used at the workspace level. For example, service principals can be resolved using the <a href="https://docs.databricks.com/api/azure/workspace/iamv2/resolveserviceprincipalproxy"><em>resolveByExternalId</em></a> API together with their Entra ID object ID. Similar APIs exist for users and groups, both at the workspace and account level.</p><p>To invoke these APIs from Terraform, the terraform_data resource can be combined with an idempotent local-exec provisioner that runs the Databricks CLI or directly calls the API. Alternatively, identity resolution can be executed as a CI/CD pre-deployment step before principals are referenced by Terraform.</p><h4><strong>Module 2: Unity Catalog objects — Manages data objects.</strong></h4><p>When it comes to Unity Catalog objects, we first need to define the boundary between resources managed through Terraform and resources managed through DABs (Declarative Automation Bundles, formerly known as Databricks Asset Bundles). We use Terraform for Unity Catalog objects that define the platform foundation, such as credentials, external locations, catalogs, schemas and volumes. Objects closely tied to applications or data products are better managed through DABs alongside the workloads that use them.</p><p><strong>Assumptions</strong></p><ul><li>Unity Catalog is enabled in the workspace.</li><li>Deployment CI/CD identity is either a Metastore Admin or has the appropriate Unity Catalog privileges required to manage the target resources.</li><li>Principals are resolved in Databricks.</li></ul><p><strong>Resources</strong></p><p>Previously, we granted the Databricks Access Connector managed identity access to Azure storage accounts and services such as Azure Key Vault. The next step is to register this identity as either a storage credential or a service credential (resource: databricks_credential), depending on whether it will be used to access an Azure storage account or another service.</p><p>External locations (resource: databricks_external_location) and catalogs (resource: databricks_catalog) are the primary building blocks for organising data and defining access patterns and should therefore be created next. We define external locations at the storage container level because this keeps the storage boundary clear and easy to govern. Catalog design should primarily follow business boundaries such as environment, domain, or ownership, while medallion layers can be represented as schemas within those catalogs.</p><p>We can create catalogs as either open or isolated. Open catalogs are available from all workspaces, while isolated catalogs are available only from the workspace in which they were created. If a catalog needs to be shared with additional workspaces, it can be exposed using the databricks_workspace_binding resource in either read-only or read-write mode.</p><p>Once the Unity Catalog foundation is in place, additional resources such as schemas (resource: databricks_schema) and volumes (resource: databricks_volume) can be created. Schemas provide logical organisation within catalogs, while volumes store non-tabular data and files in Unity Catalog. Tabular data objects, such as tables and views, are typically created and managed as part of DAB deployments.</p><h4><strong>Module 3: Unity Catalog privileges — Assigns privileges to Unity Catalog objects.</strong></h4><p>This is likely the module whose resources will change most frequently. Separating Unity Catalog privileges from Unity Catalog object creation allows both modules to evolve independently, as access requirements typically change much more often than the underlying data structure.</p><p><strong>Assumptions</strong></p><ul><li>Unity Catalog objects exist.</li><li>Principals are resolved in Databricks.</li><li>Deployment CI/CD identity has the required privileges to grant permissions.</li></ul><p><strong>Resources</strong></p><p>In addition to the privileges management concepts already covered in the MDT blog, we recommend using the databricks_grants resource wherever possible. Unlike individual grant resources, databricks_grants manages the complete set of privileges for a securable object and overrides privileges granted manually or outside of the current Terraform configuration. This helps ensure that the actual privileges remain aligned with the desired state defined in Terraform.</p><p>To simplify privileges management, we recommend defining Unity Catalog privileges in an easy-to-read format such as YAML and then ingesting that configuration into Terraform. This allows privilege changes to be made without modifying Terraform code and enables platform administrators to manage access without requiring deep Terraform knowledge.</p><p>Example:</p><pre>catalogs:<br>  bronze:<br>    grants:<br>      - principal: data-engineers<br>        privileges:<br>          - USE_CATALOG<br>      - principal: data-analysts<br>        privileges:<br>          - USE_CATALOG<br><br>schemas:<br>  &quot;bronze.sales&quot;:<br>    grants:<br>      - principal: sales-team<br>        privileges:<br>          - USE_SCHEMA<br>          - SELECT</pre><p>Terraform can then load the file and create the corresponding databricks_grants resources dynamically.</p><p>Related to secret management, there are now two additional approaches besides the secret scopes discussed in the MDT blog:</p><ul><li>Using service credentials, as explained in Hubert Dudek’s <a href="https://www.sunnydata.ai/blog/azure-key-vault-unity-catalog-service-credentials">blog</a>. Access to Azure Key Vault secrets is controlled through the Unity Catalog ACCESS privilege granted on the corresponding service credential. This is the recommended approach when integrating Azure Key Vault with Databricks.</li><li>Databricks also supports managing secrets as Unity Catalog objects (catalog.schema.secret). This enables fine-grained access control at the individual secret level and provides a Unity Catalog-native approach to secret management (see <a href="https://learn.microsoft.com/en-us/azure/databricks/security/secrets/unity-catalog-secrets">documentation</a>).</li></ul><h4><strong>Module 4: Databricks workspace governance — Manages workspace access, entitlements, and settings.</strong></h4><p>Once the Unity Catalog foundation is in place, we can start onboarding users and configuring workspace governance settings.</p><p><strong>Assumptions</strong></p><ul><li>Deployment CI/CD identity is a Workspace Admin.</li><li>If certain workspace settings are managed, the deployment identity may also need to be granted Databricks Account Admin privilege.</li></ul><p><strong>Resources</strong></p><p>We first add principals (users, groups, and service principals) to the Databricks workspace and assign them either user or Workspace Admin permissions. This can be achieved using the databricks_permission_assignment resource.</p><p>To better control what users can do within a workspace, the databricks_entitlements resource can be used to manage capabilities such as access to the Workspace UI, Databricks SQL, and Genie One (previously known as Databricks One). This allows different experiences to be provided for data engineers, data scientists, data analysts, and business users.</p><p>Databricks workspaces expose many configuration settings that can now be managed through the databricks_workspace_setting_v2 resource, which at the time of writing is available in Public Preview. Compared to the older databricks_workspace_conf resource, it offers several advantages:</p><ul><li>Settings are officially documented and supported.</li><li>Available settings can be easily discovered and managed.</li><li>Preview workspace settings are supported.</li><li>Each setting is managed as a separate resource, providing better granularity and control.</li></ul><p>More details on important Databricks workspace settings will be covered in a future blog focused on secure Databricks workspace deployments.</p><h4><strong>Module 5: Databricks workspace objects — Creates operational objects inside a Databricks workspace.</strong></h4><p>After users have been added to the workspace and their way of working has been defined in the previous module, the final ingredient required for development is providing access to compute resources.</p><p><strong>Assumptions</strong></p><ul><li>Deployment CI/CD identity is a Workspace Admin.</li></ul><p><strong>Resources</strong></p><p>Although Databricks increasingly promotes serverless compute because it simplifies management and enables advanced AI capabilities, most clients still use a combination of serverless, all-purpose, and job compute.</p><p>One trend we increasingly see at clients is controlling access to compute through cluster policies (resource: databricks_cluster_policy). This approach simplifies cluster administration compared to creating dedicated clusters for individual users (resource: databricks_cluster). Job workloads should generally use job clusters governed by cluster policies, as this approach typically results in better resource utilisation and lower costs. For personas that primarily require SQL access, such as data analysts, SQL warehouses can be created (resource: databricks_sql_endpoint).</p><p>The reason we suggest creating Unity Catalog objects before workspace objects is that cluster policies can use Unity Catalog volumes to store cluster logs, making them easier to govern and share with users.</p><p>Additional information about cluster policies and compute management can be found in the previously published blog <a href="https://medium.com/valcon-consulting/unity-catalog-migration-best-practices-lessons-learned-from-two-implementations-part-1-f692811643a6"><strong><em>Unity Catalog migration best practices: Lessons learned from two implementations</em></strong></a><strong>.</strong></p><p>Compared to the MDT blog, we would highlight two additional recommendations:</p><p>1. Cluster policy definitions should be kept outside of Terraform code in JSON files. This keeps the configuration transparent for end users and easier to manage for the platform team. The only value that typically needs to be specified outside the JSON definition is the maximum number of clusters per user, which is configured directly on the cluster policy resource. The example below illustrates a development-focused cluster policy that enforces Unity Catalog security, centralised logging, and cost controls while still allowing flexibility in runtime selection and compute configuration:</p><pre>{<br>  &quot;cluster_type&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: &quot;all-purpose&quot;<br>  },<br>  &quot;data_security_mode&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: &quot;USER_ISOLATION&quot;,<br>    &quot;hidden&quot;: true<br>  },<br>  &quot;runtime_engine&quot;: {<br>    &quot;type&quot;: &quot;allowlist&quot;,<br>    &quot;values&quot;: [&quot;STANDARD&quot;, &quot;PHOTON&quot;],<br>    &quot;defaultValue&quot;: &quot;STANDARD&quot;<br>  },<br>  &quot;autoscale.min_workers&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: 1,<br>    &quot;hidden&quot;: true<br>  },<br>  &quot;autoscale.max_workers&quot;: {<br>    &quot;type&quot;: &quot;range&quot;,<br>    &quot;maxValue&quot;: 4,<br>    &quot;defaultValue&quot;: 2<br>  },<br>  &quot;autotermination_minutes&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: 30,<br>    &quot;hidden&quot;: true<br>  },<br>  &quot;dbus_per_hour&quot;: {<br>    &quot;type&quot;: &quot;range&quot;,<br>    &quot;maxValue&quot;: 15<br>  },<br>  &quot;custom_tags.Environment&quot;: {<br>    &quot;type&quot;: &quot;allowlist&quot;,<br>    &quot;values&quot;: [&quot;dev&quot;, &quot;test&quot;, &quot;prod&quot;]<br>  },<br>  &quot;cluster_log_conf.type&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: &quot;VOLUMES&quot;,<br>    &quot;hidden&quot;: true<br>  },<br>  &quot;cluster_log_conf.path&quot;: {<br>    &quot;type&quot;: &quot;fixed&quot;,<br>    &quot;value&quot;: &quot;/Volumes/platform/observability/cluster_logs&quot;,<br>    &quot;hidden&quot;: true<br>  }<br>}</pre><p>2. We recommend keeping permissions on workspace objects, such as folders, cluster policies, and other workspace-level resources, within the same module where those objects are created. Unlike Unity Catalog permissions, these permissions usually change infrequently and can therefore be managed together with the underlying resources using the databricks_permissions resource.</p><h4><strong>Module 6: Databricks account — Provides account-level administration capabilities across all Databricks workspaces.</strong></h4><p>The modules discussed so far focus on Azure resources, Unity Catalog, and workspace-level configuration. However, Databricks also includes a separate account layer responsible for managing identities, workspaces, networking, and account-level governance and security. Because these resources require different privileges and are often operated by a separate platform team, they are managed in a dedicated module.</p><p>Additionally, as mentioned earlier, Databricks account-level operations may require a separate CI/CD process. In our case, private runners used for Azure and workspace deployments did not have connectivity to the Databricks account endpoint, making separate deployment pipelines a practical solution.</p><p><strong>Assumptions</strong></p><ul><li>Deployment CI/CD identity is a Databricks Account Admin.</li><li>Databricks account endpoint is reachable from the CI/CD pipeline.</li><li>Principals are resolved in Databricks.</li></ul><p><strong>Resources</strong></p><p>In the MDT blog, several account-level resources were distributed across multiple modules. Although Databricks-managed account groups created with the databricks_group resource can be useful in certain situations, they add complexity on top of Microsoft Entra ID group management. Microsoft Entra ID-managed account groups should therefore be the default authorisation principals, while Databricks-managed groups should be reserved for explicit Databricks-only requirements.</p><p>Other account-level resources were related to Network Connectivity Configurations (NCC), which enable private connectivity between serverless compute and external resources (resources: databricks_mws_network_connectivity_config, databricks_mws_ncc_binding, databricks_mws_ncc_private_endpoint_rule).</p><p>If Databricks is deployed in a way that outbound connections from standard clusters are controlled and restricted, it is usually desirable to apply similar controls to serverless compute. Network policies (resource: databricks_account_network_policy) provide an additional layer of security by controlling outbound network access for serverless workloads. To assign a network policy to a Databricks workspace, the databricks_workspace_network_option resource can be used.</p><p>As recommended earlier, dedicated service principals should be used for Databricks workloads. To control which users or groups can use these service principals, the databricks_access_control_rule_set resource can be used.</p><p>Finally, similar to the databricks_workspace_setting_v2 resource discussed in Module 4, Databricks provides the databricks_account_setting_v2 resource for managing account-wide settings in a consistent and declarative manner. At the time of writing, this resource is in Public Preview.</p><h4><strong>Production Terraform essentials</strong></h4><p>Although these controls are not Databricks-specific, they are important for production Terraform deployments:</p><ul><li>Use a secure remote backend with state locking.</li><li>Define explicit Terraform and provider version constraints.</li><li>Commit the <em>.terraform.lock.hcl</em> file to source control.</li><li>Use OIDC or workload identity federation for CI/CD authentication instead of long-lived secrets.</li><li>Apply <em>prevent_destroy</em> selectively to critical resources.</li><li>Promote reviewed and versioned modules through deployment environments.</li><li>Run scheduled Terraform plan executions to detect configuration drift.</li></ul><p>The proposed module structure is not intended to be a strict blueprint but rather a starting point that can be adapted to project requirements. In our experience, aligning Terraform modules with provider, ownership, lifecycle, and security boundaries simplifies CI/CD processes, improves governance, and makes Databricks platforms easier to operate as they grow.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9bc9b65aa61" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/building-a-databricks-lakehouse-platform-with-terraform-modules-f9bc9b65aa61">Building a Databricks Lakehouse Platform with Terraform Modules</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your cloud budget forecast just got six months longer- and a lot more honest]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/valcon-consulting/your-cloud-budget-forecast-just-got-six-months-longer-and-a-lot-more-honest-58b953f14d9f?source=rss----9ba0a8d8e953---4"><img src="https://cdn-images-1.medium.com/max/1536/1*aHYkDUJrin1jMpe2LIVVFw.png" width="1536"></a></p><p class="medium-feed-snippet">If you&#x2019;ve ever sat in a budget review trying to explain why next year&#x2019;s cloud spend looks the way it does, you know the problem isn&#x2019;t the&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/valcon-consulting/your-cloud-budget-forecast-just-got-six-months-longer-and-a-lot-more-honest-58b953f14d9f?source=rss----9ba0a8d8e953---4">Continue reading on Valcon »</a></p></div>]]></description>
            <link>https://medium.com/valcon-consulting/your-cloud-budget-forecast-just-got-six-months-longer-and-a-lot-more-honest-58b953f14d9f?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/58b953f14d9f</guid>
            <category><![CDATA[agentic-ai]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[finops]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Kaushal Amin]]></dc:creator>
            <pubDate>Wed, 12 Aug 2026 14:59:58 GMT</pubDate>
            <atom:updated>2026-08-12T14:59:57.536Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Processing high-volume event data within a 60-minute SLA on Databricks]]></title>
            <link>https://medium.com/valcon-consulting/processing-high-volume-event-data-within-a-60-minute-sla-on-databricks-777164a4ced2?source=rss----9ba0a8d8e953---4</link>
            <guid isPermaLink="false">https://medium.com/p/777164a4ced2</guid>
            <category><![CDATA[databricks]]></category>
            <category><![CDATA[data-pipeline]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[apache-spark]]></category>
            <dc:creator><![CDATA[Stefan Vujčić]]></dc:creator>
            <pubDate>Wed, 22 Jul 2026 13:01:30 GMT</pubDate>
            <atom:updated>2026-07-22T13:01:28.854Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qa9bxTy1WRH4XTNizaYoqw.png" /></figure><h4>Why this pipeline needed more than standard batch processing</h4><p>Telecom networks generate data continuously. Calls, messages, and data sessions produce millions of records per hour, every hour of the day. But in this project, volume was only half the challenge. The harder constraint was time.</p><p>On a telecom project I worked on, every event had to be fully processed within one hour of arriving in the data platform. This was not a soft target. If the pipeline missed the window, downstream systems for billing, analytics, and compliance would work with stale data. At terabyte scale, across two Databricks workspaces, that SLA became the forcing function behind almost every architectural and operational decision.</p><p>This article is not a general introduction to Databricks or the Medallion architecture. It is a practical walkthrough of the problems we hit while trying to meet that SLA, and the optimisations that made it achievable. Some of the solutions are Databricks-specific. Most of the thinking applies to any high-volume, latency-sensitive data pipeline.</p><p>If you’re building or operating a pipeline where processing latency actually matters, there’s something here for you.</p><h4>Pipeline overview</h4><p>The platform followed a <strong>Medallion architecture</strong>: data moved through three progressive layers (Bronze, Silver, and Gold), each adding structure, quality, and business meaning. <em>(See figure below.)</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Dive0j4FU1Kc8Yfb3OJqiw.png" /></figure><p>Incoming files were continuously landing in our Azure Data Lake Storage account in <strong>zipped Protobuf format,</strong> compact and efficient for transmission, but requiring custom deserialisation before the pipeline could work with structured, queryable columns.</p><p>The pipeline was split across <strong>two dedicated production workspaces</strong>:</p><ul><li><strong>Ingest workspace</strong> — handled Raw → Bronze → Silver. Auto Loader detects incoming files, after which a custom deserialisation step converts the Protobuf binary content into structured columns before appending records into the Bronze Delta table. A further process then deduplicates and merges records into Silver.</li><li><strong>Transformation workspace</strong> — handled Silver → Gold. Updates to the Silver table trigger a Structured Streaming job that applies business-level transformations and writes to the Gold layer.</li></ul><p>This two-workspace separation was a deliberate architectural choice: keeping ingestion and transformation concerns isolated means a problem on one side doesn’t destabilise the other.</p><p>Beyond production, dedicated development and testing workspaces mirrored the same topology, allowing end-to-end validation before anything reached production.</p><p>How the pipeline runs:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mMgHtat_fJIBUJVz7Y_X0A.png" /></figure><p>Two things worth noting from this table:</p><ul><li>The <strong>ingest job ran every 30 minutes</strong> on a fixed schedule, leaving enough time for Bronze, Silver, and Gold processing to complete within the SLA window. Running once per hour wouldn’t have been enough — a record landing just after a run completed would have had to wait up to 60 minutes before being picked up by a new run, leaving no time to meet the SLA.</li><li>Within each job, availableNow=true was used as the Structured Streaming trigger mode. Instead of running continuously, each job processed all currently available data in a single microbatch and then self-terminated.</li></ul><p><strong>The SLA budget</strong> is worth making explicit. Sixty minutes sounds generous until you account for: Auto Loader discovery latency, Protobuf deserialisation, Bronze append, Silver deduplication and merge, cross-workspace trigger delay, Gold microbatch processing, and cluster startup time. Every optimisation in this article targets one or more of these stages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*50kpaEPgw2JP-5cuE3VBYw.png" /></figure><p>The breakdown above reflects typical observed timings from the production pipeline. Individual run times varied depending on data volume, but these figures represent a realistic baseline for a normal run.</p><h4>Reducing file discovery latency with Auto Loader events</h4><p><strong>Why directory listing became a bottleneck</strong></p><p>Auto Loader supports two file discovery modes: <strong>directory listing</strong> and <strong>file notification</strong>. Directory listing is the default, working by periodically scanning the source directory for new files. Simple to set up, no infrastructure dependencies. But at scale it has a serious flaw: as the number of files in the directory grows, each scan takes longer. On a high-volume pipeline where files land continuously, directory listing latency quickly eats into the SLA budget before a single record is processed.</p><p><strong>The fix: switch to managed file events</strong></p><p>File events mode uses cloud storage events for file discovery. Azure Databricks automatically configures Azure Event Grid and Azure Storage Queues on your behalf, and Auto Loader reads from the managed file events cache to identify newly arrived files, instead of relying on periodic directory scans. Discovery latency drops from minutes to seconds or near-instant, regardless of how many files are in the directory.</p><p>Databricks now recommends cloudFiles.useManagedFileEvents as the standard way to enable this. The code change itself is straightforward — a single option added to the stream configuration. However, the prerequisite is having file events enabled on your Unity Catalog external location, which requires coordination with your cloud and platform teams to configure the underlying storage event infrastructure.</p><pre>.option(&quot;cloudFiles.useManagedFileEvents&quot;, &quot;true&quot;)</pre><p>On first run, Auto Loader performs a full directory listing to synchronise with the file events cache and establish a read position in the checkpoint. Every subsequent run reads directly from that cache, with no directory scanning and near-instant file discovery.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*PDcSpLkIlEUZg5i23vzNIA.png" /></figure><p><strong>One step further: Tuning </strong>maxFilesPerTrigger<strong> on the Bronze side</strong></p><p>Once file discovery is fast, the next tuning parameter to consider is maxFilesPerTrigger, which controls how many files Auto Loader processes per single run. On the Raw → Bronze Auto Loader read we set this to 10000, a deliberate cap that keeps individual microbatch size predictable.</p><p>This is a genuine tradeoff: too low and the stream becomes inefficient due to many small batches; too high and a batch occasionally grows large enough to threaten your latency budget. The right number depends on your file sizes and cluster configuration — and it requires measurement under realistic load rather than guessing.</p><h4>Making MERGE INTO fast enough for the Silver layer</h4><p><strong>Why MERGE INTO became expensive at scale</strong></p><p>The Bronze → Silver job relied on MERGE INTOto deduplicate and upsert records into the target table. At small scale, merges are fast and largely unnoticeable. At TB scale, however, they become one of the most expensive operations in the pipeline, and a significant risk to SLA compliance.</p><p>The cost comes from two places. First, Spark has to <strong>scan the target table</strong> to find matching records, and without good data organisation, that means scanning a lot of data you don’t need. Second, Delta Lake <strong>rewrites entire files</strong> even when only a few rows within them are affected by the merge. The more files touched by the merge operation, the higher the cost.</p><p><strong>Optimisation 1: use liquid clustering on Silver</strong></p><p>Liquid clustering (CLUSTER BY) organises data based on columns frequently used in filters, joins, or merge conditions, meaning Delta can skip large portions of the table that don’t match the query predicate rather than scanning everything. For a high-cardinality key like a unique event identifier, the scan reduction is dramatic.</p><p>Unlike traditional partitioning, liquid clustering can be added or changed on an existing table at any time via ALTER TABLE — no need to recreate it. New data immediately follows the updated clustering keys. However, existing data is not automatically reclustered. To force reclustering of all historical data you need to run OPTIMIZE FULL.</p><p>It’s also worth noting that Databricks now supports CLUSTER BY AUTO, which selects and adapts clustering keys automatically for Unity Catalog managed tables.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/586/1*PLIVnyklXo5Cf_HxfJilVg.png" /></figure><p><strong>Optimisation 2: deduplicate before the merge</strong></p><p>The more rows you feed into a merge, the more expensive it gets. If your incoming microbatch contains duplicates, the merge has to resolve them, adding complexity and cost to an already expensive operation. Deduplicating the incoming dataset before it hits the merge reduces the number of rows Spark has to match and write.</p><p>This also has a correctness benefit: duplicates that survive into Silver create downstream problems in Gold that are much harder to fix than catching them before the merge.</p><p><strong>Optimisation 3: drop unneeded columns early</strong></p><p>Every column that travels from Bronze through the merge is a column Spark has to read, compare, and potentially rewrite. Dropping columns that aren’t needed in Silver (at the Bronze → Silver boundary) means less data flows into every merge operation. Fewer columns means smaller files, faster scans, and less data rewritten.</p><h4>Processing only what changed</h4><p><strong>Why full reprocessing was not an option</strong></p><p>The easiest pipeline design is also the most expensive: read the entire dataset, run every transformation, and merge all results back into the target tables on every run. That can work at small scale. At terabyte scale, it quickly destroys the SLA budget. The real goal was not just to process faster, but to avoid processing unchanged data at all.</p><p><strong>Optimisation: use Change Data Feed for Gold</strong></p><p>Silver was a merge target, not an append-only table, which means rows can be inserted, updated, or deleted as new data arrives. If Silver were append-only like Bronze, the Gold job could simply process newly appended data. But because rows can change after they’ve already been written, a simple “read what’s new” approach wasn’t enough. The Gold job also needed to know when an existing row was updated or removed.</p><p>This is exactly the problem <strong>Change Data Feed (CDF)</strong> solves. Rather than reading the full Silver table on every microbatch, the Gold job read only what changed since the last run.</p><p>CDF is not enabled by default. You turn it on at the table level:</p><pre>ALTER TABLE silver_table<br>SET TBLPROPERTIES (delta.enableChangeDataFeed = true);</pre><p>Once enabled, Delta maintains a change log for every write to the table. Each record includes a _change_type column with one of four values: insert, delete, update_preimage (row before the change), or update_postimage (row after the change).</p><p>The Gold job read from this change log using readChangeFeed:</p><pre>silver_changes_df = spark.readStream \<br>.option(&quot;readChangeFeed&quot;, &quot;true&quot;) \<br>.table(&quot;silver_table&quot;)</pre><p>Combined with the availableNow=True trigger, each Gold job run processed only what changed since the last run. The job fired, processed the change set, and terminated. No redundant scanning, no reprocessing records that hadn’t changed. For a full reference on CDF configuration and options, see the <a href="https://docs.databricks.com/aws/en/delta/delta-change-data-feed">Databricks Change Data Feed documentation</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Hi_xnp8gy5a4SfOdDFCuOA.png" /></figure><h4>Removing idle wait between pipeline layers</h4><p><strong>Why scheduled handoffs added risk</strong></p><p>Optimising individual processing stages is only part of the latency equation. Delays between layers can be just as impactful. Scheduled jobs are a prime example: when a downstream job runs on a fixed schedule, newly available data may sit idle until the next execution window. Across several pipeline stages, these waiting periods add up quickly, turning minutes of scheduling latency into a meaningful threat to end-to-end SLA compliance.</p><p><strong>Optimisation 1: trigger Gold when Silver updates</strong></p><p>The direct answer to unpredictable inter-layer latency is eliminating the schedule entirely and replacing it with a <strong>table update trigger. </strong>This is a native Databricks feature that automatically launches a job shortly after a source table is updated, usually within a few seconds to one minute.</p><p>To set it up, open your Databricks job’s trigger settings, select “Table update” as the trigger type, and choose the table you want to observe.</p><p>In our pipeline, the Gold job in the transformation workspace used a table update trigger watching the Silver table in the ingest workspace. Once the Silver job completed and committed its changes, the Gold job fired automatically. That removed wasted schedule wait time and reduced cross-workspace handoff latency from minutes to seconds.</p><p>For a full reference on configuring table update triggers, see the <a href="https://docs.databricks.com/aws/en/jobs/trigger-table-update">Databricks documentation</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*UKRAV5aYomAcmaaomzYryw.png" /></figure><p><strong>Optimisation 2: use cluster pools to reduce startup time</strong></p><p>One hidden cost of trigger-based execution is <strong>cluster startup time.</strong> If each run starts a fresh cluster, several minutes can be lost before any data is processed, reducing the time left within the SLA.</p><p>Cluster pools solve this by maintaining a set of pre-warmed instances ready to be claimed immediately when a job fires. The cost model is worth understanding: DBU charges are pay-per-use, only accumulating when a job is actively running, while Azure VM costs apply even when instances are idle. You are essentially trading a continuous but predictable VM cost for the elimination of startup latency.</p><p>We configured pools on both the ingest and transformation workspaces, ensuring every job across the pipeline claimed a pre-warmed instance rather than spinning up from scratch. Without pools, cluster startup alone took at least 5 minutes; with pools, that dropped to a couple of minutes. On a pipeline with a 60-minute SLA, that difference mattered.</p><h4>Putting it all together</h4><p>Every optimisation in this article targets a specific slice of the 60-minute SLA budget. No single optimisation was sufficient on its own. Instead, the SLA was achieved by eliminating waste at every layer and compounding small gains into a pipeline that consistently met its deadline.</p><p>Here’s a consolidated view:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ne2qiskXrLjzYy23j-ViXg.png" /></figure><p>One pattern stands out immediately: the majority of high-impact optimisations are also low effort to implement. Adding liquid clustering, configuring a table update trigger, and setting up cluster pools — none of these require significant engineering investment. They are configuration and design decisions more than they are development projects. A few others, like useManagedFileEvents and CDF, need a bit more setup but are still well worth the investment given their impact.</p><p><strong>What moved the needle most</strong>: the combination of Auto Loader file events, liquid clustering on Silver, CDF on Gold, table update triggers, and cluster pools. Each of these targeted a distinct and significant source of latency in the pipeline. Everything else was incremental improvement on top of a foundation that already worked.</p><h4>Conclusion</h4><p>A 60-minute SLA on a TB-scale pipeline may look like a performance problem, but in practice it is an architecture problem. The biggest wins did not come from low-level Spark tuning. They came from decisions about how layers interact, what data is allowed to flow forward, and when jobs should run.</p><p>Although the specific stack here is Databricks, Delta Lake, and Azure, the thinking applies broadly. If you’re operating any high-volume, latency-sensitive pipeline, the questions are the same: is time being wasted in file discovery? Are you processing more data than necessary? Are scheduled jobs introducing idle wait that an event-based trigger could eliminate?</p><p>The SLA was a hard constraint, but it was also the best forcing function we had for building a pipeline that was fast, correct, and easy to operate at scale. Constraints, it turns out, can be useful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=777164a4ced2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/valcon-consulting/processing-high-volume-event-data-within-a-60-minute-sla-on-databricks-777164a4ced2">Processing high-volume event data within a 60-minute SLA on Databricks</a> was originally published in <a href="https://medium.com/valcon-consulting">Valcon</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>