12 ways to make ChatGPT your personal Junior Developer (with examples)

Supercharging developer productivity with AI

OpenAI released its newest version of its language generation model a few weeks ago and took many by surprise at how advanced it is. Not only does it easily create works of text-based art out of thin air like writing articles, writing songs, writing mean rap battles, writing dialogues, writing movie scripts and stand-up comedy jokes in all tones and styles imaginable, but it also provides what some might deem the day to day bread and butter of junior developers. Here are 10 ways in which ChatGPT can make you a more productive developer by taking tedious tasks off your hands.

Disclaimer: the output produced by ChatGPT has to be checked and can not be blindly copy&pasted. You may only get 80% of the work automated.

1) Code out functions

When working as a software engineer or software architect you come across occasions where you lay out the source code structure, pre-plan the classes and functions and work with what imaginary results they need to deliver, leaving the actual coding for later. Now, you can leave it for your unpaid assistant. Let's assume you brought up the need to calculate the average price of purchases in a financing project. Instead of trying to remember the algorithm in detail, looking through the internet for examples or searching in old code bases where it might have been implemented once, simply ask:

As the software engineer, you have determined that the variables allPrices and allVolumes are ready to use, and you would like the have the average price. Instead of sending this on slack or teams to someone who may or may not do it in the next 10 seconds, chatGPT is happy to take that work off your hands. The response is this:

public static decimal GetAveragePrice(decimal[] allPrices, decimal[] allVolumes)
{
    // Check that the input arrays have the same length
    if (allPrices.Length != allVolumes.Length)
    {
        throw new ArgumentException("The input arrays must have the same length.");
    }

    decimal totalPrice = 0;
    decimal totalVolume = 0;

    // Calculate the total price and total volume
    for (int i = 0; i < allPrices.Length; i++)
    {
        var price = allPrices[i];
        var volume = allVolumes[i];

        totalPrice += price * volume;
        totalVolume += volume;
    }

    // Calculate the average price
    if (totalVolume == 0) return 0;
    decimal averagePrice = totalPrice / totalVolume;

    return averagePrice;
}

The AI understood what you want from the limited information you gave. You can also specify the programming language of your choice.

2) Create test cases

Test cases are an important aspect of software development, especially when using CI/DI pipelines. But having good test coverage can be time-consuming. So why not ask the AI about it?

And the result is:

Done is the [TestMethod], even with edge cases. This is also a good reminder that the output needs to be double-checked. As the observative reader might now say "Wait a minute, the first expected result is not 30": yes, right. That is something that would have come up when testing the result. Luckily, the AI is open for criticism:

3) Give performance hints

Have a look at this old code of mine:

static public (double? upperBands, double? lowerBands) GetBoilingerBands(IEnumerable<Quote> history)
        {
            var bbs = Indicator.GetBollingerBands(history).ToList();
            bbs = bbs.OrderByDescending(m => m.Date).ToList();
            var current = bbs.First();
            return (upperBands: current.UpperBand, lowerBands: current.LowerBand);
        }

This code is using the incredible stock indicator library by Dave Skender. The code calculates some info on a chart pattern and returns 2 information from the most recent one.

Might there be room for improvement? let's ask

Using Shift+Enter you can add a new line in the current UI of ChatGPT and paste things, like code.

And optimizations he has:

Even though he has no idea about all the actual implementation of the included datatypes like "Quote" or "Indicator" and all the lazy "var" use of me, the still comes up with info. And let's not stop here.

And the output is:

He even keeps my spelling mistake in the name of the function and still gets the concept (It's BollingerBands, not BoilingerBands). Incredible.

And not only does he deliver a commented optimization, but he also adds an explanation afterwards. Quote:

This optimized version of the GetBoilingerBands function converts the history data to an array to avoid the overhead of enumeration and uses a parallel processing technique to calculate the Bollinger bands. It also sorts the Bollinger bands in descending order by date and returns the current upper and lower bands.

4) Implement algorithms and concepts from scratch

A few years ago when the predecessors of chatGPT were still young, there was excitement about genetic algorithms. Genetic algorithms aim at mimicking a brain, a very small brain. Many languages got their own implementation, with c# being no exception. 2 of the most advanced ones are SharpNeat by Colin Green and Genetic Sharp by the Brazilian software developer Diego Giacomelli. Both projects have different approaches and use cases, but both share the underlying "NEAT" concept. Lets find out what that is:

Sounds pretty complicated. Wouldn't it be nice to have a source code for this without having to start from total scratch?

And it does just that. (The source code produced goes on for many pages, I will not post everything here for brevity.) Pretty NEAT, right?

One more example on this topic: if you are like me and you gain a full understanding of a concept only after seeing it implemented in code, chatGPT has something to teach. Going back to the earlier topic of financial indicators, how does an RSI work?

Result given by chatGPT:

using System;
using System.Collections.Generic;

namespace RsiExample
{
    public static class Rsi
    {
        public static double Calculate(List<double> prices, int period)
        {
            // Validate the input
            if (prices.Count < period)
            {
                throw new ArgumentException("Not enough prices for the given period");
            }

            // Calculate the average gain and average loss over the given period
            double gainSum = 0, lossSum = 0;
            for (int i = 1; i < period; i++)
            {
                double diff = prices[i] - prices[i - 1];
                if (diff > 0)
                {
                    gainSum += diff;
                }
                else if (diff < 0)
                {
                    lossSum -= diff;
                }
            }
            double avgGain = gainSum / period;
            double avgLoss = lossSum / period;

            // Calculate the relative strength
            double rs = avgGain / avgLoss;

            // Calculate the RSI
            double rsi = 100 - (100 / (1 + rs));

            return rsi;
        }
    }
}

5) Help with Clean Coding

Clean coding is like brushing teeth 3-4 times a day: you know you are supposed to do it, and you do it when someone is monitoring you, but if no one else has a stake in the result it might be forgotten.

But what if there is help, both for scholars learning the concept of clean code, and those who want it implemented without putting too much effort into it?

This is a function used in parsing the result of Azure Form Recognizer, which parses PDFs.

And as expected, it does just that

But wait, there is more!

The already refactored code now also got comments on it.

6) Remind you of the approach you know but forgot about

Developers rarely write the same code twice, but sometimes the requirements tingle a hidden memory somewhere in the brain. "I implemented this already, didn't I? How did I do it? where is that code?".

Fear not, when you can describe it, you can have it made for you. Let's assume a requirement comes up to get the column content of a specific SharePoint Row. Of course, we should try to use state-of-the-art authentication and the newest possible interface for the data.

Having this info in mind, we can start the google journey of having many tabs open, trying to figure out who gives up-to-date answers, putting the results together and hopefully having it working, or we can ask chatGPT:

using Microsoft.Graph;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Replace these values with your own client ID and secret.
            // You can obtain these by creating an app in the Azure portal: https://portal.azure.com
            string clientId = "your-client-id";
            string clientSecret = "your-client-secret";

            // Replace this with the ID of the SharePoint site that contains your list.
            string siteId = "your-site-id";

            // Replace this with the name of your list.
            string listName = "datalist1";

            // Replace this with the title of the list item you want to read.
            string itemTitle = "item1";

            // Replace this with the name of the column you want to read.
            string columnName = "Column1";

            // Initialize the Graph client.
            GraphServiceClient graphClient = GetAuthenticatedGraphClient(clientId, clientSecret);

            // Get the list.
            List list = GetList(graphClient, siteId, listName).Result;

            // Get the list item.
            ListItem listItem = GetListItem(graphClient, list, itemTitle).Result;

            // Get the value of the specified column.
            object columnValue = listItem[columnName];

            Console.WriteLine($"Column '{columnName}' has value: {columnValue}");
        }

        private static async Task<GraphServiceClient> GetAuthenticatedGraphClient(string clientId, string clientSecret)
        {
            var app = ConfidentialClientApplicationBuilder.Create(clientId)
                .WithClientSecret(clientSecret)
                .Build();
            var scopes = new string[] { "https://graph.microsoft.com/.default" };
            var authResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
            var accessToken = authResult.AccessToken;

            GraphServiceClient graphClient = new GraphServiceClient(
                new DelegateAuthenticationProvider(
                    (requestMessage) =>
                    {
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
                        return Task.CompletedTask;
                    }));
            return graphClient;
        }

        private static async Task<List> GetList(GraphServiceClient graphClient, string siteId, string listName)
        {
            var lists = await graphClient.Sites[siteId].Lists
                .Request()
                .Filter($"startswith(displayName, '{listName}')")
                .GetAsync();
            return lists.FirstOrDefault();
        }

        private static async Task<ListItem> GetListItem(GraphServiceClient graphClient, List list, string itemTitle)
        {
            var items = await graphClient.Sites[list.SiteId].Lists[list.Id].Items
                .Request()
                .Filter($"startswith(fields.Title, '{itemTitle}')")
                .GetAsync();
            return items.FirstOrDefault();
        }

(some code was left out for brevity).

Not only did chatGPT adhere to the wish for specific names of lists and items, but it also already did the nitty-gritty work on initializing a Graph Client and preparing the Filter criteria, which on its own would have been some Google searches.

7) Find errors in the code

This one is tricky and needs to be used with even more caution, but a hint about a problem is better than no hint about a problem. Let's make some problematic code (read at your own risk, you have been warned):

 public string fixme(decimal param1, int param2)
        {
            if((bool)(param1 = param2))
            {
                myText = "param1 is " param2;
            }
            for(int i = 1; i < 1000; i++)
            {
                myText = myText;
            }
        }

What could possibly be done about this?

The result does not fail to impress:

This is far more advanced than compile-time error handling. ChatGPT understood the concept of the code, how to make it compile, what is unnecessary and which error handling needs to be done.

8) Explain the Code to the management

While micro-managing developers are poison to their productivity there could also be a simple curiosity-driven interest in the works of a keyboard magician. Let this code be the subject of curiosity, as it might be the business critical part whose functionality might need to end up explained in a PowerPoint presentation:

public async Task Run([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"C# Timer TriggerWebhooks executed at: {DateTime.Now}");
            DateTime lastChecked =await _tableStorageService.GetLastChecked();
            var newestEvents =await _mowasService.GetEventsSince(lastChecked);

            List<Task<DispatchWebhookResult>> webhookCalls = new List<Task<DispatchWebhookResult>>();
            //accessing memory is way cheaper and faster than accessing the database one at a time
            Dictionary<PolygonPoint, WebhookTableEntry> positionToWebhooks = _tableStorageService.GetPositionToWebhookDictionary();
            foreach(var warning in newestEvents)
            {
                List<List<PolygonPoint>> polygonsInWarning = MowasParsingHelper.GetPolygonListFromWarning(warning);

                foreach(var positionToWebhook in positionToWebhooks)
                {
                    var gpsPositionOfWebhook = positionToWebhook.Key;
                    var webhookData = positionToWebhook.Value;

                    bool webhookIsInsideWarningArea = PolygonCalculationHelper.IsInAnyPolygon(gpsPositionOfWebhook, polygonsInWarning);

                    if (webhookIsInsideWarningArea)
                    {
                       var call =  _mowasService.DispatchWebhook(webhookData, warning);
                        webhookCalls.Add(call);                       
                    }
                }
            }

         await   Task.WhenAll(webhookCalls.ToArray());
           foreach(var call in webhookCalls)
            {
                var callResult = call.Result;
              _tableStorageService.UpdateWebhookStrikes(callResult.webhookData, callResult.Success);
            }

        await    _tableStorageService.SetLastChecked(DateTime.Now);
        }

This is a regularly triggered check of webhooks that might need to be triggered, delivering information to outside systems.

The result is long, interesting, correct and simple:

This code is a C# function that is designed to be run on a regular schedule (every 5 minutes, in this case). It performs the following tasks:

  1. It logs the current time to a log file.

  2. It retrieves the last time the function was run from a storage service.

  3. It retrieves a list of events that have occurred since the last time the function was run from a web service.

  4. It creates an empty list of tasks that will be used to make web service calls.

  5. It retrieves a list of webhooks and their associated GPS positions from a storage service.

  6. It loops through each event in the list of events that have occurred since the last time the function was run.

  7. For each event, it retrieves a list of polygons that define the area affected by the event.

  8. It loops through each webhook in the list of webhooks and their associated GPS positions.

  9. For each webhook, it determines whether the GPS position of the webhook is inside any of the polygons associated with the event.

  10. If the webhook's GPS position is inside one of the polygons, it adds a task to the list of tasks that makes a web service call to dispatch the webhook with the event data.

  11. It waits for all of the tasks in the list to complete.

  12. It updates the storage service with the results of the web service calls.

  13. It updates the storage service with the current time.

This code is used to process events and send webhooks to users based on the location of their webhooks relative to the area affected by the events. It does this by retrieving events from a web service, comparing the location of the webhooks to the area affected by the events, and making web service calls to dispatch the webhooks with the event data if the webhooks are in the affected area. The function is designed to run on a regular schedule, so that it can check for new events and send updates to users as needed.

9) Documentation

Apart from "add comments to my code" and "make my code clean" earlier, which can already be considered documentation from developers for developers, there might be a requirement to have documentation outside the code, explaining the code to devs.

Staying in the theme of webhooks, this code shall be documented:

internal async Task<RegisterWebhookResponse> AddWebhookAsync(string webhookUrl, float gpsNorth, float gpsEast)
        {
            Uri uri = new Uri(webhookUrl);
            string urlHash = Hash(webhookUrl.ToLower());
            await _webhooksTable.CreateIfNotExistsAsync();
            var existingRow = await _webhooksTable.GetEntityAsync<WebhookTableEntry>(uri.Host, urlHash);
            if (existingRow != null && existingRow.Value != null)
            {
                return new RegisterWebhookResponse { Success = false, Message = "Webhook already registered" };
            }

            await _webhooksTable.AddEntityAsync(new WebhookTableEntry
            {
                PartitionKey = uri.Host,
                RowKey = urlHash,
                Url = webhookUrl,
                LastUpdate = DateTime.MinValue,
                StrikeOut = 0,
                Timestamp = DateTime.Now,
                gpsEast = gpsEast,
                gpsNorth = gpsNorth
            });

            return new RegisterWebhookResponse { Success = true, Message = "Webhook registered" };
        }

And the result is ready to be copied to whatever Documentation.docx wants it:

Here is a documentation of the code you provided:

Introduction

The purpose of this code is to register a webhook for a user. It does this by storing the webhook URL, GPS coordinates, and other relevant information in a storage service. The code checks to see if the webhook has already been registered, and returns a response indicating whether the registration was successful.

Inputs and Outputs

Inputs

  • The URL of the webhook to be registered.

  • The GPS coordinates of the webhook.

Outputs

  • A response indicating whether the registration was successful. The response includes a success flag and a message explaining the result.

Procedure

  1. The code constructs a URI object from the webhook URL and calculates a hash of the URL.

  2. It checks if the storage service table for webhooks exists, and creates it if it does not.

  3. It retrieves the webhook from the storage service using the URL's hostname and hash as the partition and row keys.

  4. If the webhook has already been registered, it returns a response indicating that the registration was unsuccessful.

  5. If the webhook has not been registered, it adds a new entry to the storage service table with the webhook URL, GPS coordinates, and other relevant information.

  6. It returns a response indicating that the registration was successful.

Notes

  • The code uses a hash of the webhook URL as the row key in the storage service table. This helps to ensure that the row key is unique and does not exceed the maximum length allowed by the storage service.

  • The code stores the hostname of the webhook URL as the partition key in the storage service table. This helps to improve the performance of queries that filter by hostname.

  • The code stores the date and time that the webhook was registered, as well as a counter for the number of times the webhook has been "struck out" (i.e. failed to deliver an event). This information can be used to track the status of the webhook and take appropriate action if necessary.

10) Help with scripting

Having a good software package is one thing, delivering it to a specific staging system is another. A client might insist on a staging concept with completely separated systems, leaving you to deliver and install for each environment.

The result is what we ask for:

# Import the required PSSession and Credential modules
Import-Module PSSession
Import-Module Credential

# Prompt for the remote system credentials
$cred = Get-Credential

# Create a new PSSession to the remote system using the provided credentials
$session = New-PSSession -ComputerName "Staging01" -Credential $cred

# Copy the zip file to the remote system
Copy-Item -Path "C:\Local\Path\To\ZipFile.zip" -Destination "C:\Remote\Path\To\ZipFile.zip" -ToSession $session

# Unpack the zip file on the remote system
Invoke-Command -Session $session -ScriptBlock {
    Expand-Archive -LiteralPath "C:\Remote\Path\To\ZipFile.zip" -DestinationPath "C:\Remote\Path\To\Unpacked"
}

# Run the install.exe with the -Staging argument on the remote system
Invoke-Command -Session $session -ScriptBlock {
    & "C:\Remote\Path\To\Unpacked\install.exe" -Staging
}

# Close the PSSession
Remove-PSSession $session

Client: "We now need you to cleanup the folder before unzipping the file", they now need us to cleanup the folder before unzipping the file? Okay

# Import the required PSSession and Credential modules
Import-Module PSSession
Import-Module Credential

# Prompt for the remote system credentials
$cred = Get-Credential

# Create a new PSSession to the remote system using the provided credentials
$session = New-PSSession -ComputerName "Staging01" -Credential $cred

# Copy the zip file to the remote system
Copy-Item -Path "C:\Local\Path\To\ZipFile.zip" -Destination "C:\Remote\Path\To\ZipFile.zip" -ToSession $session

# Clean up the unzip folder on the remote system
Invoke-Command -Session $session -ScriptBlock {
    # Check if the unzip folder exists
    if (Test-Path "C:\Remote\Path\To\Unpacked") {
        # If the unzip folder exists, remove it
        Remove-Item "C:\Remote\Path\To\Unpacked" -Recurse -Force
    }
}

# Unpack the zip file on the remote system

[...]

11) Data transformations and extractions

Working with data is probably already step 2 after learning how to print "hello world" in the developer learning journey.

Unless building a huge monolithic software without contact with the outside world there is a good chance that one's software wants to speak with another software on the internet, which might be a web service. JSON is an established form of communication between software systems, especially on the net. What makes 2 systems sure they talk about the same JSON when exchanging it? JSON Schema. What makes JSON Schemas? A developer with too much time on his (or her) hands, a 3rd party website or an in-house hosted openAI instance. Despite security concerns about sending your precious JSON into the internet to some website with unknown owners, you might simply not be a fan of 3rd party cookies and advertisements that are placed into your face while clicking the "make JSON Schema" button. So let's try what OpenAI has to offer us.

Let us have this JSON example taken from JSON.org

{"menu": {
    "header": "SVG Viewer",
    "items": [
        {"id": "Open"},
        {"id": "OpenNew", "label": "Open New"},
        null,
        {"id": "ZoomIn", "label": "Zoom In"},
        {"id": "ZoomOut", "label": "Zoom Out"},
        {"id": "OriginalView", "label": "Original View"},
        null,
        {"id": "Quality"},
        {"id": "Pause"},
        {"id": "Mute"},
        null,
        {"id": "Find", "label": "Find..."},
        {"id": "FindAgain", "label": "Find Again"},
        {"id": "Copy"},
        {"id": "CopyAgain", "label": "Copy Again"},
        {"id": "CopySVG", "label": "Copy SVG"},
        {"id": "ViewSVG", "label": "View SVG"},
        {"id": "ViewSource", "label": "View Source"},
        {"id": "SaveAs", "label": "Save As"},
        null,
        {"id": "Help"},
        {"id": "About", "label": "About Adobe CVG Viewer..."}
   ]
}}

And make a Schema out of it:

The result after not even 10 seconds:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "menu": {
      "type": "object",
      "properties": {
        "header": {
          "type": "string"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            },
            "required": ["id"],
            "additionalProperties": false
          }
        }
      },
      "required": ["header", "items"],
      "additionalProperties": false
    }
  },
  "required": ["menu"],
  "additionalProperties": false
}

Next, let us extract some info from that JSON

On the quest of dipping my toes in python waters, how could I do that?

Nice.

12) Help with writing high stake emails to demanding clients

There is a spectrum of how much care a client needs in order to feel happy and "in the loop". On the work-intensive end of the spectrum might be a client with an increased need for formality. A Mail like this might not leave them feeling sufficiently respected:

Hi Mark,

the project is doing well. It looks like we will stay within the budget, and you do not need to worry. i will call you when there are updates, okay? Then we can schedule a review.

Best,

Florian

Same information, different perception.

Conclusion

OpenAis ChatGPT is a big step for developers. While it might change the baseline of the work done in many industries, I think it is exciting progress toward more independence, self-learning, and ultimately a better experience for IT workers. Given that Microsoft is the main investor of openAI, developers with a Microsoft Stack focus can optimistically look forward to having this support tied into their routines and tools.

Ethical workplace disclaimer: The title says "Junior Developer" to indicate a level of support given. Actual Junior developers need experienced developers not only to give them tedious tasks but to learn from them, share domain knowledge and be included in decision-making to create a healthy, respectful and productive work environment

Did you find this article valuable?

Support Jens Caasen by becoming a sponsor. Any amount is appreciated!