What it was like to spend a month using GitHub Copilot and why I plan to not use it (next month)
Tags: githubcopilot, ai, coding, productivity
Published: 2023-06-15 13:57:57

You're probably already familiar with [GitHub Copilot](https://github.com/features/copilot/?ref=heydesigner): a tool created by Microsoft to help developers by providing real-time code suggestions. While tools like ChatGPT are also capable of generating code, GitHub Copilot takes advantage of tight integration with the code editor.

There are several ways to use it: you can write a feature as a comment and the tool is capable of generating a function, method, or even a complete class to contemplate what you described. Or you can type the name of a function or method and let the autocomplete try to predict the corresponding code. Or you can just use it as a slightly "smarter" autocomplete for smaller parts of your code.

The first way (using only comments) I don't trust and would never recommend. The second, writing just the name of the function or method, usually works surprisingly well for snippets of code with reduced and closed scope, such as creating a function that will receive a data structure and do some simple transformation or filter operations. The last way, as a more "efficient" autocomplete, had mixed results. Sometimes it hit the jackpot! 🎯 But it wasn't uncommon to need adjustments or even come up with a solution that was just plain wrong.

Throughout May 2023, I used this tool to program in [Clojure](https://clojure.org) and [Elm](https://elm-lang.org). In this article, I tell you a little about what I thought of this experience.

# Why I decided to give it a try

In April 2023 Kent Beck posted [the following message on Twitter](https://twitter.com/KentBeck/status/1648413998025707520?s=20):

![Kent Beck: I’ve been reluctant to try ChatGPT. Today I got over that reluctance. Now I understand why I was reluctant. The value of 90% of my skills just dropped to $0. The leverage for the remaining 10% went up 1000x. I need to recalibrate.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fho2oytlo8iock53258j.png)

This twit was so successful that he ended up [writing a post](https://tidyfirst.substack.com/p/90-of-my-skills-are-now-worth-0) to better explain his opinion.

For those who don't know him, Kent Beck is one of my favorite technical book authors, having written such books as [eXtreme Programming Explained](https://www.goodreads.com/book/show/67833.Extreme_Programming_Explained), [Planning Extreme Programming ](https://www.goodreads.com/book/show/67839.Planning_Extreme_Programming), [Test-Driven Development: By Example](https://www.goodreads.com/book/show/387190.Test_Driven_Development), among [others](https://www.goodreads.com/author/list/25211.Kent_Beck).

In April 2023 I was also reluctant to try ChatGPT, but after reading this twit, I immediately opened it and started testing it. It soon became clear that I was facing something very different from what I had experienced before. I was very impressed and spent hours doing various experiments, including code generation.

After a day of testing ChatGPT, one thing stuck in my head: if it manages to generate codes so well when it wasn't even created for this purpose, imagine what it must be like to use GitHub Copilot!

To my joy, I remembered that the company I work for was selecting a group of people to test this tool in the following month, in partnership with Microsoft. I ran and managed to include myself in this team. Couldn't wait to get started! 🎉

# First impressions

Initially, I didn't know (and, I confess, I still don't know) exactly how to use this technology. As I reported at the beginning of the article, there is no formula, and each person can adapt to their way of working. But it was very impressive. I started small, writing functions in Clojure (backend) and Elm (frontend) in well-defined contexts, and it felt like it could read my mind! I wrote the name of the function and... the implementation appeared! 🧙🪄

Looked like facing a great revolution and that the way I would program would never be the same. I **felt** more productive. As if I didn't waste more time with boilerplates and repetitive codes in general. Now I could focus on what matters!

But little by little I noticed some not-so-cool things, both in the generated code and in my behavior.

# Confusing and non-standard codes

I used Copilot in a web application that had been in production for over 6 months, with many screens and services that already had a clear design pattern. And while Copilot can adapt, there are limitations. Suddenly I began to notice that the construction of some functions was quite odd, adopting mechanisms that I didn't even know about.

When I realized that, I tried to see it as a good thing: _Wow! I didn't know it was possible to do that. How cool, it's helping me in learning new things!_ And it was true. I learned new things because of Copilot. And I could of course reject those suggestions and rewrite them as I wanted.

On the other hand, it's very easy to get carried away. Gradually I began to feel more and more comfortable in accepting the proposed suggestions. I analyzed the solution, but less judiciously. In some moments it even generated codes that I didn't fully understand. It wasn't necessarily complex but used some language tricks I didn't understand. In some cases, I did some testing (both automated and manual) and it worked. What should I do in these situations? I have a fully working code, but I don't quite understand how it works. I even accepted the solution a few times, saying to myself that I would come back later to study that part (but, of course, I never had the time and inclination to do so).

At the same time, I felt that the fact that I was able to write code more quickly was worth it.

Could this be the future? Writing code that we don't quite understand? Perhaps I should create more automated tests and trust that the code is correct as the tests are passing? But wouldn't I use this same technology to write the tests? Do I want to program this way? 🤔

Many questions started running through my head. Until the worst happened.

# Oops, I put a bug in production and didn't even notice! 🐛

When I'm programming in Elm, it's not uncommon to start writing not very organized code, to test my ideas. Once I have the screen ready, displaying everything the way I want, I reorganize the code. This usually works great, in part because it's a statically typed language with an amazing compiler. I'm able to change the code and let the compiler guide me, and usually when the code compiles, my application still behaves as expected.

I'm a big fan of automated tests, but for this part of the application, there were no complex rules. All I had to do was make a REST call to the backend and display some formatted information on the screen. So my test coverage was low.

And it was during one of these modifications that something strange happened.

## The problem I was solving

I won't go into too many business details, but I was working on a new functionality for an internal support web page (similar to a dashboard), where it's possible to consult various reports about a given system. This system provides a series of services to other third-party systems, and I needed to expose the usage metrics of these services through a page, with tables, graphs, etc.

Internally, there is an identification table for these third-party systems, containing (among other things) an identifier (an integer) and a description (a string).

To do this, I built a new endpoint in the backend that returned a _json_ containing 2 lists: one of them was a simple key-value, containing the third-party system code and its respective name/description. The other list contained some metrics about the accesses made by these systems, grouped by month.

In a simplified form, the _json_ returned was something like this:

```json
{
    "hits": [
        {
            "monthYear": 1633057200000, // date in POSIX format
            "consumerSystemCode": 10,
            "quantity": 61
        },
        {
            "monthYear": 1635735600000,
            "consumerSystemCode": 10,
            "quantity": 220
        },
        {
            "monthYear": 1635735600000,
            "consumerSystemCode": 11,
            "quantity": 34032
        },
        {
            "monthYear": 1638327600000,
            "consumerSystemCode": 11,
            "quantity": 179301
        }
    ],

    "consumerSystemCodes": [
        {
            "id": 10,
            "decription": "XPTO Systen"
        },
        {
            "id": 11,
            "decription": "Foo System"
        },
        {
            "id": 12,
            "decription": "Another System"
        } 
    ]
}
```

Note that in this example the first list contains information about systems with identifiers 10 and 11, while the list of `consumerSystemCodes` contains identifiers with numbers 10, 11, and **12**. This is important to understand what went wrong in my code.

## How I solved the problem (without Copilot's help)

I wasn't using Copilot yet while building the first iteration of this screen. It contained a general report, with a summary gathering all systems, followed by a more detailed report, separated by sessions (one for each system).

To implement this, it is necessary to start from one of two lists: `hits` or `consumerSystemCodes`. A more distracted person might start from `consumerSystemCodes`, since it seems to be easier, after all, one could just make a _map_ on top of it and generate a session on the screen for each system. Or, even better, could generate some intermediate data structure first, so it can be sorted and transformed however necessary before moving on to the view layer.

After reflecting a bit, I chose to start with the `hits` list, for two main reasons:

1- There are no restrictions that make it impossible for the `hits` list to have an entry with an `id` that is not present in the `consumerSystemCodes` list. And I wanted to be sure that all entries would be displayed on the screen and, in case this unexpected situation happens, that a new session was created on the screen, with the title "Unknown System (ID: x)" (one session for each unknown identifier).

2- And the opposite can also occur: the list `consumerSystemCodes` may contain systems that do not have any data in the list `hits`, so it would be displaying sessions with empty information.

There are several ways to get around these problems. The way I chose to do it was to start processing with the `hits` list.

So I started with a code that, I confess, was more complex than I initially imagined. Had to create some helper functions to get the needed data, but in the end, it worked fine.

## Rearranging with the help of Copilot

I was eager to see the results on the screen and the code reflected that: it was messy and disorganized. But luckily it had been written in Elm! And the compiler was there, ready to help me with the reorganization. And this time I was already using Copilot.

When I started to change the design of the code, Copilot tried to implement it in the simplest way possible, through the list `consumerSystemCodes`. My mind was no longer focused on the potential problems of this path and... I let the Copilot guide me. Suddenly I was smiling, deleting various auxiliary functions that were "no longer needed". And, unfortunately, there were no automated tests to help me with this part of the redesign. Then I opened the system, pointing to my development environment, and... all right! All reports continued to appear as expected.

I was so excited! I remember texting a colleague to celebrate how Copilot had helped me drastically reduce the complexity of my code! 🥳

Time to _push_ and let the _pipeline_ publish to production.

As soon as I opened the page in production, I realized that something was wrong. 🪲🐞🪳 Multiple sessions with empty information! In development, this did not happen, since the database content was different. Lucky for me, although I was in the production environment, I hadn't made the link available in the menu yet, so no one else had access to this page and I had time to better analyze what was happening. My first reaction was to create a filter to remove empty entries. But that didn't happen before! What has changed? That's when I realized the source of the problem. And it wasn't just filtering the empty entries, since doing just that wouldn't solve problem 1 that I mentioned above.

Once again I needed to change the code, this time returning to a logic closer to the original implementation. And once again, Copilot insisted on starting the process through the `consumerSystemCodes` list. All autocompletes took me the wrong way and suddenly, I was almost re-implementing the logic in the wrong way again! Even knowing what needed to be done, it was hard not to let Copilot lead me down the wrong path. 🤦

After some fight, I won! But this battle left a bitter taste in my mouth. And spent hours thinking: **would I have included this bug if not for Copilot?** Probably not. Could I have avoided this through more automated testing? Probably yes. What if I was doing _mob_ or _pair programming_? Maybe someone would spot the problem. And would an asynchronous code review catch this situation? I think it's unlikely, but maybe.

But this was just one of the scenarios where something like this happened. There weren't many and this was the most annoying, but they were enough to start causing me some discomfort.

## More weird code

At some point, I was reviewing the code and noticed something VERY strange: a function was returning an anonymous function, without any reason why. I don't know exactly when that happened, but my hypothesis is that I had created a new function and forgotten to include one of the parameters to do what I needed. Any developer would notice this right away and change the function signature, but Copilot is not able to **change** the code, it only **suggests new code**. To solve the problem, I think it created an anonymous function with the missing parameter! The rest of the code was as expected and did the right thing, which is perhaps the reason I accepted the suggestion without realizing the existence of the anonymous function. 😳

I wondered what it would be like if someone else had encountered this problem in my code! What would they think? That made no sense! Even more so in Elm, where every function has [currying](https://pt.wikipedia.org/wiki/Currying) by default! If it weren't my code, maybe I'd even be afraid to change it, after all, no human being would write something like that without having a good reason. I could spend hours looking at that lines without realizing why it was returning an anonymous function.

# Trust or distrust autocomplete?

After a while, I realized that even though I was quite skeptical at first and understood the limitations of an AI-assisted tool, it got it right enough times to slowly gain my trust. And that needed to change.

Ever since I started working professionally as a software developer, I've been using some kind of code **autocomplete** tool. In general, simple things like the name of a function or method. One of the advantages of autocompletes in IDEs and code editors is that **I can trust them**. If my IDE is telling me that this object has a certain method or if a certain module has a certain function, I've learned to believe this information. When I don't remember if the function is called `getTaxpayerStatus` or `retrieveTaxpayerStatus` and the first option appears in my editor, I **know** that this is the correct name and **trust** it.

But from the moment that my autocomplete starts to **hallucinate** and **invent** names for functions or methods, I need to be more cautious. Of course, my IDE (or code editor) autocomplete and Copilot autocomplete are visually quite different, but I need to "turn off" a switch in my brain, which is used to trusting all autocomplete. Now I always have to ask myself: is this based on **facts** or was this generated by a plugin that is just making things up based on **probability** and **statistics**?

# How to proceed?

Copilot positively surprised me in many ways. I studied AI during [my master's degree](https://dspace.mackenzie.br/handle/10899/24422) and didn't expect that it would be possible to have such an advanced tool so soon.

And in the first days it was just joy, but after a month and some non-trivial to detect bugs, using this tool started to generate some stress and anxiety. And something that should have lessened my cognitive load has started to increase it.

I started to distrust everything that was generated and that pleasant feeling of the first days become less common.

This doesn't mean that I think GitHub Copilot is bad or that I don't recommend it. On the contrary. It was a really cool experience! And I recommend that every developer try it out and draw their conclusions. I think it's likely that we're moving towards a time when this type of technology will become part of (almost) every developer's day-to-day. Whether this will be good or bad, only time will tell.

But still, I chose not to use it anymore. At least for a while.

Although I didn't do any measurements, turning this tool off seems to have slowed me down. Writing a filter, simple parsers, and boilerplates, in general, have become more onerous processes. But this is not necessarily a bad thing. Taking time to reflect on what I'm doing has taken a weight off my shoulders.

Copilot's slogan is: _"Your AI pair programmer"_. And yes, it felt like there was a person programming with me all the time - but an annoying one, who wouldn't shut up for a second. 📣 It was like doing pair programming, but with someone who has no idea what it means to work this way. Who understands absolutely nothing about the problem I want to solve. And when something goes wrong, blames me.

In the first hours without Copilot I really missed it! I was already used to the idea of ​​typing the name of a function and seeing the code being generated. But soon readjusted to the way I programmed before. And felt more in control. More relaxed.

I still don't know if (or when) I'll ever use a technology like this again, but for now, I'm fine without it. When I need something very specific, I talk to ChatGPT and that has been enough for me. 

---

And what about you? Have you tried Copilot yet? What are your thoughts? Leave your comments below!

---

Did you like this text? Check out my other articles at: [https://segunda.tech/tags/english](https://segunda.tech/tags/english) and follow me on [Twitter](https://twitter.com/marciofrayze) and [Blue Sky](https://staging.bsky.app/profile/segunda.tech).