AI has become a polarizing topic of discussion in the 2020s, with growing concerns about the impact of releasing intelligent machines to an unprepared humanity. This fear has been perpetuated by the media repeatedly during the 21st century, and Hollywood has done a great job of instilling dread into the minds of moviegoers since 2001: A Space Odyssey came out in 1968. The movie was a cultural phenomenon, and it has since led to an entire genre of movies about hostile AI such as Terminator, Blade Runner, IRobot, and the Matrix.

However, the state of AI in the real world is much different. While it is difficult to predict which Hollywood film will accurately depict the future, many individuals are worried about the impact of AI on the job market. Factory workers, delivery drivers, and software developers alike are concerned because of AI’s potential to automate portions of their work. In fact, an Evans Data Corporation survey found that nearly one third of developers surveyed are in fear of becoming obsolete due to AI. But is such a significant amount of fear rational? In this article, the code that large AI platforms like OpenAI can produce will be compared to clean code (production code) written by professional developers.

Space Odyssey

“Malevolent robot stories used to be more about brawn than brain — so it was a genuine shock for audiences in 1968 when the sentient HAL-9000 computer calmly said, ‘I'm sorry, Dave, I'm afraid I can't do that.’ Above, Gary Lockwood and Keir Dullea in 2001: A Space Odyssey. Metro-Goldwyn-Mayer/Getty Images.”

AI has come a long way since the invention of the perceptron algorithm in 1957. It has acted as a basic building block for neural networks and was partially responsible for some recent advancements such as supervised and unsupervised machine learning. These have led to machines that can challenge pro chess and go players, write essays, create art or music, but more importantly to this article, produce code. Perhaps the most recognized and largest platform is OpenAI which has created ChatGPT. Anyone can log into ChatGPT and ask it to produce code based on the user’s description. At first glance the code it produces seems extraordinary; it is produced quickly and confidently with explanations of how the code works. However, ChatGPT is susceptible to creating poorly written code on its first attempt. The code below depicts ChatGPT’s first attempt to solve a common Euler problem for finding the nth prime number.

(defn prime? [n]
  (and (<= n 1) false
       (not-any? #(zero? (rem n %)) (range 2 (Math/sqrt (inc n))))))
(defn nth-prime [n]
  (let [primes (filter prime? (range 2 (inc Integer/MAX_VALUE)))]
    (nth primes (dec n))))
(defn -main []
  (let [n 10001]
    (let [result (nth-prime n)]
      (println (str "The " n "th prime number is " result)))))

AI tools like this can feasibly be used for simple Euler problems or data structure questions, but even so, syntax errors may arise and the code may not work as expected. In this case, upon running ChatGPT’s output in a coding environment, the program takes a moment to process and then produces an IndexOutofBoundsException. Based on clean code principles this code would be considered neither clean nor functional. The naming of the functions is acceptable, but the implementations are not. For instance, the prime? function should refactor out a function to check if a number is divisible by zero. Likewise, the use of the filter function would be better suited for the task, and it would appear more readable as well. Finally, the nth-prime function could be simplified by using (range) in place of the Integer/MAX_VALUE and the function produces the exception because it is not correctly utilizing the laziness that range can provide. There are certainly other issues with the code, but the emphasis in the next section will instead be code that I wrote for the same prompt.

(defn mod-equal-zero? [dividend divisor]
  (zero? (mod dividend divisor)))
(defn prime-number? [n]
  (if  (= n 1)
    false
    (empty? (filter #(mod-equal-zero? n %) (rest (rest (range n)))))))
(defn nth-prime [n]
  (nth (filter prime-number? (range)) n))

The code above runs quickly and produces the correct result. Additionally, because there is a separate function for checking if a number is divisible by another, the code is easier to follow and utilizes Clojure-specific tools to produce a correct result. It is crucial to note that the code was created using test driven development (TDD), a powerful tool that Clean Coders developers use, and AI tools are not yet capable of implementing. TDD could be considered a controversial topic amongst the world's developers, but it is generally effective at reducing errors and bugs within code. This is a prime example of something that human developers are capable of that AI is not. While a user could provide tests for ChatGPT to try and pass, based on the way AI functions, it is not capable of strictly following TDD. In the screenshot below, ChatGPT was asked about its TDD capabilities based on how it produces code.

ai tdd

This one example does not definitively prove that AI will be unable to replace human developers, but it does suggest that there may be an opportunity for coexistence instead. One reason is that ChatGPT’s greatest strength was its ability to fix its mistakes through human intervention. The code below depicts ChatGPT’s second attempt after being given feedback.

(defn prime? [n]
  (if (<= n 1)
    false
    (not-any? (fn [i] (zero? (rem n i))) (range 2 (int (Math/sqrt n) + 1)))))
(defn nth-prime [n]
  (loop [count 0
         num 2]
    (if (= count n)
      (dec num)
      (if (prime? num)
        (recur (inc count) (inc num))
        (recur count (inc num))))))
(defn -main []
  (let [n 10001]  ; Change this to the desired n
    (let [result (nth-prime n)]
      (println (str "The " n "th prime number is " result)))))

ChatGPT did revise its initial attempt, but in the prime? function it attempts to add the integer of the square root of n with 1. This is a valid approach but is not how numbers are added in Clojure. The syntax would be

(+ (int Math/sqrt n) 1).

or better yet:

(inc (int Math/sqrt n))

After fixing this, the code does work, but it lacks many of the fundamentals of clean code. Functionality wise, the use of the loop function works fine here, but loops are generally considered to be unidiomatic and excess code that could be replaced using the filter function as demonstrated by my own code in a previous screenshot. Finally, as mentioned earlier, it still does not refactor unless specifically told to. In the code below, ChatGPT was prompted again to change its implementation.

(defn prime? [n]
  (and (<= n 1) false
       (not-any? #(zero? (rem n %)) (range 2 (Math/sqrt (inc n))))))
(def primes (filter prime? (cons 2 (mapcat #(list %1 %2) (range 3 (dec Integer/MAX_VALUE) 2) (repeat 3 5)))))
(defn nth-prime [n]
  (nth primes (dec n)))
(defn -main []
  (let [n 10001]  ; Change this to the desired n
    (let [result (nth-prime n)]
      (println (str "The " n "th prime number is " result)))))

While the implementation was changed, the code no longer worked and required additional time for the prompter to explain necessary revisions. The changed code is below.

(defn divisible? [n divisor]
  (zero? (rem n divisor)))
(defn prime? [n]
  (and (<= n 1) false
       (not-any? #(divisible? n %) (range 2 (Math/sqrt (inc n)))))
(def primes (filter prime? (cons 2 (mapcat #(list %1 %2) (range 3 (dec Integer/MAX_VALUE) 2) (repeat 3 5)))))
(defn nth-prime [n]
  (nth primes (dec n))

Finally, after three more attempts I was able to get ChatGpt to produce eligible code that works and is mostly idiomatic. However, it had forgotten that I wanted it to refactor out a function that checks for a number being divisible by zero, so I asked it one more time.

(defn divisible? [n i]
  (zero? (rem n i))
(defn prime? [n]
  (if (<= n 1)
    false
    (not-any? #(divisible? n %) (range 2 (int (Math/sqrt n) + 1)))))
(def primes (filter prime? (iterate inc 2)))
(defn nth-prime [n]
  (nth primes (dec n))
(defn -main []
  (let [n 10001]  ; Change this to the desired n
    (let [result (nth-prime n)]
      (println (str "The " n "th prime number is " result)))))

Even after the above screenshot of a fourth attempt, an error reoccurred in the prime? function by trying to add 1 to the square root of n. After I intervened and resolved this, the code was effective and efficient. The evidence is mounting that in order to use this tool to write code, the prompter must already know how to code so that they can revise the output. As demonstrated above, it may take multiple attempts to get the AI to write clean code that works for something as simple as finding a prime number. A novice in the field of software would have a hard time finding what is wrong with the code and then telling it what is needed to change to make it function as intended. If this is the case for a simple prompt, it is likely that far more would be necessary to get ChatGPT to produce a larger portion of code such as a game or website. The evident conclusion is that it would be time consuming and frustrating for a developer to strictly use ChatGPT to create a complex project, but nearly impossible for someone who is not a developer.

Conclusion

Before answering the initial question proposed at the beginning of this article, it is important to understand that tools like ChatGPT are amazing tools that have and will continue to help people of all walks of life. The point of this article is not to advise against the use of AI, but instead to demonstrate why it should not be feared by software developers or other professionals. The examples in this article demonstrate that current AI tools are in no state to outright replace developers and should instead be perceived as another tool in the developer’s arsenal. In conclusion, this work reveals that in order to get clean maintainable code from ChatGPT, the user of the tool needs to be well-versed in software development. Even in an optimal situation frustration and headaches arise before anything useful comes out. Therefore, businesses will continue to get better value from hiring real developers that follow clean coding principles and can make their vision become reality through descriptive iteration planning meetings(IPMs) and user stories than they would from attempting to use AI.


The illustration for this article was drawn by Clean Coders team member Nick Meccia, using the following image from openart.ai as a reference:

raw hero image