Reflections on GitHub Copilot

Caveat

I do not use GitHub Copilot or similar products at work, and I caution anyone else about using such technology at work without proper guidance by senior leadership.

I am reporting my experiences in the context of ‘recreational programming,’ in a personal open source laboratory context, in particular over the weekend on my personal time.

We live in interesting times where powerful new technology has burst into our lives. Technology such as Copilot and ChatGPT is both exciting and alarming, with profound implications on not only our personal lives, but on society as well.

Laboratory Context

I have various ‘laboratories’ in my personal GitHub account where I like to experiment with technology and ideas, to learn, assess, and reflect on deeper meanings.

Loom

One of my technical passions is Java Project Loom coming in the next Java Long Term Support (LTS) release JEP 444: Virtual Threads Arrive in JDK 21, Ushering a New Era of Concurrency.

Nima

Helidon 4.0

Oracle Helidon taps virtual threads for ‘pure performance’ is a good introduction to Helidon Version 4.0.0 coming soon.

Helidon is a cloud-native, open‑source set of Java libraries for writing microservices that run on a fast web core powered by Netty.

Helidon Níma is the first Java microservices framework based on virtual threads.

It combines an easy-to-use programming model with outstanding performance.

In particular, Helidon Version 4 introduces a ‘blocking’ library in contrast to its established ‘reactive’ library. The lesson here is that the new blocking API offers similar or better performance than the reactive API, but with much less cognitive load to the software developer, and I believe better code quality, reliability, robustness, etc.

Reactive Programming

I have years of experience with Reactive programming, and while it has been a very effective technology for exploiting concurrency to improve performance, it has cost us a lot in terms of complexity and contortion in our programming skills and results.

Hussein Yoga performing a combination of a cheststand and dislocation

The hope of Loom, Structured Programming, Helidon Nima, etc. is to improve the sanity of our web applications development, without sacrificing performance.

Kotlin

The Kotlin (programming language) is a response to the Scala (programming_language) where it is said that Kotlin has 80% the power of Scala with only 20% of the features.

See also my article on KVision, where Kotlin can be used for front-end development of web pages, where Kotlin code is compiled into Javascript code. My evil plan it to concoct a purely Kotlin full-stack web application. :smiling_imp:

GitLab Copilot

Costing only $100.00 per year, this is a bargain. I don’t have extensive experience with Copilot yet, but I am quickly forming high-level impressions.

Pros

  • Copilot does a surprisingly good job of recommending useful code, including documentation.
    • In one case, I was writing some ‘index.html’ text embedded into my code, and Copilot was recommending text based on prior code comments I had written.
  • As someone who diligently writes code comments, I may be experiencing an aspect of Copilot that others may not or will not.
    • Copilot is very much designed to exploit code comments, and I hope it encourages many programmers to get into the habit of writing code commments.
  • Copilot seems to work as well with Kotlin as with Java.
    • In conjunction with IntelliJ’s ability to translate Java code into Kotlin code, this can be a huge improvement in productivity.

Cons

  • The combination of Copilot and IntelliJ editor quirks sometimes makes me insane, frustrated, and even angry.
    • The term “too many cooks in the kitchen” comes to mind when IntelliJ’s editor, spell checker, Copilot, and I are all trying to edit the same text concurrently. :crazy_face: :face_with_symbols_over_mouth: :scream:
  • The power of Copilot and related tooling can lead us down a pathelogical trail, drunk with power, that can lead to unintended consequences…
    • Yes, I had to catch myself going down that pathelogical trail and come to my senses.

Anecdotes

Copying and pasting code from helidon-nima-example I consistently let IntelliJ IDEA translate Java to Kotlin. Often the results were surprising, in that Kotlin is a much more expressive language than Java. I was later able to improve the aesthetics of the code… but while the code can look very pretty, it can be hard to see what is really going on. While the code works as intended, I am still trying to fathom what is really going on well enough to explain it in code comments.

While cleaning up the IntelliJ translations, Copilot was very effective in this, typically completing what I was trying to do.

Original Java

@Override
 public void routing(HttpRules httpRules) { 
    httpRules.get("/one", this::one) 
            .get("/sequence", this::sequence) 
            .get("/parallel", this::parallel) 
            .get("/sleep", this::sleep)
             .put("/create", this::create) 
            .put("/create-async", this::create); 
}

IntelliJ Kotlin Translation

override fun routing(httpRules: HttpRules) { 
    httpRules["/one", Handler { req: ServerRequest?, res: ServerResponse? ->
         one( 
            req!!, res!! 
        ) 
    }]["/sequence", Handler { req: ServerRequest?, res: ServerResponse? ->         this.sequence(             req!!, res!!         )     }]["/parallel", Handler { req: ServerRequest?, res: ServerResponse? -> 
        parallel( 
            req!!, res!! 
        )
     }]["/sleep", Handler { req: ServerRequest?, res: ServerResponse? -> 
        sleep( 
            req!!, res!!
         )
     }]  
       .put("/create", 
            Handler { req: ServerRequest?, res: ServerResponse? ->
                 this.create( 
                    req, 
                    res 
                ) 
            }) 
        .put("/create-async", 
            Handler { req: ServerRequest?, res: ServerResponse? -> 
                this.create( 
                    req, 
                    res
                 ) 
            }) 
}

Wow… talk about ugly… but it works…

One improvement is to replace stuff like

Handler { req: ServerRequest?, res: ServerResponse? ->
         one( 
            req!!, res!! 
        ) 
}

With a function declaration. For example, I started typing

val one =

and Copilot generated

val one = Handler { req: ServerRequest?, res: ServerResponse? -> 
    one(req!!, res!!) 
}

so I could further improve my code as

override fun routing(httpRules: HttpRules) { 
    httpRules[
         "/one", one][ 
        "/sequence", sequence][
         "/parallel", parallel][
         "/sleep", sleep][ 
        .put("/create", create) 
        .put("/create-async", createAsync)
}

then I could paste the body of the Kotlin functions into the closures

val one = Handler { req: ServerRequest?, res: ServerResponse? -> 
    val response: String =
        io.examples.helidon.nima.BlockingService.callRemote(io.examples.helidon.nima.BlockingService.client()) 
    res.send(response)
}

eliminating an unnecessary level of indirection.

No… Generative Large Language Models are not going to put programmers out of work, but they can help us become more productive.

Probably it is better for the final code to look like

override fun routing(httpRules: HttpRules) { 
    httpRules
         .get("/one", one)
        .get("/sequence", sequence)
         .get("/parallel", parallel)
         .get("/sleep", sleep)
        .put("/create", create) 
        .put("/create-async", createAsync)
}

as the other form is very clever use of Kotlin features, and the Nima API design, it is not at all intuitive and would be an on-boarding nightmare. Indeed, I was so focused on the cleverness of IntelliJ, Copilot, and my newfound powers, I was heading down the path of producing overly concise code that hides the simple mechanics of what is really going on, or what should really be going on.

I would say, that one danger of Copilot and similar technology, is that it will enable clever programmers to be even more prolific in their cleverness. :exploding_head:

Putting on my political hat for a moment, Copilot is like a gun, which is a useful tool when you are hunting game, especially when you live in a hunter/gatherer culture that relies on hunting game, but when the gun is an AR-15, then the consequences can be profound.

I bring up such a violent notion because I wonder when people learn to use Copilot for hacking, phishing, and other nefarious goals and objectives, how can we defend ourselves from such corrupt intent? :thinking:

Personally, as a Computing Professional, I believe it is our ethical and moral duty to comprehend the dangerous consequences of our craft, and prepare for them.

With great power comes great responsibility

1 Like