<?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: Alan Barr</title>
    <description>The latest articles on DEV Community by Alan Barr (@alanmbarr).</description>
    <link>https://dev.to/alanmbarr</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%2F53570%2F7651f41f-838c-468f-8263-f55fb25f75b9.jpg</url>
      <title>DEV Community: Alan Barr</title>
      <link>https://dev.to/alanmbarr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alanmbarr"/>
    <language>en</language>
    <item>
      <title>AI / LLM Testing Podcast</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Mon, 08 Jan 2024 17:05:03 +0000</pubDate>
      <link>https://dev.to/alanmbarr/ai-llm-testing-podcast-43d1</link>
      <guid>https://dev.to/alanmbarr/ai-llm-testing-podcast-43d1</guid>
      <description>&lt;ul&gt;
&lt;li&gt;How are we using AI?&lt;/li&gt;
&lt;li&gt;AI Products and Testing&lt;/li&gt;
&lt;li&gt;AI Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do you think?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.alanmbarr.com/blog/ai-llm-testing-podcast/"&gt;AI / LLM Testing Podcast&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Solo, pair program, or mob ?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Tue, 05 Sep 2023 13:57:28 +0000</pubDate>
      <link>https://dev.to/alanmbarr/solo-pair-program-or-mob--19ai</link>
      <guid>https://dev.to/alanmbarr/solo-pair-program-or-mob--19ai</guid>
      <description>&lt;p&gt;Do you program, as a duo, a mob or by yourself?&lt;/p&gt;

&lt;p&gt;When I worked at marketing companies, I usually programmed by myself. I've seen others try pair programming and at times programming as a mob. Either of these could work, but I am curious to have you tried or disliked any in particular.&lt;/p&gt;

&lt;p&gt;What do you think? Would you try pair programming or mobbing, or would you rather work by yourself?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Is Domain-Driven Design relevant?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Wed, 30 Aug 2023 16:55:31 +0000</pubDate>
      <link>https://dev.to/alanmbarr/is-domain-driven-design-relevant-50f8</link>
      <guid>https://dev.to/alanmbarr/is-domain-driven-design-relevant-50f8</guid>
      <description>&lt;p&gt;I found a &lt;a href="https://www.domainlanguage.com/ddd/reference/"&gt;FREE&lt;/a&gt; guide on Domain-Driven Design that I found helpful. How is it relevant anymore? &lt;/p&gt;

&lt;p&gt;It seems like writing code is less significant than modeling your system.&lt;/p&gt;

&lt;p&gt;Have you found value in domain-driven design techniques? Or did you find that modeling is not worth the effort?&lt;/p&gt;

&lt;p&gt;What do you think? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Down for me?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Wed, 23 Aug 2023 15:48:41 +0000</pubDate>
      <link>https://dev.to/alanmbarr/down-for-me-595</link>
      <guid>https://dev.to/alanmbarr/down-for-me-595</guid>
      <description>&lt;p&gt;I was trying to post and dev.to was down for me.&lt;/p&gt;

&lt;p&gt;When you make a change, how do you know when an update is a bad break?&lt;/p&gt;

&lt;p&gt;Have you ever had a bad deployment?&lt;/p&gt;

</description>
      <category>devto</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Should you ALWAYS write unit tests?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Mon, 21 Aug 2023 21:24:40 +0000</pubDate>
      <link>https://dev.to/alanmbarr/should-you-always-write-unit-tests-144e</link>
      <guid>https://dev.to/alanmbarr/should-you-always-write-unit-tests-144e</guid>
      <description>&lt;p&gt;I was reading an article about &lt;a href="https://www.testim.io/blog/unit-test-vs-integration-test/"&gt;unit tests&lt;/a&gt;. Honestly, it seems like a lot of effort. Do you receive a lot of value from your unit tests? Personally, I'm still trying to understand domain-driven design. I feel like with supple design, we need to use several techniques to pin software on the wall. Constraints such as revealing interfaces, side-effects-free functions, and many assertions should make your software better.&lt;/p&gt;

&lt;p&gt;What do you think? Is it always better to write unit tests? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>unittest</category>
    </item>
    <item>
      <title>Surprising Apps in Testing</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Sat, 19 Aug 2023 13:57:16 +0000</pubDate>
      <link>https://dev.to/alanmbarr/surprising-apps-in-testing-kb9</link>
      <guid>https://dev.to/alanmbarr/surprising-apps-in-testing-kb9</guid>
      <description>&lt;p&gt;Do you have any applications that you test? I was wondering how to explain a common app. I decided to log in to my grocery account, and I was surprised to see...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ajhDPLsh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmhn9c8rpkzn650az33e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajhDPLsh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmhn9c8rpkzn650az33e.png" alt="Grocery App Bug" width="800" height="1733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I could guess. I'm an Android user. It's probably a hybrid app, and they probably know it. Well, that's life as a software tester. Play around and you'll find something new anytime.&lt;/p&gt;

&lt;p&gt;What have you found?&lt;/p&gt;

</description>
      <category>testing</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How should I start?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Thu, 17 Aug 2023 16:59:05 +0000</pubDate>
      <link>https://dev.to/alanmbarr/how-should-i-start-4ccj</link>
      <guid>https://dev.to/alanmbarr/how-should-i-start-4ccj</guid>
      <description>&lt;p&gt;If you were going to look at an application with fresh eyes, how would you test?&lt;/p&gt;

&lt;p&gt;There is always a risk of being static and stale with your testing. Mind maps, heuristics, and mnemonics like &lt;a href="https://www.sharonob.com/blog/sfdipot"&gt;SFDIPOT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Imagine yourself a beginner in software testing. Where could you start to investigate an application and find a problem?&lt;/p&gt;

</description>
      <category>testing</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Security and Observability Platforms</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Tue, 07 Sep 2021 19:11:07 +0000</pubDate>
      <link>https://dev.to/alanmbarr/security-and-observability-platforms-56jd</link>
      <guid>https://dev.to/alanmbarr/security-and-observability-platforms-56jd</guid>
      <description>&lt;p&gt;Where do you see the future of software development platforms going with security and observability? What does security look like? What does observability look like?&lt;/p&gt;

&lt;p&gt;I am curious because this is brand new territory for me. Where do you learn about these topics?&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>How do you deal with incidents?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Wed, 13 Jan 2021 22:52:17 +0000</pubDate>
      <link>https://dev.to/alanmbarr/how-do-you-deal-with-incidents-3mnl</link>
      <guid>https://dev.to/alanmbarr/how-do-you-deal-with-incidents-3mnl</guid>
      <description>&lt;p&gt;It's near the end of the workday and something is blowing up. People are raging in slack. How do you manage the chaos? I'm no expert at emergencies I've been through many but I'd like to know how you manage problems at scale? How do you keep a handle on issues?&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>When should you build an internal developer platform on Kubernetes?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Wed, 13 Jan 2021 21:02:58 +0000</pubDate>
      <link>https://dev.to/alanmbarr/when-should-you-build-an-internal-developer-platform-on-kubernetes-ee0</link>
      <guid>https://dev.to/alanmbarr/when-should-you-build-an-internal-developer-platform-on-kubernetes-ee0</guid>
      <description>&lt;p&gt;What do you all think? I built mine, its been a great six+ months, and I'm a little regretful I could not buy and leverage one of the options on the market. When do you think it makes sense to build an internal developer platform?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Who even needs Kubernetes?</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Thu, 01 Aug 2019 12:34:25 +0000</pubDate>
      <link>https://dev.to/alanmbarr/who-even-needs-kubernetes-14oe</link>
      <guid>https://dev.to/alanmbarr/who-even-needs-kubernetes-14oe</guid>
      <description>&lt;p&gt;Is Kubernetes even necessary at all?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Export ServiceNow Report CSV to Airtable</title>
      <dc:creator>Alan Barr</dc:creator>
      <pubDate>Fri, 19 Jul 2019 03:00:00 +0000</pubDate>
      <link>https://dev.to/alanmbarr/export-servicenow-report-csv-to-airtable-ffg</link>
      <guid>https://dev.to/alanmbarr/export-servicenow-report-csv-to-airtable-ffg</guid>
      <description>&lt;h2&gt;
  
  
  ServiceNow report data to Airtable
&lt;/h2&gt;

&lt;p&gt;I manage a platform product roadmap and the majority of work lives in ServiceNow. ServiceNow began as a type of help desk ticketing utility. It appears they are positioning themselves as a general business workflow engine. I do not have API access as far as I know but I can generate reports and download them as CSV's. There appears to be a module in ServiceNow to do Agile Software development workflows but I lack the time or the interest to discover how to use this functionality. In the mean time we are using a flexible board that will place cards into our Visual Task Board based on the assignment group. This enables our team to work in a Kanban style flow. Unfortunately the burden is on me to generate metrics and charts based on their progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  ServiceNow reporting interface
&lt;/h2&gt;

&lt;p&gt;ServiceNow has a decent reporting interface that makes it easy to find data in tables and connect data structures together. I access the vtb_card table and populate specific columns based on the assignment group of my team. Specifically Task.Number, Lane, Task.Short Description, Task.State, Label 1, Label 2, Label 3, Label 4, Label 5, Label 6, Label 7. The most annoying thing about the labels are they are specific to a particular board and do not retain their names. However, it is not terrible to work around it. From there right click on the column name and export to CSV.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preprocessing the data before uploading to AirTable
&lt;/h2&gt;

&lt;p&gt;The one thing I had to do first with the exported CSV was to convert it to UTF8. The default encoding was not UTF8 and I used powershell to help achieve this. I also use the Google Cloud powershell library to upload my converted csv to cloud storage. Where I can trigger a serverless compute function to process the upload to airtable. This powershell is triggered by a usual batch script with the command. There's probably a way to do it in python but PowerShell was easy enough.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; PowerShell -NoProfile -ExecutionPolicy Bypass -Command "&amp;amp; './upload\_backlog.ps1'"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$srcRoot = "dailybacklogreport\"

$utf8 = New-Object System.Text.UTF8Encoding $false

Get-ChildItem $srcRoot\*  -recurse -Include *.csv | ForEach-Object {
$content = $_ | Get-Content -Raw

Set-Content -Value $utf8.GetBytes($content) -Encoding Byte -Path $_.FullName

}

$fileList = Get-ChildItem -Path $srcRoot -File -Force -Recurse
$file = $fileList | Select-Object -First 1

New-GcsObject -Bucket "alanmbarrdatasyncing" -File $file.FullName -ObjectName "platform_engineering/backlog.csv" -Force
Remove-Item -Path "$srcRoot\*" -Include "*.csv" -Force
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once uploaded it triggers the Google Cloud Function to run on file creation. I use pandas to do the data filtering. I only want to send new records or records that changed due to AirTable Limits. What is missing from the script is keeping the labels in sync over time. It's possible but I haven't found it worth the effort to write a custom check.&lt;/p&gt;

&lt;p&gt;The requirements.txt for the GC Function needs to contain the libraries for data processing.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;airtable-python-wrapper==0.12.0
pandas==0.24.2
gcsfs==0.2.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def parse_report(data):
    import pandas as pd
    def filterColumn(row):
        return list(filter(lambda row: row != None, row.values))

    startWithPandas = pd.read_csv('gs://' + data['bucket'] + '/' + data['name'])
    startWithPandas["label_1"] = startWithPandas["label_1"].apply(lambda x: "Defect" if x == True else None )
    startWithPandas["label_2"] = startWithPandas["label_2"].apply(lambda x: "High Priority" if x == True else None )
    startWithPandas["label_3"] = startWithPandas["label_3"].apply(lambda x: "Feature" if x == True else None )
    startWithPandas["label_4"] = startWithPandas["label_4"].apply(lambda x: "Idea" if x == True else None )
    startWithPandas["label_5"] = startWithPandas["label_5"].apply(lambda x: "Request" if x == True else None )
    startWithPandas["label_6"] = startWithPandas["label_6"].apply(lambda x: "Story" if x == True else None )
    startWithPandas["label_7"] = startWithPandas["label_7"].apply(lambda x: "Low Priority" if x == True else None )
    startWithPandas["Labels"] = startWithPandas[["label_1", "label_2", "label_3", "label_4", "label_5", "label_6", "label_7"]].apply(filterColumn,axis=1)
    return startWithPandas.drop(columns=["label_1", "label_2", "label_3", "label_4", "label_5", "label_6", "label_7"])

def parse_airtable_data():
    from airtable import Airtable
    import os, pandas as pd
    base_key = 'app5beEUuaFQatE2T'
    table_name = 'Features &amp;amp; Requests'
    airtable = Airtable(base_key, table_name, api_key=os.environ['AIRTABLE_KEY'])
    res = airtable.get_all(fields=["task.number","task.state","task.short_description","lane"])
    data = []
    for r in res:
        f = r["fields"]
        data.append(
            {"task.number":f["task.number"],
            "task.state":f["task.state"],
            "lane":f["lane"],
            "task.short_description":f["task.short_description"],
            "recordId":r.get("id")
            })

    airtable_data = pd.DataFrame(data)
    return airtable_data

def process_differences(servicenow,airtable_data):
    m = servicenow.merge(airtable_data, on=["task.number","task.state","task.short_description","lane"], how='outer', suffixes=['', '_'], indicator=True)
    differences = m[(m["_merge"]!= "both") ]
    return differences

def upload_to_airtable(differences):
    import os
    from airtable import Airtable
    base_key = 'app5beEUuaFQatE2T'
    table_name = 'Features &amp;amp; Requests'
    airtable = Airtable(base_key, table_name, api_key=os.environ['AIRTABLE_KEY'])
    unique_ids = set(differences["task.number"].values)

    for item in unique_ids:
        row = differences[differences["task.number"] == item]
        if len(row) == 2:
            recordId = row[row["recordId"].notnull()]["recordId"].values[0]
            f = row[~row["recordId"].notnull()]
            fields = f.to_dict(orient='records')[0]
            del fields["recordId"]
            del fields["_merge"]
            if len(fields.get("Labels")) == 1 and fields.get("Labels")[0] == "":
                del fields["Labels"]
            airtable.update(recordId,fields = fields)
        else:
            fields = row.to_dict(orient='records')[0]
            del fields["recordId"]
            del fields["_merge"]
            if isinstance(object, list):
                fields["Labels"]=list(filter(lambda x:x!="",fields["Labels"]))
            else:
                del fields["Labels"]
            airtable.insert(fields)


def upload_airtable_data(event, context):
    """Triggered by a change to a Cloud Storage bucket.
    Args:
         event (dict): Event payload.
         context (google.cloud.functions.Context): Metadata for the event.
    """
    file = event

    print(f"Processing file: {file['name']}.")
    if file['name'] and file['name'].startswith('platform_engineering/'):
        servicenow_frame = parse_report(file)
        airtable_frame = parse_airtable_data()
        diff = process_differences(servicenow_frame,airtable_frame)
        upload_to_airtable(diff)
    print(f"Processing Complete.")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>spreadsheets</category>
      <category>servicenow</category>
      <category>data</category>
      <category>googlecloud</category>
    </item>
  </channel>
</rss>
