<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Richard Li</title>
    <description>The latest articles on DEV Community by Richard Li (@richarddli).</description>
    <link>https://dev.to/richarddli</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F31455%2F37e66a45-999e-4c18-a09f-941c482a828f.jpeg</url>
      <title>DEV Community: Richard Li</title>
      <link>https://dev.to/richarddli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/richarddli"/>
    <language>en</language>
    <item>
      <title>Bullish on AI infrastructure, bearish on AI developer frameworks</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Fri, 31 Jan 2025 13:30:07 +0000</pubDate>
      <link>https://dev.to/richarddli/bullish-on-ai-infrastructure-bearish-on-ai-developer-frameworks-571p</link>
      <guid>https://dev.to/richarddli/bullish-on-ai-infrastructure-bearish-on-ai-developer-frameworks-571p</guid>
      <description>&lt;p&gt;When I said “&lt;a href="https://dev.to/blog/lessons-from-ai#dont-buy-the-ai-library-hype"&gt;don’t buy the AI library hype&lt;/a&gt;”, one of the more common responses was “Did you try $NEW_AI_FRAMEWORK instead?”&lt;/p&gt;

&lt;p&gt;After thinking about these comments, I realized that my framing of the developer AI framework space as a maturity issue is not quite correct. I see a &lt;em&gt;structural&lt;/em&gt; deficiency in this market, and I believe that many (most?) developer AI frameworks suffer from this gap.&lt;/p&gt;

&lt;p&gt;Let me explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  An AI Application (should be) an event-driven asynchronous application
&lt;/h2&gt;

&lt;p&gt;As context, I believe most AI applications should adopt an event-driven, asynchronous architecture. This is because most AI operations (e.g., calculating an embedding, or calling an LLM) have high latency. In a synchronous architecture, a call to the LLM can occupy a thread for tens of seconds (or longer!) while it waits for a response.&lt;/p&gt;

&lt;p&gt;In an asynchronous architecture, the application sends a remote procedure call (RPC) to the LLM and moves on to other tasks while waiting for the response. This non-blocking approach ensures that threads are not tied up, allowing the application to handle other requests or workflows simultaneously. Once the LLM responds, an event listener or callback mechanism processes the response, reintegrating it into the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core value of AI developer frameworks: syntactic sugar and standardization
&lt;/h2&gt;

&lt;p&gt;AI developer frameworks such as &lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;, &lt;a href="https://www.llamaindex.ai/" rel="noopener noreferrer"&gt;LlamaIndex&lt;/a&gt;, &lt;a href="https://mirascope.com/" rel="noopener noreferrer"&gt;Mirascope&lt;/a&gt; generally make it easier to create these RPCs, which can get complicated. For example, a typical RPC could include all of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A "system" prompt, which sets the overall context for the AI interaction&lt;/li&gt;
&lt;li&gt;A “user” prompt, which contains the actual question at hand&lt;/li&gt;
&lt;li&gt;Historical context, which includes any relevant conversational history&lt;/li&gt;
&lt;li&gt;Question context, which includes any data that might be relevant to the prompt itself (e.g., a PDF document)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But while assembling all of these details can be complicated and time consuming for a developer, the workflow is fairly straightforward (in most cases, you’re populating a JSON object to send with your RPC). The reality is that these developer frameworks codify common design patterns by providing thin wrappers around a bunch of other lower-level libraries.&lt;/p&gt;

&lt;p&gt;Thus, the core value of these libraries is not “developer productivity”. The core value of these libraries is &lt;em&gt;standardization&lt;/em&gt; (&lt;a href="https://x.com/eyfriis" rel="noopener noreferrer"&gt;H/T Erick Friis&lt;/a&gt;) through &lt;a href="https://en.wikipedia.org/wiki/Syntactic_sugar" rel="noopener noreferrer"&gt;syntactic sugar&lt;/a&gt;. For organizations with lots of developers, consistency is key to maintainability, and these libraries provide consistency. Outside of consistency, I don’t believe that these frameworks offer much value.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what AI frameworks and tools &lt;em&gt;do&lt;/em&gt; add value?
&lt;/h2&gt;

&lt;p&gt;While AI developer libraries are not valuable for most developers (standardization is an organizational benefit), I believe there are three categories of libraries &amp;amp; infrastructure that AI developers do use which will have enduring value: event-driven infrastructure, model training, and model inference. The software in these three categories are all non-trivial to implement, and comprise important parts of an AI application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-driven infrastructure
&lt;/h3&gt;

&lt;p&gt;Virtually all AI applications adopt an event-driven architecture, given the high latency in LLM response. Asynchronous I/O libraries, message queues, and other infrastructure software created for event-driven architectures are even more relevant today in the age of AI. &lt;/p&gt;

&lt;p&gt;As an entrepreneur, I believe premature scaling is a common mistake that startups make. Prior to building my own small-scale AI application, I would have put much of event-driven infrastructure into the “premature scaling” category. Then, I ran into some of these challenges at very small scale, and that has forced me to reconsider.&lt;/p&gt;

&lt;p&gt;I now believe that AI applications are forcing a reordering of technology priorities, and event-driven infrastructure will see a renaissance. The winners of this space will be the organizations that do the best job of creating a great developer experience for AI applications. &lt;/p&gt;

&lt;h3&gt;
  
  
  Model training
&lt;/h3&gt;

&lt;p&gt;Training pipelines are the backbone of any real-world AI application. Building these pipelines require significant engineering effort to create high quality, reproducible models. Training pipelines typically include steps for data processing, fine tuning, and evaluation. Fortunately, a robust ecosystem of libraries and tools are available to make it easier to build these pipelines. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data preprocessing and manipulation: Libraries like &lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;Pandas&lt;/a&gt; solve for the messy, real-world challenge of efficiently wrangling and cleaning large datasets. Without it, you'd be reinventing functionality for basic tasks like merging, filtering, or aggregating data.&lt;/li&gt;
&lt;li&gt;Fine-tuning models: Libraries like &lt;a href="https://huggingface.co/docs/transformers/en/index" rel="noopener noreferrer"&gt;HuggingFace Transformers&lt;/a&gt;  offer pre-built functionality for adapting large language models to your domain. Implementing this on your own would require deep familiarity with tokenization, optimizer setups, and memory management.&lt;/li&gt;
&lt;li&gt;Experiment tracking and reproducibility: Tools like &lt;a href="https://wandb.ai" rel="noopener noreferrer"&gt;Weights &amp;amp; Biases&lt;/a&gt; solve the hard problem of managing hundreds of experiments with varying hyperparameters, dataset splits, and evaluation results. This is critical for teams working collaboratively on model improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Model inference
&lt;/h3&gt;

&lt;p&gt;Serving a model in production is deceptively complex. While running a single inference locally might seem trivial, scaling that process to handle latency requirements, cost constraints, and diverse use cases exposes deep infrastructure needs. Some example tools for model inference include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inference engines: Tools like &lt;a href="https://docs.vllm.ai/en/latest/" rel="noopener noreferrer"&gt;vLLM&lt;/a&gt; address the core problem of high-latency inference by optimizing token streaming and GPU utilization. These aren't just "nice-to-haves"—without them, response times can make your application unusable.&lt;/li&gt;
&lt;li&gt;KV caching: Specialized caches for LLMs such as &lt;a href="https://lmcache.ai/" rel="noopener noreferrer"&gt;LMcache&lt;/a&gt; can dramatically reduce LLM latency and improve scalability.&lt;/li&gt;
&lt;li&gt;Structured output generation: Generating reliable structured data isn't trivial. Libraries like &lt;a href="https://dottxt-ai.github.io/outlines/welcome/" rel="noopener noreferrer"&gt;Outlines&lt;/a&gt; address this by wrapping generation with schema validation, saving significant development time and reducing downstream errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(There's a shift that is also taking place where allocating 💰 to inference vs training provides a better bang-for-the-buck on accuracy which needs to be explored, but that's yet another post.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The evolving AI ecosystem
&lt;/h2&gt;

&lt;p&gt;While I’m optimistic about the AI ecosystem as a whole, I’m pessimistic about the future of AI developer libraries in this ecosystem. The LangChain team is also moving beyond their core library, with the introduction of &lt;a href="https://docs.smith.langchain.com/" rel="noopener noreferrer"&gt;LangSmith&lt;/a&gt; (AI observability) and &lt;a href="https://langchain-ai.github.io/langgraph/" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt; (durable workflow). The tools that will thrive will be the ones that solve hard problems, made accessible through a great developer experience. We’re still in the early innings, with lots more to come!&lt;/p&gt;

&lt;p&gt;(Thanks to &lt;a href="https://x.com/williambakst" rel="noopener noreferrer"&gt;William Bakst&lt;/a&gt; and &lt;a href="https://x.com/eyfriis" rel="noopener noreferrer"&gt;Erick Friis&lt;/a&gt; for feedback.) &lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Data-driven customer acquisition: Machine Learning applied to Customer Lifetime Value</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Wed, 03 Apr 2024 15:45:51 +0000</pubDate>
      <link>https://dev.to/richarddli/data-driven-customer-acquisition-machine-learning-applied-to-customer-lifetime-value-2p7i</link>
      <guid>https://dev.to/richarddli/data-driven-customer-acquisition-machine-learning-applied-to-customer-lifetime-value-2p7i</guid>
      <description>&lt;p&gt;In today's data-centric world, insights from customer data can identify new opportunities to drive growth. Instead of staring endlessly at dashboards (and driving data analysts crazy with requests), we'll explore using regression analysis on your data to calculate lifetime value (LTV). We'll then analyze this model to find new ideas to try to drive LTV.&lt;/p&gt;

&lt;p&gt;LTV, also called customer lifetime value (CLTV), is a pivotal metric that quantifies the total revenue a business can expect from a single customer over their entire relationship. Understanding your LTV is crucial to analyzing your overall go-to-market performance, so that's where we'll start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional strategy
&lt;/h2&gt;

&lt;p&gt;Calculating LTV traditionally involves a "top-down" approach, where the average revenue per customer and the average lifespan of a customer are calculated to derive the LTV. This method provides a broad overview of the potential value of a customer to the business over their lifetime. However, the high-level nature of this calculation doesn’t give any indication of what actually drives LTV (and thus, how you can affect it).&lt;/p&gt;

&lt;p&gt;For instance, different customer acquisition strategies can attract different customer segments, which lead to differences in LTV. And, different strategies have different acquisition costs. Typically, segmentation is then used to answer this question. You can segment based on demographics, geography, company size, and other relevant factors and then calculate the corresponding payback periods.&lt;/p&gt;

&lt;p&gt;Segmentation helps in understanding the nuances of LTV among different customer groups, allowing for more targeted and effective acquisition strategies. However, traditional segmentation may not always capture the full complexity of customer behavior and preferences.&lt;/p&gt;

&lt;p&gt;This raises the question: what if you want to delve deeper and explore segments beyond the traditional categories? We’re going to next explore a long-standing mathematical tool that can help us identify new opportunities: regression analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regression analysis and machine learning
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.toblog/time-series-vs-regression"&gt;Regression analysis&lt;/a&gt; is a statistical method used to understand the relationship between a dependent variable and one or more independent variables. Traditionally, regression analysis is employed to predict values of the dependent variable based on the values of the independent variables. However, in the context of LTV analysis, we can focus on building a directionally accurate model that can help identify the customer characteristics and behaviors that contribute to higher value for the business.&lt;/p&gt;

&lt;p&gt;Moreover, we can use machine learning to enhance regression analysis. Machine learning allows for more complex and nuanced modeling of the relationship between variables. Instead of fitting a simple linear model, machine learning algorithms can capture non-linear relationships and interactions among variables, providing a more accurate representation of the data. In LTV analysis, machine learning can be used to build regression models that not only predict LTV but also identify the key factors driving LTV for different customer segments. &lt;/p&gt;

&lt;h2&gt;
  
  
  Shape of Data
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.kaggle.com/datasets/shibumohapatra/customer-life-time-value" rel="noopener noreferrer"&gt;VahanBima insurance dataset&lt;/a&gt; consists of thousands of individual insurance customers and their customer lifetime value. The data set also includes some demographic information (e.g., area, gender, education, income) and behavioral information (e.g., number of policies, past claims).&lt;/p&gt;

&lt;h2&gt;
  
  
  Training a model
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Encoding
&lt;/h3&gt;

&lt;p&gt;Regression analysis can only be performed on actual numerical values, so non-numerical values need to be encoded into numerical values. In this particular situation, we will use n-hot encoding for all the categorical values. In n-hot encoding, we convert each unique value in a row into a column. For example, the “qualification” column can be “High School”, “Bachelor”, or “Other”. We convert this single column to three columns: “High_School”, “Bachelor”, and “Other”, with true/false values in each column.&lt;/p&gt;

&lt;h3&gt;
  
  
  Training
&lt;/h3&gt;

&lt;p&gt;To illustrate the core concepts of ML and regression analysis, we’ll start with a simple model. &lt;a href="https://chat.openai.com" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; (the free version) creates something that works with this prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Load a df with a CSV file of data. The df has a target of "cltv", an index of "id", and feature variables "gender", "area", "qualification", "income", "marital_status", "vintage", "claim_amount", "num_policies", "policy", and "type_of_policy", n-hot encode the type_of_policy, income, qualification columns. Convert the gender, area, and num_policies column to boolean by mapping one value to 0 and the second value to 1. Gender is Male/Female, area is Urban/Rural, and Num_policies is "more than 1" or 1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ChatGPT gives the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="c1"&gt;# Load the data
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;train_BRCpofr.csv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# N-hot encode the 'type_of_policy', 'income', 'policy' and 'qualification' columns
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_dummies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type_of_policy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;income&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;policy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;qualification&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Map 'gender', 'area', and 'num_policies' columns to boolean
&lt;/span&gt;&lt;span class="n"&gt;gender_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Male&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Female&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;area_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Urban&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Rural&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;num_policies_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;more than 1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gender_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num_policies&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num_policies&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_policies_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the above into a Jupyter notebook and run it. You can then ask ChatGPT to use a gradient-boosted decision tree to analyze this dataframe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.pipeline&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;make_pipeline&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.impute&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleImputer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.ensemble&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GradientBoostingRegressor&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mean_squared_error&lt;/span&gt;

&lt;span class="c1"&gt;# Assuming X_train, X_test, y_train, y_test are your training and test sets
&lt;/span&gt;
&lt;span class="c1"&gt;# Create a pipeline with an imputer and the GradientBoostingRegressor
&lt;/span&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;SimpleImputer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# You can change the strategy as needed
&lt;/span&gt;    &lt;span class="nc"&gt;GradientBoostingRegressor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fit the pipeline on the training data
&lt;/span&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Predict on the test data
&lt;/span&gt;&lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Calculate the mean squared error
&lt;/span&gt;&lt;span class="n"&gt;mse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean_squared_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mean Squared Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mse&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interpreting the model
&lt;/h2&gt;

&lt;p&gt;The first thing to look at is how well our model fits the data.  This is typically measured using metrics like &lt;a href="https://en.wikipedia.org/wiki/Root-mean-square_deviation" rel="noopener noreferrer"&gt;Root Mean Squared Error (RMSE)&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Mean_absolute_percentage_error" rel="noopener noreferrer"&gt;Mean Absolute Percentage Error (MAPE)&lt;/a&gt;. If the model doesn't fit the data well, you may need to revisit your model and data preprocessing steps. The RMSE on this data set is 87,478 with a MAPE of 71.4%. The average LTV in the data set is $97,953. This suggests that the model’s prediction have a large spread with a significant error percentage. &lt;/p&gt;

&lt;p&gt;Most data scientists would say the model isn’t useful at this point, as its predictive power is poor. And it is! You don’t want to use this model to predict the actual LTV of a customer based on these variables. But our goal was not to build highly accurate models for prediction. Our goal was to identify customer characteristics and behaviors that are high value to the business. So let’s explore this a little bit more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature importance
&lt;/h3&gt;

&lt;p&gt;We want to understand the relative importance of each of these independent variables on the output. Machine learning models typically have ways to compute “feature importance”, which is the relative importance of each independent variable to the final prediction’s &lt;em&gt;accuracy&lt;/em&gt;. In other words, features (independent variables) with high importance contribute more to the accuracy of the prediction (and the prediction isn’t really all that accurate right now).&lt;/p&gt;

&lt;p&gt;But what we really care about is not which features contribute to the accuracy -- we care about which features actually impact the output. And so traditional feature importance can easily lead us astray. Instead, we will turn to Shapley values.&lt;/p&gt;

&lt;p&gt;By leveraging concepts from cooperative game theory, &lt;a href="https://christophm.github.io/interpretable-ml-book/shapley.html" rel="noopener noreferrer"&gt;Shapley values&lt;/a&gt; provide a more nuanced understanding of feature importance than traditional methods. They quantify the marginal contribution of each feature to the prediction by considering all possible combinations of features and their impact on the model's output. This approach captures interactions between features and ensures that each feature is credited proportionally to its true contribution, even in complex models where features may interact in non-linear ways. By doing so, Shapley values offer deeper insights into the factors driving the model's decisions, making them a powerful tool for interpreting machine learning models.&lt;/p&gt;

&lt;p&gt;Computing Shapley values is computationally intensive and can take hours. We’ll use the &lt;a href="https://shap.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Python SHAP library&lt;/a&gt; with some sampling to compute the following feature importance chart:&lt;/p&gt;

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

&lt;p&gt;This tells us the major factors that are driving this particular computation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What-If Analysis
&lt;/h3&gt;

&lt;p&gt;We now know the number of policies is the biggest factor, followed by claim amount, followed by area. So, how exactly does the number of policies affect the average LTV?&lt;/p&gt;

&lt;p&gt;We can use our predictive model to answer this question. We take our original input data, and change the average number of policies up and down in 10% intervals. This lets us create a what-if chart like below, which shows the relative impact of changing the number of policies, area, and claim amounts.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;As the average number of policies increases, the average LTV &lt;em&gt;decreases&lt;/em&gt;, as shown by the purple line. A 50% increase in policies causes a 10.7% decrease in average LTV.&lt;/li&gt;
&lt;li&gt;Claim amounts are represented by the teal line. As claim amounts increase, the average LTV modestly increases.  A 50% increase in claim amount causes a 1% decrease in average LTV.&lt;/li&gt;
&lt;li&gt;Area is shown by the red line. Urban customers are slightly more valuable than rural customers. As the mix shifts towards urban by 50%, a 1.1% increase in average LTV is noted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;p&gt;Traditional models for LTV have historically focused on segmentation and aligning customer acquisition channels to specific segments. While effective, this approach often relies on predefined assumptions and can limit the scope of analysis. In contrast, regression analysis offers a powerful tool for at-scale data exploration, allowing for the analysis of possibilities that may not have been considered initially. Dashboards excel in the traditional model as they align with predefined questions, but regression analysis, especially when augmented with machine learning, can reveal insights that go beyond the scope of predefined queries. By embracing machine learning to enhance regression analysis, businesses can uncover new levers for customer acquisition and optimize their strategies for long-term success in a data-driven landscape.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>dataengineering</category>
      <category>machinelearning</category>
      <category>saasmetrics</category>
    </item>
    <item>
      <title>When Metrics Go Awry: Analyzing KPIs using machine learning, regression analysis, and Shapley values</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Fri, 08 Mar 2024 13:25:21 +0000</pubDate>
      <link>https://dev.to/richarddli/when-metrics-go-awry-analyzing-kpis-using-machine-learning-regression-analysis-and-shapley-values-3kgo</link>
      <guid>https://dev.to/richarddli/when-metrics-go-awry-analyzing-kpis-using-machine-learning-regression-analysis-and-shapley-values-3kgo</guid>
      <description>&lt;p&gt;Every week, management teams at companies around the world gather to review the weekly dashboard. Inevitably, one of these key metrics … is red. How do we turn it from red to green?&lt;/p&gt;

&lt;p&gt;There are two typical reactions to a metrics incident:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wait another week to see if it’s a trend.&lt;/li&gt;
&lt;li&gt;Schedule a meeting to investigate this metric.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither of these approaches are particularly satisfying. The flaw of the first is that if the problem is a trend, you’ve just lost a week of time to address the issue. The flaw of the second is that traditional analysis techniques don’t tell you why, and frequently lead into a round of expensive and inconclusive data analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Segmentation: Traditional analysis
&lt;/h2&gt;

&lt;p&gt;The management team elects to go with Option 2. What happens in that meeting?&lt;/p&gt;

&lt;p&gt;The traditional tool used is segmentation. Typically, the KPI is decomposed into different segments: geography, customer size, gender, and so forth to see if there is a common segment that is underperforming.&lt;/p&gt;

&lt;p&gt;The data team works steadily for the next day writing SQL queries to produce a set of dashboards that show the metric in question by segment. They figure it’s worth codifying these segments the next time something happens.&lt;/p&gt;

&lt;p&gt;The dashboards show that the metric has gone down for most segments, but it’s most pronounced in N. America. Now what?&lt;/p&gt;

&lt;p&gt;The team has run into the core problem with segmentation: segmentation only identifies what segment(s) are affected by the KPI change. Segmentation does not provide any insight into what might be driving the change. Conversations with marketing &amp;amp; product ensue to ask if they’ve changed anything in the past week that might affect most customers, but particularly N. America customers. This is inconclusive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regression analysis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.amorphousdata.com/blog/time-series-vs-regression" rel="noopener noreferrer"&gt;Regression analysis&lt;/a&gt; is a statistical method used to model the relationship between a dependent variable (in this case, the KPI) and one or more independent variables). The goal of regression analysis is to understand how the independent variables impact the dependent variable.&lt;/p&gt;

&lt;p&gt;The earliest forms of regression analysis were published in 1805 (!). Since then, research in regression analysis has resulted in sophisticated algorithms that can find patterns in noisy and non-linear data. The most recent of these algorithms fall into the “machine learning” category, and take advantage of the awesome computational power of modern CPUs &amp;amp; GPUs. We’ll see how these algorithms can be used to analyze a KPI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insurance and LTV
&lt;/h2&gt;

&lt;p&gt;We’ll start with the VahanBima customer lifetime value dataset. We previously used this data set to &lt;a href="https://www.amorphousdata.com/shape/lifetime-value" rel="noopener noreferrer"&gt;build a regression model for LTV&lt;/a&gt;. This data set has approximately 90,000 insurance customers and their lifetime value. To simulate a drop in LTV, we’ll add another 10,000 synthetic customers based on this dataset. If you want to try this yourself, you can download the &lt;a href="https://www.kaggle.com/datasets/rad1al/insurance-cltv-dataset-with-a-decreasing-ltv/data" rel="noopener noreferrer"&gt;updated dataset here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let’s take a look at the LTV of this dataset. We can graph the trend line of LTV using a simple moving average, and show it here:&lt;/p&gt;

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

&lt;p&gt;Why is LTV down? This data set has multiple independent variables: number of policies, claim amount, area, marital status, and so forth. We'll now explore which of these variables, if any, could be causing this drop in LTV.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://www.amorphousdata.com/shape/lifetime-value" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;, we trained a regression model on the same dataset to find ways to increase LTV, so we won’t re-train a model here. Instead, we’ll start where we left off, which was with the feature importance chart.&lt;/p&gt;

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

&lt;p&gt;Let’s look at each independent variable, in descending order of feature importance, to see if we can identify what might be driving LTV down. For each variable, we’ll look at three factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The feature importance, which we have previously computed using Shapley values.&lt;/li&gt;
&lt;li&gt;The trend line, which we can compute using a simple moving average (SMA).&lt;/li&gt;
&lt;li&gt;The expected impact of the variable on LTV as the variable increases &amp;amp; decreases, which we can visualize using Shapley values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The variable with the highest feature importance in this data set is number of policies. Here’s the trend line:&lt;/p&gt;

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

&lt;p&gt;There is no discernible pattern in this trend line, so we can dismiss a change in the number of policies issued as the driver of the CLTV.&lt;/p&gt;

&lt;p&gt;Let’s look at the next variable, claim amount. Here’s the trend line:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwhkkiopw2mnnj1t5pv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwhkkiopw2mnnj1t5pv8.png" alt="Claim Amount Trend" width="542" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s an obvious drop in the claim amount for more recent customers. We didn't need any fancy regression analysis or machine learning to identify this trend. But our model lets us go one step further, because a drop in an independent variable does not necessarily correspond to a drop in the target variable. We can look at the Shapley chart for claim amount to understand this further:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9btfehn4eggjfmulrj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9btfehn4eggjfmulrj2.png" alt="Claim Amount Shapley" width="531" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Shapley scatter charts&lt;/strong&gt; are a powerful tool that gives a sense of how changes in the independent variable impact the predicted value. In this chart, each dot represents a single prediction from the data set. The x-axis is the specific value of the independent variable, while the y-axis is the change in the target for a given x-axis value.&lt;/p&gt;

&lt;p&gt;Shapley scatter charts also help identify situations where independent variables are not completely independent. When the predicted values on the y-axis have a wide dispersion for the same x-axis value, that suggests that there are other factors in play besides the independent variable in play. Similarly, if there is a narrow dispersion, this suggests the independent variable is driving the given prediction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Shapley scatter chart for claim amount is suggestive. As the claim amounts increase, so does the LTV (presumably via increased premiums). There is relatively narrow dispersion in the chart, which suggests that claim amount is fairly independent.&lt;/p&gt;

&lt;p&gt;We now have a hypothesis! We can quickly scan the trend lines in the other independent variables, and our eye quickly settles in on the spike in vintage:&lt;/p&gt;

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

&lt;p&gt;Vintage is the number of years a customer has been a customer. We look at the Shapley chart:&lt;/p&gt;

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

&lt;p&gt;Here, we see wide vertical dispersion for each vintage, and no clear changes in value. This suggests that there are high &amp;amp; low LTV customers at every vintage, and as such, the increase in vintage is unlikely to be causing any impact on LTV. We thus conclude that the recent drop in LTV is driven by a drop in claim amounts by customers. (This also suggests that LTV may not be the ideal metric for measuring insurance customers, as the increase in LTV associated with claim activity does not necessarily mean an increase in &lt;em&gt;profitability&lt;/em&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Segmentation &amp;amp; dashboards are insufficient
&lt;/h2&gt;

&lt;p&gt;When key performance indicators go down, traditional approaches like segmentation can only go so far in pinpointing the root cause. While segmentation identifies which segments are affected, it often falls short in providing actionable insights into why the change occurred.&lt;/p&gt;

&lt;p&gt;More generally, dashboards are poor tools for identifying relationships in data. Modern regression analysis can help bridge this gap between problem and action. By modeling the relationship between the KPI and various independent variables, regression analysis can uncover hidden patterns and factors driving the KPI change.&lt;/p&gt;

&lt;p&gt;The answer could be in your data. If it’s there, regression analysis will help you find it.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>saasmetrics</category>
      <category>datascience</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Six months with GitHub Copilot</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Mon, 05 Feb 2024 14:34:33 +0000</pubDate>
      <link>https://dev.to/richarddli/six-months-with-github-copilot-286e</link>
      <guid>https://dev.to/richarddli/six-months-with-github-copilot-286e</guid>
      <description>&lt;p&gt;I’ve been coding with GitHub Copilot over the past six months, and I’ve steadily seen it improve my productivity. Because the Copilot UX is seamlessly integrated into my IDE, I didn't think initially there was much to using Copilot. But after six months of steady usage, I've found that my way of using Copilot has evolved and improved over time.&lt;/p&gt;

&lt;p&gt;TL;DR: Copilot really improves productivity -- especially if you invest in adapting your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I’m a 2x founder, and with my current startup, I’m doing all the programming. As such, I have to be a generalist programmer. On any given day, I could be working on the web UI, some backend business logic, machine learning, or writing documentation.&lt;/p&gt;

&lt;p&gt;I’m building a &lt;a href="https://www.amorphousdata.com" rel="noopener noreferrer"&gt;cloud application&lt;/a&gt; that builds predictive models from large data sets. I’ve worked to make the stack as boring as possible, but there's a lot of different technologies that need to be used.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python. The ecosystem of data and machine learning frameworks built on Python made this an obvious choice.&lt;/li&gt;
&lt;li&gt;Flask. Simple, minimalist web framework.&lt;/li&gt;
&lt;li&gt;SQL. State needs to be stored in a relational database.&lt;/li&gt;
&lt;li&gt;Pandas. While Polars and DuckDB get a lot of attention, the reality is that most research and documentation start with Pandas.&lt;/li&gt;
&lt;li&gt;HTML &amp;amp; CSS. Hard to avoid these two if you have a web application.&lt;/li&gt;
&lt;li&gt;Bootstrap. I have minimal front end skills, so I picked Bootstrap because it has professional-looking components that are easy for me to use.&lt;/li&gt;
&lt;li&gt;JavaScript. I use small amounts of JavaScript to improve the UX. In particular, ML jobs can take tens of minutes or longer to run, so having a UI that can poll and update status is helpful.&lt;/li&gt;
&lt;li&gt;PyTorch and numerous ML libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, my “simple” application uses five languages (Python, SQL, JavaScript, HTML, CSS) and four major frameworks (Pandas, Bootstrap, PyTorch, Flask) that I interact with on a daily basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  My workflow
&lt;/h2&gt;

&lt;p&gt;I’m using VSCode with the Copilot plug-in. Initially, when I tried Copilot, I used it as a smarter auto-complete. I would write code, and Copilot would sometimes suggest code. I would read the code suggestion and if it made sense, I would accept it. This was super helpful for writing tedious boilerplate code, for example:&lt;/p&gt;

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

&lt;p&gt;While I appreciated the reduction in tedium, this felt like an incremental improvement in productivity. Then, I discovered the Copilot chat. Over time, I've found that using this has created a step function increase in productivity.&lt;/p&gt;

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

&lt;p&gt;After experimentation, my workflow today is something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Figure out requirements. For example, a number of users asked for native support for downloading data directly from BigQuery.&lt;/li&gt;
&lt;li&gt;Design the solution. Draw a UI mockup on my whiteboard, look at the code, and figure out how I want to add this functionality to the code in a maintainable way. If I know that the problem I’m trying to tackle is something others have run into, I ask Copilot. This is a fairly iterative approach where I might write out some pseudo-code that helps me formulate my thoughts.&lt;/li&gt;
&lt;li&gt;Implementation. This is where the Copilot chat is really great. I now know that I need to create a function call that does X. I go to the relevant bit of code, and type into the chat “create a function that does X”. And Copilot cranks out a function that does X!&lt;/li&gt;
&lt;li&gt;Review &amp;amp; test. I read the code to make sure I understand it, adding comments and fixes as I go along.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ve found that the real value of Copilot is not the auto-complete any more. Instead, its Copilot's ability to prototype entire functions based on my design that is a time saver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot represents conventional wisdom
&lt;/h2&gt;

&lt;p&gt;For me, Copilot represents the conventional wisdom of how to tackle a specific programming problem. If I'm tackling a programming problem and I have a sense that someone must have run into this problem before, I turn to Copilot.&lt;/p&gt;

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

&lt;p&gt;Before Copilot, I relied on Google to give me the conventional wisdom. Today, many of the top results on Google are commercial websites that are optimized for ranking and not user experience.   Copilot gives me contextual results without the spam!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Copilot chat
&lt;/h2&gt;

&lt;p&gt;The most important thing to realize with Copilot chat is that it takes two inputs: your code and whatever you type into the chat box. &lt;strong&gt;Make sure your cursor is in a relevant part of the code before you ask your question.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's an example where Copilot shines. The stack trace tells me where the error occurs, so I open the file and place my cursor on the line. I then paste in the error message. This is what Copilot tells me:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;While Copilot does represent conventional wisdom, you don't always want to follow conventional wisdom. In my personal experience, Copilot is heavily biased to using SQLAlchemy in Python (which I don't really use), and JQuery for all UI styling (even though I use Bootstrap). The other limitation I've encountered is that I can only supply one piece of context with my question, which is the code at hand. In reality, a web application has three pieces of context: the database schema, the HTML template, and the actual business logic. I'm sure this is something that will be addressed in the future, though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Copilot for programming
&lt;/h2&gt;

&lt;p&gt;Here's what I would tell my six-month-ago self about programming with Copilot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Think of Copilot as conventional wisdom, and use it in these situations.&lt;/li&gt;
&lt;li&gt;Use the chat and place your cursor on the code you want it to comment on.&lt;/li&gt;
&lt;li&gt;Once you design a feature, write it out in pseudo-code, and then prompt Copilot to flesh out the implementation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've found that Copilot gives me more time to spend on requirements &amp;amp; design, which is where I should be spending my time.&lt;/p&gt;

&lt;p&gt;One thing that hasn't changed for me is the feeling of satisfaction when the code works. Whether I write it or Copilot or not, I get the same feeling of accomplishment.&lt;/p&gt;

&lt;p&gt;Recommended.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://www.thelis.org/blog/github-copilot" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>programming</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Using data for predictive analytics</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Fri, 12 Jan 2024 15:13:03 +0000</pubDate>
      <link>https://dev.to/richarddli/using-data-for-predictive-analytics-49o9</link>
      <guid>https://dev.to/richarddli/using-data-for-predictive-analytics-49o9</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.getambassador.io" rel="noopener noreferrer"&gt;Ambassador&lt;/a&gt;, the weekly/monthly/quarterly metrics review was a core part of the operating cadence of the company. We'd meet and review metrics that spanned the business: usage, customer satisfaction, revenue, pipeline. When a metric was not tracking to plan, we'd task a team to investigate and recommend actions to get back on track.&lt;/p&gt;

&lt;p&gt;Yet, as the business grew in complexity, these teams got slower, as they were trying to reconcile data from different systems: Salesforce, HubSpot, Google Analytics, product data. Luckily, I was introduced to the world of modern data engineering, which promised a better approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern data infrastructure, Extract-Load-Transform, and cloud data warehouses
&lt;/h2&gt;

&lt;p&gt;Over the past decade, two macro trends have powered innovation in the modern data ecosystem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unlimited demand for data. Modern applications such as machine learning and business intelligence are fueled by data -- the more, the better.&lt;/li&gt;
&lt;li&gt;Plummeting cost of storage and compute, particularly in the cloud. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These trends have given rise to the "Extract-Load-Transform" (ELT) &lt;a href="https://a16z.com/emerging-architectures-for-modern-data-infrastructure/" rel="noopener noreferrer"&gt;architecture&lt;/a&gt;, which is an evolution from the traditional "Extract-Transform-Load" approach. In an ELT architecture, data is stored in its original format, and then transformed as needed, instead of being transformed prior to load. An ELT architecture is much more flexible to adapt to future (unanticipated) needs, as no information is ever thrown away. The tradeoff with ELT vs ETL is more storage costs -- but with cloud storage being cheap, this almost always is worthwhile. &lt;/p&gt;

&lt;h2&gt;
  
  
  Business intelligence is not a dashboard
&lt;/h2&gt;

&lt;p&gt;We adopted a modern data infrastructure solution: &lt;a href="https://cloud.google.com/bigquery" rel="noopener noreferrer"&gt;Google BigQuery&lt;/a&gt; (cloud data warehouse), &lt;a href="https://www.fivetran.com/" rel="noopener noreferrer"&gt;FiveTran&lt;/a&gt; (ELT), &lt;a href="https://www.metabase.com/" rel="noopener noreferrer"&gt;Metabase&lt;/a&gt; (Business Intelligence / Dashboard), &lt;a href="https://www.getdbt.com" rel="noopener noreferrer"&gt;DBT&lt;/a&gt; (modeling), &lt;a href="https://hightouch.com/" rel="noopener noreferrer"&gt;Hightouch&lt;/a&gt; (Reverse ELT). This worked great, as we were able to aggregate data from our CRM, marketing, product, support, and other systems in one place. And we started building dashboards, which illuminated parts of the business we had never seen before.&lt;/p&gt;

&lt;p&gt;But the success of the data warehouse created more demand for dashboards, and we had dashboards upon dashboards. Our small data analyst team couldn't keep up with the demand. We also struggled to keep all of our dashboards up-to-date, and track which dashboards were being used.&lt;/p&gt;

&lt;p&gt;Our business "intelligence" solution of dashboards was pretty dumb. That's when we realized that we were overusing dashboards as both a reporting tool and a communication and alignment tool. If we went back to first principles, the reality is that we wanted &lt;strong&gt;data to make better decisions&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models
&lt;/h2&gt;

&lt;p&gt;Around this time, I was introduced to a CFO who was looking for her next opportunity. We weren't actively looking for a CFO, but we really liked her, and I wanted to figure out if we could get her on board. And she said something that stuck with me: "What I like to do is figure out how to turn the business into a spreadsheet."&lt;/p&gt;

&lt;p&gt;And I realized: We didn't need more dashboards. We needed more models.&lt;/p&gt;

&lt;p&gt;What's a model? A model is a representation of a thing that is smaller in scale than the original. Models, being smaller in scale, are easier to manipulate. In the context of business, models are everywhere: financial models, funnels, and sales productivity models are common examples. Models are super-powerful because assumptions can be quickly tested. At a previous company, we had agreed on a top-line revenue goal for the year, but when we plugged that number into the sales productivity model, it showed how we would have to more than double rep productivity. Needless to say, we added more sales reps to the plan.&lt;/p&gt;

&lt;p&gt;We had a financial model, productivity model, and funnel model -- but what we started to do after that was to build even more granular models. Our first model was our signup to product-qualified lead model, which accounted for all the steps (and decisions) a user needed to make from signup all the way to activation all the way to lead. We then built a dashboard that tracked the different steps of this model, and, as our understanding of the model evolved, so did the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data teams and the evolution of business intelligence
&lt;/h2&gt;

&lt;p&gt;I've talked to dozens of data teams at B2B SAAS companies since then, and I've realized our journey was typical. The modern data journey looks something like this:&lt;/p&gt;

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

&lt;p&gt;Businesses usually start with a homegrown business metrics dashboard, which can be implemented in slides or spreadsheets. This dashboard is an aggregation of key metrics from each function. These metrics are pulled from each function's critical systems: sales will pull pipeline data from Salesforce, marketing will pull lead data from marketing automation, support from Zendesk, and so forth. And this strategy can work well for a long time.&lt;/p&gt;

&lt;p&gt;At some point, companies realize they need to do more cross-functional data analysis. It's not enough to know that marketing drove X signups, or product drove Y activations, or sales created Z opportunities. Organizations realize that all of these functions need to work together, and knowing where to find signups that are most likely to result in activations and opportunities requires the integration of different data systems. This drives Phase 2: the creation of a central data team, which drives the adoption of an ELT architecture and dashobards.&lt;/p&gt;

&lt;p&gt;Data is addictive: the more you have, the more you want. And this will lead to the data team being overwhelmed with requests to create more dashboards and analysis. The typical answer is "self-service dashboards" from a business intelligence vendor, where technologies such as Looker, or more recently, LLM-powered dashboards, have become popular. This leads to Phase 3: self-service dashboards for the rest-of-the-organization.&lt;/p&gt;

&lt;p&gt;Self-service dashboards have a problem: they make the easy problems easy, and they don't make hard problems any easier. What typically follows from self-service are an explosion of unmaintained dashboards (because creating them is easy) but there's still a huge bottleneck on analysis. The business functions inevitably hire their own data analysts: a marketing data analyst, product analyst. And this is because the real questions can't be answered in a chat session with an LLM. This leads to Phase 4: function-specific analysts.&lt;/p&gt;

&lt;p&gt;All these analysts querying the same data warehouse causes a different type of problem: multiple competing definitions of critical KPIs. Different teams use similar but different definitions of revenue. Marketing runs on a Sunday weekly start, while sales starts on Monday. All these different definitions start to create concerns around data integrity. The solution proposed is to standardize these definitions in a metrics layer (&lt;a href="https://medium.com/airbnb-engineering/how-airbnb-achieved-metric-consistency-at-scale-f23cc53dea70" rel="noopener noreferrer"&gt;AirBnb's version of this story&lt;/a&gt;). And thus, the organization is in Phase 5: implementing metrics.&lt;/p&gt;

&lt;p&gt;Yet with all this investment, the original concern of the business: using data to make better decisions, is taking longer than ever. Things go back to Phase 2 in an attempt to standardize access to the metrics layer, which will let everyone be more productive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ambassador, and a different way
&lt;/h2&gt;

&lt;p&gt;At Ambassador, we got to Phase 2. The data team was a bottleneck, but we weren't big enough to justify a big investment in self-service. We were forced to innovate, and that's when we started building models. Our data evolution ended up looking like this:&lt;/p&gt;

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

&lt;p&gt;Different functional teams who needed dashboards started by building models in spreadsheets and slides. They shared these models with the data teams, who helped them build dashboards that let them track the performance of these models.&lt;/p&gt;

&lt;p&gt;We found that models became powerful tools for aligning the data team, the functional teams, and the broader organization on the purpose of the dashboards. Beyond the alignment, we were able to test and question assumptions and use these models in planning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business intelligence is about communication
&lt;/h2&gt;

&lt;p&gt;Since then, I've come to view that models are a critical abstraction between analysis &amp;amp; dashboard tools and data itself.&lt;/p&gt;

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

&lt;p&gt;In the context of the data stack, these models are a distinct abstraction from the modeling done by tools such as DBT or LookML. These models represent how the business is operating, and capture the business processes themselves.&lt;/p&gt;

&lt;p&gt;More generally, I've come to see business intelligence is a &lt;em&gt;communication&lt;/em&gt; function. With BI, you're using data and visualizations and models to align the organization around the challenge at hand. Models are a crucial part of this communication function. In the process of building a model, you'll find holes in your data, and assumptions you're making -- and that's when you should go off and go validate those assumptions and fill in these holes. Most importantly, models create alignment between all the different functions in the organization, from data to engineering to go-to-market.&lt;/p&gt;

&lt;p&gt;This post was originally published &lt;a href="https://www.amorphousdata.com/blog/data-is-not-a-strategy" rel="noopener noreferrer"&gt;on the Amorphous Data blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>datascience</category>
      <category>data</category>
    </item>
    <item>
      <title>Developing Python Applications on Kubernetes</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Tue, 02 Mar 2021 21:29:59 +0000</pubDate>
      <link>https://dev.to/ambassadorlabs/developing-python-applications-on-kubernetes-5339</link>
      <guid>https://dev.to/ambassadorlabs/developing-python-applications-on-kubernetes-5339</guid>
      <description>&lt;p&gt;Kubernetes has become the de-facto standard for running cloud applications. With Kubernetes, users can deploy and scale containerized applications at any scale: from one service to thousands of services. The power of Kubernetes is not free — the learning curve is particularly steep, especially for application developers. Knowing what to do is just half the battle, then you have to choose the best tools to do the job. So how do Python developers create a development workflow on Kubernetes that is fast and effective?&lt;/p&gt;

&lt;p&gt;There are two unique challenges with creating productive development workflows on Kubernetes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Most development workflows are optimized for local development, and Kubernetes applications are designed to be native to the cloud.&lt;/li&gt;
&lt;li&gt;Most Kubernetes applications either start off or evolve into a microservices architecture. Thus, your development environment becomes more complex as every microservice adds additional dependencies to test code. And in turn, these &lt;a href="https://www.getambassador.io/resources/eliminate-local-resource-constraints/" rel="noopener noreferrer"&gt;services quickly become too resource-intensive&lt;/a&gt; and exceed the limits of your local machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this tutorial, we’ll walk through how to set up a realistic development environment for Kubernetes. Typically, we’d have to wait for a container build, push to registry and deploy to see the impact of our change. Instead, we’ll use Telepresence and see the results of our change instantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.getambassador.io/products/telepresence/" rel="noopener noreferrer"&gt;Telepresence&lt;/a&gt; is an open source project that lets you run your microservice locally, while creating a bi-directional network connection to your Kubernetes cluster. This approach enables the microservice running locally to communicate to other microservices running in the cluster, and vice versa. Since you’re running the microservice locally, you’re able to &lt;a href="https://www.getambassador.io/use-case/local-kubernetes-development/" rel="noopener noreferrer"&gt;benefit&lt;/a&gt; from any workflow or tool that you run locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Deploy a Sample Microservices Application
&lt;/h2&gt;

&lt;p&gt;For our example, we’ll make code changes to a Go service running between a resource-intensive Java service and a large datastore. We’ll start by deploying a sample microservice application consisting of 3 services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VeryLargeJavaService&lt;/code&gt; A memory-intensive service written in Java that generates the front-end graphics and web pages for our application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DataProcessingService&lt;/code&gt; A Python service that manages requests for information between the two services.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VeryLargeDataStore&lt;/code&gt; A large datastore service that contains the sample data for our Edgey Corp store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: We’ve called these VeryLarge services to emphasize the fact that your local environment may not have enough CPU and RAM, or you may just not want to pay for all that extra overhead for every developer.&lt;/p&gt;

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

&lt;p&gt;In this architecture diagram, you’ll notice that requests from users are routed through an ingress controller to our services. For simplicity’s sake, we’ll skip the step of &lt;a href="https://www.getambassador.io/docs/latest/topics/install/install-ambassador-oss/#kubernetes-yaml" rel="noopener noreferrer"&gt;deploying an ingress controller&lt;/a&gt; in this tutorial. If you’re ready to use Telepresence in your own setup and need a simple way to set up an ingress controller, we recommend checking out the &lt;a href="https://www.getambassador.io/products/edge-stack/" rel="noopener noreferrer"&gt;Ambassador Edge Stack&lt;/a&gt; which can be easily configured with the &lt;a href="https://app.getambassador.io/initializer" rel="noopener noreferrer"&gt;K8s Initializer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s deploy the sample application to your Kubernetes cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/datawire/edgey-corp-python/master/k8s-config/edgey-corp-web-app-no-mapping.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: This tutorial assumes you have access to a Kubernetes cluster with &lt;code&gt;kubectl&lt;/code&gt; access. If you don’t, some options include MicroK8S and Docker Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Set up your local Python development environment
&lt;/h2&gt;

&lt;p&gt;We’ll need a local development environment so that we can edit the &lt;code&gt;DataProcessingService&lt;/code&gt; service. As you can see in the architecture diagram above, the &lt;code&gt;DataProcessingService&lt;/code&gt; is dependent on both the &lt;code&gt;VeryLargeJavaService&lt;/code&gt; and the &lt;code&gt;VeryLargeDataStore&lt;/code&gt;, so in order to make a change to this service, we’ll have to interact with these other services as well. Let’s get started!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository for this application from GitHub:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/datawire/edgey-corp-python.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; Install the application dependencies with &lt;code&gt;pip&lt;/code&gt; (you may need to type &lt;code&gt;pip3&lt;/code&gt; if you have Python 3 installed):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd edgey-corp-python/DataProcessingService/
pip install flask requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the application (you may need to type &lt;code&gt;python3&lt;/code&gt; if you have Python 3 installed):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Test the application. In another terminal window, we’ll send a request to the service, which should return blue.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl localhost:3000/color
blue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Make Code Changes with Telepresence
&lt;/h2&gt;

&lt;p&gt;To test a code change with Kubernetes, you typically need to build a container image, push the image to a repository, and deploy the Kubernetes cluster. This takes minutes.&lt;/p&gt;

&lt;p&gt;Telepresence is an open source, Cloud-Native Computing Foundation project that solves exactly this problem. By creating a bidirectional network connection between your local development environment and the Kubernetes cluster, Telepresence enables fast, local development.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download Telepresence (~60MB):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Mac OS X
sudo curl -fL https://app.getambassador.io/download/tel2/darwin/amd64/latest/telepresence -o /usr/local/bin/telepresence
# Linux
sudo curl -fL https://app.getambassador.io/download/tel2/linux/amd64/latest/telepresence -o /usr/local/bin/telepresence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Make the binary executable:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chmod a+x /usr/local/bin/telepresence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Test Telepresence by connecting to the remote Kubernetes cluster:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telepresence connect
```


4. Send a request to the Kubernetes API server:



```
curl -ik https://kubernetes.default.svc.cluster.local
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache, private
Content-Type: application/json
Www-Authenticate: Basic realm="kubernetes-master"
Date: Tue, 09 Feb 2021 23:21:51 GMT
```



Congratulations! You’ve successfully configured Telepresence. Telepresence is intercepting the request you’re making to the Kubernetes API server, and routing over its direct connection to the cluster instead of over the Internet.

## Step 4: Set up an Intercept
An intercept is a routing rule for Telepresence. We can create an intercept that will route traffic intended for the `DataProcessingService` in the cluster and route all the traffic to the local version of the DataProcessingService running on port 3000.
1. Create the intercept:


```
telepresence intercept dataprocessingservice --port 3000
```


2. Access the application directly with Telepresence. In your browser, go to http://verylargejavaservice:8080. Again, Telepresence is intercepting requests from your browser and routing them directly to the Kubernetes cluster.
3. Now, let’s make a code change. Open `edgey-corp-python/DataProcessingService/app.py` and change `DEFAULT_COLOR` from `blue` to `orange`. Save the file.
4. Reload the page in your browser, and see how the color has changed from blue to orange.

That’s it! With Telepresence we saw how quickly we can go from editing a local service to seeing how these changes will look when deployed with the larger application. When you compare it to our original process of building and deploying a container after every change, it’s very easy to see how much time you can save especially as we make more complex changes or run even larger services.


## Learn More about Telepresence
Typically, developers at organizations adopting Kubernetes face challenges slow feedback loops from inefficient local development environments. Today, we’ve learned how to use Telepresence to set up fast, efficient development environments for Kubernetes and get back to the instant feedback loops you had with your legacy applications.

If you want to learn more about Telepresence, check out the following resources:
* Watch a [demo video](https://www.youtube.com/watch?v=W_a3aErN3NU), which shows more details on different features in Telepresence
* Check out the [Python Quickstart for Telepresence](http://docs/latest/telepresence/quick-start/qs-python/)
* Learn about [Preview URLs](https://www.getambassador.io/docs/pre-release/telepresence/howtos/preview-urls/#collaboration-with-preview-urls)  for easy collaboration with teammates
* [Join our Slack channel](https://d6e.co/slack) to connect with the Telepresence community

In our next tutorial, we’ll use Telepresence to set up a local Kubernetes development environment and then use Pycharm to set breakpoints and debug a broken service. To be notified when more tutorials are available, make sure to check out our [website](https://www.getambassador.io) or follow us on [Twitter](http://www.twitter.com/ambassadorlabs).

*This post was originally published on [Python Pandemonium](https://medium.com/python-pandemonium/developing-python-applications-on-kubernetes-75be68a3f0f9).*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>python</category>
      <category>kubernetes</category>
      <category>telepresence</category>
      <category>microservices</category>
    </item>
    <item>
      <title>SRE vs Platform Engineering</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Tue, 16 Feb 2021 21:08:00 +0000</pubDate>
      <link>https://dev.to/ambassadorlabs/the-rise-of-cloud-native-engineering-organizations-4dge</link>
      <guid>https://dev.to/ambassadorlabs/the-rise-of-cloud-native-engineering-organizations-4dge</guid>
      <description>&lt;p&gt;Over the past decade, engineering and technology organizations have converged on a common set of best practices for building and deploying cloud-native applications. These best practices include continuous delivery, containerization, and building observable systems.&lt;/p&gt;

&lt;p&gt;At the same time, cloud-native organizations have radically changed how they’re organized, moving from large departments (development, QA, operations, release) to smaller, independent development teams. These application development teams are supported by two new functions: site reliability engineering and platform engineering. SRE and platform engineering are spiritual successor of traditional operations teams, and bring the discipline of software engineering to different aspects of operations.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Site Reliability Engineering and Platform Engineering
&lt;/h1&gt;

&lt;p&gt;Platform engineering teams apply software engineering principles to accelerate software delivery. Platform engineers ensure application development teams are productive in all aspects of the software delivery lifecycle.&lt;/p&gt;

&lt;p&gt;Site reliability engineering teams apply software engineering principles to improve reliability. Site reliability engineers minimize the frequency and impact of failures that can impact the overall reliability of a cloud application.&lt;/p&gt;

&lt;p&gt;These two teams are frequently confused and the terms are sometimes used interchangeably. Indeed, some organizations consolidate SRE and platform engineering into the same function. This occurs because both roles apply a common set of principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform as product. These teams spend time understanding their internal customers, building roadmaps, having a planned release cadence, writing documentation, and doing all the things that go into a software product.&lt;/li&gt;
&lt;li&gt;Self-service platforms. These teams build their platforms for internal use. In these platforms, best practices are encoded, so that the users of these platforms don’t need to worry about it -- they just push the button. In the &lt;a href="https://puppet.com/resources/report/2020-state-of-devops-report/" rel="noopener noreferrer"&gt;Puppet Labs 2020 State of DevOps report&lt;/a&gt;, Puppet Labs found that High functioning DevOps organizations had more self-service infrastructure than low DevOps evolution organizations.&lt;/li&gt;
&lt;li&gt;A constant focus on &lt;a href="https://sre.google/sre-book/eliminating-toil/" rel="noopener noreferrer"&gt;eliminating toil&lt;/a&gt;. As defined in the Google SRE book, toil is manual, repetitive, automatable, tactical work. The best SRE and platform teams identify toil, and work to eliminate it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Platform Engineering
&lt;/h1&gt;

&lt;p&gt;Platform engineers constantly examine the entire software development lifecycle from source to production. From this introspective process, they build a workflow that enables application developers to rapidly code and ship software. A basic workflow typically includes a source control system connected with a continuous integration system, along with a way to deploy artifacts into production.&lt;/p&gt;

&lt;p&gt;As the number of application developers using the workflow grows, the needs of the platform evolves. Different teams of application developers need similar but different workflows, so self-service infrastructure becomes important. Common platform engineering targets for self-service include CI/CD, alerting, and deployment workflows. &lt;/p&gt;

&lt;p&gt;In addition to self-service, education and collaboration become challenges. Platform engineers find they increasingly spend time educating application developers on best practices and how to best use the platform. Application developers also find that they depend on other teams of application developers, and look to the platform engineering team to give them the tools to collaborate productively with different teams.&lt;/p&gt;

&lt;h1&gt;
  
  
  Site Reliability Engineering
&lt;/h1&gt;

&lt;p&gt;Site reliability engineers create and evolve systems to automatically run applications, reliably. The concept of site reliability engineering originated at Google, and is documented in detail in the Google SRE Book. Ben Treynor Sloss, the SVP at Google responsible for technical operations, described SRE as “what happens when you ask a software engineer to design an operations team.” &lt;/p&gt;

&lt;p&gt;SREs define service level objectives and build systems to help services achieve these objectives. These systems evolve into a platform and workflow that encompass monitoring, incident management, eliminating single points of failure, failure mitigation, and more.&lt;/p&gt;

&lt;p&gt;A key part of SRE culture is to treat every failure as a failure in the reliability system. Rigorous post-mortems are critical to identifying the root cause of the failure, and corrective actions are introduced into the automatic system to continue to improve reliability.&lt;/p&gt;

&lt;h1&gt;
  
  
  SRE and Platform Engineering at New Relic
&lt;/h1&gt;

&lt;p&gt;One of us (Bjorn Freeman-Benson) managed the engineering organization at New Relic until 2015 as it grew from a handful of customers to tens of thousands of customers, all sending millions of requests per second into the cloud. New Relic had independent SRE and platform engineering teams that followed the general principles outlined above.&lt;/p&gt;

&lt;p&gt;One of the reasons these teams were built separately was that the people who thrived in these roles differed. While both SREs and platform engineers need strong systems engineering skills in addition to classic programming skills, the roles dictate very different personality types. SREs tend to enjoy crisis management and get an adrenaline rush out of troubleshooting an outage. SRE managers thrive under intense pressure and are good at recruiting and managing similarly minded folks. On the other hand, platform engineers are more typical software engineers, preferring to work without interruption on big, complex problems. Platform engineering managers prefer to operate on a consistent cadence.&lt;/p&gt;

&lt;h1&gt;
  
  
  DevOps and GitOps
&lt;/h1&gt;

&lt;p&gt;Over the past decade, DevOps has become a popular term to describe many of these practices. More recently, GitOps has also emerged as a popular term. How do DevOps and GitOps relate to platform and SRE teams?&lt;/p&gt;

&lt;p&gt;Both DevOps and GitOps are a loosely codified set of principles of how to manage different aspects of infrastructure. The core principles of both of these philosophies -- automation, infrastructure as code, application of software engineering -- are very similar.&lt;/p&gt;

&lt;p&gt;DevOps is a broad movement that began with a focus on eliminating traditional silos between development and operation. Over time, strategies such as infrastructure automation and engineering applications with operations in mind have gained widespread acceptance as ways better build highly reliable applications.&lt;/p&gt;

&lt;p&gt;GitOps is an approach for application delivery. In GitOps, declarative configuration is used to codify the desired state of the application at any moment in time. This configuration is managed in a versioned source control system as the single source of truth. This ensures auditability, reproducibility, and consistency of configuration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DevOps is a set of guiding principles for SRE, while GitOps is a set of guiding principles for platform engineering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Unlocking application development productivity
&lt;/h1&gt;

&lt;p&gt;Site reliability engineering and platform engineering are two functions that are critical to optimizing engineering organizations for building cloud-native applications. The SRE team works to deliver infrastructure for highly reliable applications, while the platform engineering team works to deliver infrastructure for rapid application development. Together, these two teams unlock the productivity of application development teams.&lt;/p&gt;

&lt;p&gt;This story was originally published on the &lt;a href="https://www.getambassador.io/resources/rise-of-cloud-native-engineering-organizations/" rel="noopener noreferrer"&gt;Ambassador blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Optimize the Kubernetes Developer Experience with Version 0</title>
      <dc:creator>Richard Li</dc:creator>
      <pubDate>Fri, 10 Jul 2020 13:39:46 +0000</pubDate>
      <link>https://dev.to/ambassadorlabs/optimize-the-kubernetes-developer-experience-with-version-0-28n7</link>
      <guid>https://dev.to/ambassadorlabs/optimize-the-kubernetes-developer-experience-with-version-0-28n7</guid>
      <description>&lt;p&gt;One of the core promises of microservices is development team autonomy, which should, in theory, translate into faster and better decision making. But sometimes, this theory doesn’t translate into reality.&lt;/p&gt;

&lt;p&gt;Why is this the case?&lt;/p&gt;

&lt;p&gt;There are a multitude of reasons for microservices not working well. Microservices, cloud-native, and Kubernetes are a new approach and culture shift, and there’s a lot of good ways and bad ways to approach the challenge.&lt;/p&gt;

&lt;p&gt;One of the keys to success is enabling a consistent developer experience for each microservice from day 0, which is critical for unlocking team autonomy and development velocity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrapping a Microservice
&lt;/h2&gt;

&lt;p&gt;Creating microservices should be cheap and easy. This enables app dev teams to quickly build and ship new microservices to address specific business needs without being encumbered by preexisting code. At the same time, this agility and flexibility do come at a cost — applications become distributed, dynamic organisms that can be harder to develop, test, and debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Developer Experience == Better Customer Experience
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://www.getambassador.io/podcasts/gene-kim-on-developer-productivity-the-five-ideals-and-platforms/" rel="noopener noreferrer"&gt;recent Ambassador podcast&lt;/a&gt;, Gene Kim spoke about how a great developer experience is critical to delivering value to customers. By creating a great developer experience, developers can ship more code, which results in happier customers.&lt;/p&gt;

&lt;p&gt;We’ve seen a similar trend in organizations that successfully adopt microservices: an emphasis on the developer experience. While it may not be a “strategic” initiative in the organization, usually there’s someone at the company who is passionate about creating a great developer workflow and is able to spend time working on continuously improving that developer workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Microservices Developer Experience
&lt;/h2&gt;

&lt;p&gt;With a monolith, there’s a common application that is the target for the development workflow. With microservices, there is no longer a single common application. Every new microservice requires a developer workflow. Without due care, it’s easy to have a smorgasbord of microservices, all with poor developer workflows. In this situation, velocity actually decreases since microservices can’t be easily and rapidly shipped. This defeats the entire rationale for adopting microservices in the first place, and development slows.&lt;/p&gt;

&lt;p&gt;At the same time, &lt;a href="https://blog.getambassador.io/why-it-ticketing-systems-dont-work-with-microservices-18e2be509bf6" rel="noopener noreferrer"&gt;microservices presents an opportunity for improving the developer experience&lt;/a&gt;. By optimizing the developer experience of each microservice, teams can build the best possible developer experience for the team (and not the organization), and continue to optimize that experience as the application and team evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience, Defined
&lt;/h2&gt;

&lt;p&gt;A developer experience is the workflow a developer uses to develop, test, deploy, and release software. The developer experience typically consists of both an inner dev loop and an outer dev loop. &lt;a href="https://blog.getambassador.io/four-approaches-for-microservice-testing-inner-dev-loops-in-kubernetes-bcf779668179" rel="noopener noreferrer"&gt;The inner dev loop&lt;/a&gt; is a single developer workflow. A single developer should be able to set up and use an efficient inner dev loop to code and test changes quickly. The inner dev loop is typically used for pre-commit changes. The outer dev loop is a shared developer workflow that is orchestrated by a continuous integration system. The outer dev loop is used for post-commit changes and includes automated builds, tests, and deploys.&lt;/p&gt;

&lt;p&gt;Engineering a good inner and outer dev loop is key to a great developer experience and unlocking the potential of microservices. So how can an engineer help in building a great developer experience?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Version 0 Strategy
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.getambassador.io/learn/kubernetes-glossary/version-0/" rel="noopener noreferrer"&gt;version 0 strategy&lt;/a&gt; involves shipping an end-to-end development and deployment workflow as the first milestone — before any features are coded. A good test of a version 0 milestone is if a developer on a different team is able to independently code, test, and release a change to the microservice without consulting the original team. This implies a version 0 has a development environment, a deployment workflow, and documentation that explains how to get started and ship. With a version 0 in place, the microservices team then begins with feature development, knowing that their ability to rapidly iterate and ship is already in place.&lt;/p&gt;

&lt;p&gt;The Version 0 approach works well for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The codebase is very simple, so there is no reverse engineering of obscure dependencies, monkey patches, or any other gremlins to get a working environment&lt;/li&gt;
&lt;li&gt;With no features, there is less pressure from external parties who want to implement changes and adjustments to the roadmap&lt;/li&gt;
&lt;li&gt;A great developer experience accrues benefits over time, so Version 0 maximizes the payback period&lt;/li&gt;
&lt;li&gt;Most importantly, version 0 sets the tone for the microservice, which is that developer experience is important!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Version 0 for Engineers
&lt;/h2&gt;

&lt;p&gt;Any engineer can adopt the version 0 practice (and should!). &lt;a href="https://www.getambassador.io/resources/enabling-full-cycle-development" rel="noopener noreferrer"&gt;A development team should have full autonomy over a microservice&lt;/a&gt;, which includes the development timeline and workflow! So starting with a Version 0 will help the team rapidly bootstrap the microservice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 0 for Managers
&lt;/h2&gt;

&lt;p&gt;Managers can support Version 0 across the organization by asking engineering teams that are creating new microservices to start with a Version 0. As engineering organizations grow, the organization could choose to assign platform engineers focused on development workflows. These platform engineers should not implement Version 0, but instead provide tools, templates, and best practices to the microservice teams on how best to build a version 0. The Netflix engineering team adopted &lt;a href="https://netflixtechblog.com/full-cycle-developers-at-netflix-a08c31f83249#0df4" rel="noopener noreferrer"&gt;this approach&lt;/a&gt; to developer empowerment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Every engineer has felt the pain of a bad developer workflow. A trivial one-line fix takes a half-day to complete. Microservices can exacerbate this problem. The Version 0 strategy is a simple but powerful strategy that will help integrate developer experience into your organization’s development workflow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://blog.getambassador.io/k8s-might-slow-you-down-but-theres-one-thing-you-can-do-about-it-the-version-0-strategy-c81a1a0ff6e" rel="noopener noreferrer"&gt;Ambassador blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>microservices</category>
      <category>ambassador</category>
    </item>
  </channel>
</rss>
