Task Automation and Debugging with AI-Powered Tools

    Timi Omoyeni
    Timi Omoyeni
    Share

    This introduction to task automation and debugging with AI tools is excepted from the book Generative AI Tools for Developers: A Practical Guide, available now on SitePoint Premium.

    Table of Contents

    Task Automation

    One of the ways engineers can make use of AI-powered tools is with task automation. Many mundane and repetitive tasks can be automated with the help of AI coding assistants.

    AI automation tasks list

    For example, we can ask our AI assistant to generate boilerplate code — for common tasks like creating a basic REST API with routes, controllers, models, and so on. This saves time initially setting up a project skeleton.

    Using Codeium, here’s an example of how we can generate boilerplate code.

    Codeium generating boilerplate code

    We can also use Cody to generate boilerplate code.

    Cody generating boilerplate code

    Here, we can see that, using an AI coding assistant like Codeium or Cody, we’re able to quickly create a simple Express server that’s enough to get started with the basic structure and routes defined. To do this, we have to click on the Codeium icon, which should be among the list of extensions on the left side of our editor (or right, depending on where we’ve placed the icons). Doing this opens up the Codeium chat interface that allows us to communicate with the Codeium server. This is a lot quicker than manually writing all the boilerplate code from scratch.

    Here’s what Codeium gives us:

    const express = require('express');
    const app = express();
    const port = 3000;
    
    app.get('/', (req, res) => {
    res.send('Hello World!');
    });
    
    app.listen(port, () => {
    console.log(`Server listening on port ${port}`);
    });
    

    Using Cody, here’s what we get:

    const express = require('express');
    
    const app = express();
    
    app.get('/', (req, res) => {
    res.send('Hello World!');
    });
    
    app.listen(3000, () => {
    console.log('Server listening on port 3000');
    });
    

    Now let’s ask our AI assistant to write some tests. AI tools can also help us generate test cases as a starting point for testing our code. This ensures code is tested from the beginning, which is important for quality and avoiding bugs. This can help engineers who are still learning how to write tests and also help introduce test-driven development practices into a codebase without tests.

    Here’s an example of how we can do this using GitHub Copilot Labs.

    We can also generate tests using Codeium.

    In this example, we see the Copilot Labs test feature and Codeium in action. For it to work, we need to provide a function for it to test against:

    function milliSecondsToDayHourMin = (timeRemaining) => {
      let dayInMilliseconds = 86400000;
      let hourInMilliseconds = 3600000;
      let day = Math.floor(timeRemaining / dayInMilliseconds);
      let hour = Math.floor(
         (timeRemaining - day * dayInMilliseconds) / hourInMilliseconds
      );
      let min = Math.round(
         (timeRemaining - day * dayInMilliseconds - hour * hourInMilliseconds) /
            60000
      );
      let seconds = Math.round(timeRemaining - min / 60);
      const pad = function (num) {
         return num < 10 ? "0" + num : num;
      };
      if (min === 60) {
         hour++;
         min = 0;
      }
      if (hour === 24) {
         day++;
         hour = 0;
      }
      return `${day} : ${pad(hour)}  :  ${pad(min)}:  ${pad(seconds)}`;
    };
    

    After doing this, it’s able to generate test cases to cover different scenarios, such as valid, invalid, and edge cases. The test case generated can act as a good starting point for developers to implement proper testing.

    Here’s what Copilot gives us:

    describe('test Untitled_1', function() {
      it('test Untitled-1.milliSecondsToDayHourMin', function(done) {
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(0), '0 : 00  :  00:  00');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(60000), '0 : 00  :  01:  01');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(3600000), '0 : 01  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000), '1 : 00  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(172800000), '2 : 00  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(259200000), '3 : 00  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(604800000), '7 : 00  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(604800000), '7 : 00  :  00:  60');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000 + 3600000 + 60000), '1 : 01  :  01:  01');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000 + 3600000 + 60000 + 1000), '1 : 01  :  01:  01');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000 + 3600000 + 60000 + 1000), '1 : 01  :  01:  01');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000 + 3600000 + 60000 + 1000), '1 : 01  :  01:  01');
         assert.deepEqual(Untitled_1.milliSecondsToDayHourMin(86400000 + 3600000 + 60000 + 1000), '1 : 01  :  01:  01');
         done();
      })
    })
    

    And here’s what Codeium gives us:

    test("milliSecondsToDayHourMin - should return 0 : 00 : 00 : 00 for 0 milliseconds", () => {
      expect(milliSecondsToDayHourMin(0)).toBe("0 : 00 : 00 : 00");
    });
    
    test("milliSecondsToDayHourMin - should return 1 : 00 : 00 : 00 for 86400000 milliseconds", () => {
      expect(milliSecondsToDayHourMin(86400000)).toBe("1 : 00 : 00 : 00");
    });
    
    test("milliSecondsToDayHourMin - should return 1 : 01 : 00 : 00 for 90000000 milliseconds", () => {
      expect(milliSecondsToDayHourMin(90000000)).toBe("1 : 01 : 00 : 00");
    });
    
    test("milliSecondsToDayHourMin - should return 1 : 01 : 01 : 00 for 90060000 milliseconds", () => {
      expect(milliSecondsToDayHourMin(90060000)).toBe("1 : 01 : 01 : 00");
    });
    
    test("milliSecondsToDayHourMin - should return 1 : 01 : 01 : 01 for 90061000 milliseconds", () => {
      expect(milliSecondsToDayHourMin(90061000)).toBe("1 : 01 : 01 : 01");
    });
    

    Debugging

    AI-powered tools are also useful for debugging. Debugging is one of the most time-consuming tasks any engineer deals with on a daily basis, regardless of their experience level. Integrating AI tools into the debugging workflow reduces the time spent trying to understand what’s going wrong.

    Here’s an example of how we can debug using Codeium:

    function cleanupFounders() {
      const founders = this.orgInfo.founders;
      foundeers.map((document) => {
         delete document.organisation;
         delete document.createdAt;
         delete document.updatedAt;
         delete document.__v;
      });
      this.orgInfo.founders = founders;
    }
    

    Codeium Debugging

    We can also use Cody to debug code.

    And here’s another example of how we can do this using GitHub Copilot Labs.

    Copilot Debugging

    We can see above that Codeium points out an issue in the code by first understanding the founders variable declaration and finding the typo in the code. It then produces a working version of the code (without the typo) while also explaining the true intention of the function.

    Here’s the Codeium corrected code:

    function cleanupFounders() {
      const founders = this.orgInfo.founders;
      founders.map((document) => {
        delete document.organisation;
        delete document.createdAt;
        delete document.updatedAt;
        delete document.__v;
      });
      this.orgInfo.founders = founders;
    }
    

    Using Cody, we’re also able to debug code by first providing a function for it to debug. It then produces a working version of the code while also explaining the true intention of the function. It also goes a step further by suggesting extra ideas to improve the code.

    When using the debug feature in Copilot Labs, we’re required to provide a function for it to debug. When we do this, we can see that it automatically fixes our code and gives us a working version of the code:

    function cleanupFounders() {
      const founders = this.orgInfo.founders;
      this.orgInfo.founders = founders.map((document) => {
        delete document.organisation;
        delete document.createdAt;
        delete document.updatedAt;
        delete document.__v;
        return document;
      });
    }
    

    With these tools, debugging is easier, faster, and more efficient. However, while these tools can help us out with all these tasks, we still need to go over the solutions in order to verify the quality of the code. This way, we get to spend time learning rather than debugging, searching the Internet, and getting frustrated over bugs in our code.

    Want to learn more about chatbots, LLMs and other AI tools that can help you in your work as a developer? Check out Generative AI Tools for Developers: A Practical Guide, available now on SitePoint Premium.