<?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: Gal Bashan</title>
    <description>The latest articles on DEV Community by Gal Bashan (@galbash).</description>
    <link>https://dev.to/galbash</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%2F992351%2F973fb655-d318-475b-82e0-51a30e53dd24.jpeg</url>
      <title>DEV Community: Gal Bashan</title>
      <link>https://dev.to/galbash</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/galbash"/>
    <language>en</language>
    <item>
      <title>How ChatGPT’s Coding Skills Got Me Drunk</title>
      <dc:creator>Gal Bashan</dc:creator>
      <pubDate>Mon, 12 Dec 2022 20:02:17 +0000</pubDate>
      <link>https://dev.to/galbash/how-chatgpts-coding-skills-got-me-drunk-1gkg</link>
      <guid>https://dev.to/galbash/how-chatgpts-coding-skills-got-me-drunk-1gkg</guid>
      <description>&lt;h2&gt;
  
  
  ChatGPT helped me scrape cocktail websites to create a universal drink index.
&lt;/h2&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%2Fm2fe2xv6yaepi7qwbtpf.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%2Fm2fe2xv6yaepi7qwbtpf.png" alt="This image was generated with DALL-E, obviously." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately, I've become a fan of making cocktails. After getting the best equipment and booze money can buy, I realized the leading blocker for me was cocktail recipes. I wanted a platform where I could input the ingredients I have at home, and the output would be a list of cocktails I could make. There are a few apps for that, but they are limited in their variety unless you pay for the app. And since the only thing I like more than cocktails is &lt;em&gt;free&lt;/em&gt; cocktails, I was looking for an alternative.&lt;/p&gt;

&lt;p&gt;It was about a week after &lt;a href="https://openai.com/blog/chatgpt/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; was released, and it had already become my best friend. Could it also be my drinking buddy? I realized many recipes were available online, and I just had to index them correctly. Can ChatGPT build me a tool to index them on my own?&lt;/p&gt;

&lt;p&gt;TLDR — yes, &lt;a href="https://github.com/galbash/drinkindex" rel="noopener noreferrer"&gt;here is the GitHub repo&lt;/a&gt;. There are even ChatGPT-generated READMEs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Plan
&lt;/h3&gt;

&lt;p&gt;I decided to give it a go. I wanted to use ChatGPT to build a simple system to index cocktails from the web. The solution would have two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crawler — a process that gets a domain to crawl and outputs URLs that appear to be cocktail recipes to a queue. It also follows additional URLs on the page recursively to search for other pages with recipes. This seemed like an easy enough task to let ChatGPT code on its own&lt;/li&gt;
&lt;li&gt;Indexer — This component is meant to get a URL, determine if the page contains a cocktail recipe, and store it in a database. The problem is that blogs with cocktail recipes are highly unstructured and have a lot of unnecessary text before reaching the point. Can ChatGPT help me make sense of this mess?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the plan in place, I set out to start building. I started by laying down the architecture and had to decide what queue to use. ChatGPT came to the rescue:&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%2F91y1lyzeblnsjr76pk7i.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%2F91y1lyzeblnsjr76pk7i.png" width="800" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reviewing its suggestions, I decided to go with RabbitMQ since I had some experience with it. I asked ChatGPT to lay out the foundations for 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%2Fjcufzm3qnnfary9gbqq7.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%2Fjcufzm3qnnfary9gbqq7.png" width="800" height="610"&gt;&lt;/a&gt;&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%2F9zwbgub6wkjnff2vkm7w.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%2F9zwbgub6wkjnff2vkm7w.png" width="800" height="626"&gt;&lt;/a&gt;&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%2F5l2spzuhsrcd4dhie5bh.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%2F5l2spzuhsrcd4dhie5bh.png" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the project set up, the next step was for ChatGTP to develop the crawler.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Crawler
&lt;/h3&gt;

&lt;p&gt;I asked ChatGPT to do the work for me, and boy, did it deliver:&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%2Fnxfj61dlv5kob49t2vbc.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%2Fnxfj61dlv5kob49t2vbc.png" width="800" height="211"&gt;&lt;/a&gt;&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%2F3qbki5sn548zeh0r3ghl.jpeg" 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%2F3qbki5sn548zeh0r3ghl.jpeg" width="800" height="1204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I ran the program, I came into two issues. First, the visited URLs were not cached, and since almost any page was linked to the home page, we ended up in an infinite loop. I asked ChatGPT to handle that, and it modified the code correctly:&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%2Fmddgo46rb26ozsmy0mdu.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%2Fmddgo46rb26ozsmy0mdu.png" width="771" height="102"&gt;&lt;/a&gt;&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%2F9swdiw34fzhnzuqqmhji.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%2F9swdiw34fzhnzuqqmhji.png" alt="Sadly I cannot recreate this response to catch it in a better resolution." width="620" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second issue was that it started crawling other domains as well — for example, for a page containing a video, the crawler started crawling youtube as well. I asked ChatGTP to fix that as well, and it obliged:&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%2Fxcuxpovic61yjqpmq9i8.jpeg" 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%2Fxcuxpovic61yjqpmq9i8.jpeg" width="800" height="1478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that was it! The crawler was ready, and the next step was to code the indexer.&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%2F1358brt7zoipj18yig6i.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%2F1358brt7zoipj18yig6i.png" alt="Crawler output. There are some mistakes in identifying recipes — the next step will handle that." width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Indexer
&lt;/h3&gt;

&lt;p&gt;As I mentioned before, parsing the content of a web page to identify if it describes a cocktail recipe is challenging. Here is an example of a cocktail recipe web page:&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%2Fyg1r5g2mg7lu3bae8jy3.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%2Fyg1r5g2mg7lu3bae8jy3.png" width="800" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's almost impossible to handle all the different use cases to parse the page and extract the ingredients. Once again — ChatGPT to the rescue!&lt;/p&gt;

&lt;p&gt;I came across an &lt;a href="https://github.com/acheong08/ChatGPT" rel="noopener noreferrer"&gt;unofficial python implementation of the ChatGPT API&lt;/a&gt; and decided to use it in my indexer. The idea was simple, using a well-crafted prompt, I should be able to use ChatGPT to extract the ingredients from the cocktail page. Since ChatGPT has no internet access, it couldn't code this part, but it did help me with the generic components of it. Here is the code I used:&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;pika&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;revChatGPT.revChatGPT&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chatbot&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CocktailRecipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;traceback&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;config&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;session_token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cf_clearance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;chatbot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chatbot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# connect to RabbitMQ
&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BlockingConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConnectionParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# create a queue to consume messages from, if it does not already exist
&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queue_declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drink_urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;QUESTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    From the following text below, please understand if it is an article
    describing a cocktail recipe. If it is, output the following: The first
    line should be: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;cocktail name&amp;gt;: &amp;lt;ranking&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. If the ranking doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t exist
    output &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. use only lowercase letters and the generic name of the cocktail
    , without mentioning brands. the following lines contain the ingredients:
    each line should contain one ingredient and it&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s amount in the format
    &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;ingredient&amp;gt;: &amp;lt;amount&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. The ingredient part (before the semicolon)
    should contain only the ingredient name, not the amount. If it is not a
    cocktail recepie, output only the word &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. Output the ingredients in 
    their generic name, and don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t include a brand. For example, instead of 
    &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bacardi white rum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; output &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white rum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. All of the output should be lower
    cased, don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t capitalize any word. The text is: %s&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# define a callback function to process incoming messages
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&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="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatbot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_chat_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUESTION&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&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;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not a cocktail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&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="n"&gt;traceback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format_exc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# consume messages from the queue, using the callback function to process them
&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basic_consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drink_urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_message_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auto_ack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# start consuming messages
&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_consuming&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked like a charm. ChatGPT did an excellent job understanding whether or not a page contained a cocktail recipe, and if it did, the output was almost always in the correct format. I used to think coding with Python was explicit as coding could be, but it was never &lt;em&gt;that&lt;/em&gt; close.&lt;/p&gt;

&lt;p&gt;Now I just had to store it in a database. I asked ChatGPT to create the database for 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%2Flnhuk8h9kbj5ciovazy7.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%2Flnhuk8h9kbj5ciovazy7.png" width="800" height="1254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, I gave it a sample input generated by itself and asked it to write code for inserting the information into the database. The initial implementation it provided was using psycopg2. I asked it to use SQLAlchemy as I find it easier to work with an ORM:&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%2F7f8fqlwuqulrkr326hfg.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%2F7f8fqlwuqulrkr326hfg.png" width="647" height="196"&gt;&lt;/a&gt;&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%2Ffnfvfmz6po2a5l3v1hqf.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%2Ffnfvfmz6po2a5l3v1hqf.png" alt="Note that ChatGPT coded the parsing logic of its response for me as well" width="800" height="1299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I integrated this code into the indexer and finally had the cocktail database of my dreams!&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%2F78ir1h6mtvfhul1gk7se.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%2F78ir1h6mtvfhul1gk7se.png" alt="Example output from the indexer process" width="800" height="591"&gt;&lt;/a&gt;&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%2F2zuiafl14djg82f8y3dz.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%2F2zuiafl14djg82f8y3dz.png" alt="A view of my cocktail database" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, I will use ChatGPT to help me create an API and UI to browse the cocktails database and choose the one I want to make today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This whole project took me roughly 3 hours from end to end. ChatGPT's ability to accelerate my development process blew my mind. The biggest win was the text parsing ChatGPT provided, which I could not do myself, and ChatGPT made simple.&lt;/p&gt;

&lt;p&gt;However, the more complex a task got, the chances of ChatGPT performing it correctly decreased drastically. When pairing with ChatGPT, it is still the developer's job to break down the work into small enough tasks for it to swallow, at least for now.&lt;/p&gt;

&lt;p&gt;I'm excited to see what comes next!&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%2Ft5wswbbabcwqrfojvomy.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%2Ft5wswbbabcwqrfojvomy.png" alt="I asked ChatGPT to rewrite the conclusion. Who did it better?" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>openai</category>
      <category>python</category>
      <category>softwaredevelopment</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>Stop Using Dev Metrics!</title>
      <dc:creator>Gal Bashan</dc:creator>
      <pubDate>Wed, 30 Nov 2022 14:18:19 +0000</pubDate>
      <link>https://dev.to/galbash/stop-using-dev-metrics-3mac</link>
      <guid>https://dev.to/galbash/stop-using-dev-metrics-3mac</guid>
      <description>&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%2F3fws4dydgc5kx4msd66p.jpeg" 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%2F3fws4dydgc5kx4msd66p.jpeg" width="760" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You manage the company’s best team: the fastest cycle time, the highest planning accuracy, and the least amount of rework. Your team has the lowest review time, the most weekly deploys, and the best bugs / KLOC ratio. And then someone high up shuts down your project — what just happened?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Output Paradox
&lt;/h3&gt;

&lt;p&gt;As a junior developer, I was taught that merging small changes frequently is key to delivering value fast. As a junior engineering manager, I was told that tracking &amp;amp; optimizing metrics were vital to the manager’s job. The first google result pointed me to a bunch of terms and acronyms, and these were my first introductions to dev metrics.&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%2F6o740al7j1zw2xjlab4v.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%2F6o740al7j1zw2xjlab4v.png" alt="Google’s featured snippet for “metrics for engineering manager.” This is what we teach engineering managers to track." width="767" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dev metrics are essentially a set of metrics that help engineering teams track their velocity (move fast) and quality (without breaking things). Different metrics can be used to measure these attributes. Cycle time, PRs count, or closed issues track velocity. To track quality, monitor the defects count, mean-time-to-resolution, or the number of deployments that cause failure. Each of these metrics will provide different insights into the attribute you inspect. Some metrics also help with analyzing proxy attributes. Track rework to analyze efficiency, which impacts velocity. Planning accuracy is a good indicator of predictability, which enables both velocity and quality and has value on its own.&lt;/p&gt;

&lt;p&gt;The problem with all the metrics above is that while they do an excellent job of measuring efficiency, they are usually not enough to measure success. The main reason is that they are entirely disconnected from the &lt;em&gt;business&lt;/em&gt; KPIs (key performance indicators, yet another fancy name for metrics). This disconnection often leads to ineffective communication between organizations in the company, mainly product and engineering. After all, the product organization (and the rest of the business) doesn’t care for velocity or quality alone, as those track &lt;em&gt;output&lt;/em&gt;. The product organization usually cares for &lt;em&gt;outcome &lt;/em&gt;— what revenue did our new feature produce? How many new users did we attract?&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%2F12xms30lgu7a0v279o3l.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%2F12xms30lgu7a0v279o3l.png" alt="Using dev metrics to measure project success, Illustration." width="318" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a new engineering manager, this was baffling to me. On the one hand, it was clear that carrying on measuring my team based on dev metrics over business metrics would lead to misalignment with the product team. On the other hand, it seemed unfair to measure my team based on business metrics: How can they impact them? Is it our job? Will I be stepping on the product organization’s toes?&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure What Matters
&lt;/h3&gt;

&lt;p&gt;I took a leap of faith and tried using business metrics as my north star. As time passed, it led to better results.&lt;/p&gt;

&lt;p&gt;First, it simplified communication. it’s easier for your product counterpart to understand why it’s essential to prioritize the DB upgrade when you put it in terms of shared KPI that will be harmed. Just because it’s clear to you that if you don’t prioritize the DB upgrade, the following few user stories will take twice as long, and you will have to spend time on maintenance, which will delay the feature release to a point where you won’t have enough time to hit the usage target you set as the KPI, doesn’t mean it’s clear to your product counterpart. I mean, that’s &lt;em&gt;a lot&lt;/em&gt; of hops; why not start with the one that matters? (no, it’s not the DB upgrade one)&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%2Fkf4v0omwo9ladvqgdri5.jpg" 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%2Fkf4v0omwo9ladvqgdri5.jpg" alt="Product hearing the phrase “we need to refactor the API abstraction layer to improve DB query p99 performance.״" width="460" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, measuring my team based on business metrics made me see that we can impact them quite a bit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can identify features where we can build 80% of the user value for 20% of the effort. This can free up resources to help move our KPIs even faster. To do that, the team must clearly understand the business goals, user needs, and the drive to improve them.&lt;/li&gt;
&lt;li&gt;We can use the KPIs to guide what tech debt we should accumulate: Are we trying to get our first feature users, and feature-failure is an option? Let’s release as fast as possible and worry about tech debt later. Are we trying to improve the retention of a large customer base? Let’s ensure high quality for this one.&lt;/li&gt;
&lt;li&gt;We can suggest solutions to pain points product didn’t even know solvable, based on a new technology advancement or an innovative engineering angle.&lt;/li&gt;
&lt;li&gt;We can (as annoying as it may be) use the KPIs to understand that there is no point in pursuing a specific cool technological solution we want to implement because the problem itself is not crucial to the business.&lt;/li&gt;
&lt;/ul&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%2Fehaao0ks8h2u11fvc3fr.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%2Fehaao0ks8h2u11fvc3fr.png" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, I realized that measuring my team and myself on anything other than the business’ KPIs sets us up for failure. It will drive us to build &amp;amp; ship many durable features fast, over shipping features customers use. I understood that as someone who builds the product, I &lt;em&gt;am&lt;/em&gt; a part of the product team. Since the product success is my success, I should be calibrated to that. It is alignment at best — when engineering and product share the same goals, they will likely leverage each other’s strengths to achieve them.&lt;/p&gt;

&lt;h3&gt;
  
  
  How To Measure Success?
&lt;/h3&gt;

&lt;p&gt;After switching to metrics that matter to the business, My product counterpart and I had to choose a framework to measure them. At Epsagon, we used the &lt;a href="https://rework.withgoogle.com/guides/set-goals-with-okrs/steps/introduction/" rel="noopener noreferrer"&gt;OKR framework&lt;/a&gt;. I won’t go into details as there are many great resources for implementing OKRs available online. The gist is that this is an excellent framework for mid to large organizations, usually in the post-product-market-fit phase. It helps align different teams, groups, and organizations within the business toward the same &lt;em&gt;outcome-driven goals.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At Epsagon, we had OKRs for every product team, and they were the goals of the engineers, product, and design people who made the product team. Once implemented, we had a better collaboration between product and engineering. Less arguing over requirements and more cooperation to solve problems. We also noticed that the increase in autonomy caused by setting goals over tasks increased innovation and ownership over outcomes. The teams set the roadmap, and solutions came from engineering as well as product.&lt;/p&gt;

&lt;p&gt;The downside of this methodology is that it requires some effort in implementation and also requires you to be able to state your goals over periods of months. This is usually hard for small start-ups, especially before product-market-fit. For earlier stages, it’s OK to work with &lt;a href="https://www.ycombinator.com/library/6j-how-to-set-kpis-and-goals-sus-2019" rel="noopener noreferrer"&gt;one primary metric&lt;/a&gt; and still be driven by a business objective while remaining agile enough to change your goals and focus in the granularity of weeks or days.&lt;/p&gt;

&lt;p&gt;Whether your team is big or small, have one mission or competing priorities — as long as you measure what matters, you have a higher chance of succeeding. The “how” is just an optimization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication is Key
&lt;/h3&gt;

&lt;p&gt;Once we establish business KPIs, the next step is to follow through. In my experience, there are two critical aspects to communicating and implementing this change. The first one is consistency: it’s not enough to set those metrics and revisit them three months later to find out we missed our marks. As leaders, it is our job to constantly monitor these metrics and ensure their state and roadmap to improve them are always communicated to our entire team.&lt;/p&gt;

&lt;p&gt;The second aspect is commitment: it’s tempting to fall back to old habits of measuring individuals using dev metrics to optimize them. This will send the wrong message to your team, hinting that while you say you care about business KPIs, what you &lt;em&gt;really&lt;/em&gt; care about are dev metrics. Be sure to change your habits to reflect your priorities: celebrate business outcomes, cut non-must-have features instead of pushing for deadlines, and raise flags when business KPIs are down. You can still use dev metrics as indicators; just remember to link them to their effect on business KPIs.&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%2Fip7pccjoimublixzcm7s.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%2Fip7pccjoimublixzcm7s.png" alt="“We optimize for outcomes. Also, you didn’t meet your daily PR quota, so we’ll be cutting your bonus.”" width="586" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Are Dev Metrics Deprecated?
&lt;/h3&gt;

&lt;p&gt;Despite the click-baiting headline of this article, the answer is no — they should just be used correctly. For one, dev metrics are powerful tools for troubleshooting your business metrics. For example, a decline in user retention may be explained by an increase in defect count. In this case, you can use the dev metric as a leading indicator: Instead of waiting for the retention to drop, you should monitor the defect count to prevent it from dropping (similar to how you would monitor CPU usage to avoid 5xx API errors count from spiking and causing actual harm to you users). Another use case is dev metrics as a leading indicator for developer experience and satisfaction (which, in turn, impacts developer retention).&lt;/p&gt;

&lt;p&gt;However, the vital thing to remember is that you should never optimize the dev metrics. You should always be optimizing business metrics and use dev metrics optimization only as a tool to get to that goal. And, of course, you should only set, track or optimize dev metrics goals after you have a clear sense of the business &lt;em&gt;outcome&lt;/em&gt; you are trying to achieve and the business KPIs you are trying to hit. Great engineering stats won’t save your project if it has no value.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;If you are leading an engineering organization, switching to optimizing business outcomes over dev metrics will improve your team’s chances of creating a real impact for the business. If you are committed to becoming an outcome-driven leader, I urge you to ask yourself these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do I know what business outcomes are expected of me?&lt;/li&gt;
&lt;li&gt;Am I doing whatever I can to optimize for these outcomes?&lt;/li&gt;
&lt;li&gt;How am I tracking success? What are the criteria for raising a flag or changing my plans?&lt;/li&gt;
&lt;li&gt;Is my team aware of the business goals and roadmap to achieve them? What is their input on it?&lt;/li&gt;
&lt;li&gt;Which of my business KPIs can be improved by improving which dev metrics?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, these will assist you with shipping features customers want to use!&lt;/p&gt;




</description>
      <category>engineeringleadershi</category>
      <category>agile</category>
      <category>okr</category>
      <category>leadership</category>
    </item>
  </channel>
</rss>
