Supercharging Development Efficiencies with AI-Powered Assistants
In recent years, artificial intelligence (AI) has become an integral part of our daily lives, revolutionising various industries and fundamentally reshaping how we work and engage with technology. For IT professionals like us, AI plays a significant role in streamlining processes, enhancing productivity, and solving complex problems. In this article, we will explore the practical applications of AI in the everyday routines of Software Engineers, highlighting its wide-ranging benefits and adaptable functionalities.
There are many plugins or tools available in the market right now that are AI-powered or have a chatbot as their main power source which can seamlessly integrate into the IDE. These tools generally provide similar features and outputs. The most commonly used tools are Bito.ai, Codium.ai, and jetbrain.ai, etc. Reference links can be found at the end of this article.
This article will explore how IDE + AI, Slack + OpenAI, and GitLab + OpenAI integration enhance our work processes at Tamara.
I. Exploring Bito.ai Features
What functionalities does bito.ai provide to tackle our daily challenges? As an example, I will take a code snippet and explore different features of Bito that can be applied in this scenario.
The screenshot below illustrates the available features of Bito:
The Scenario:
Let’s consider this code:
public void performComplexOperations() {
Map<String, Integer> sampleMap = new HashMap<>();
sampleMap.put("sun", 10);
sampleMap.put("moon", 20);
Map<String, Integer> finalMap = sampleMap.entrySet().stream()
.filter(entry -> entry.getValue() > 15)
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> {
int newValue = entry.getValue() * 2;
System.out.println("Modified Key: " + entry.getKey() + ", Modified Value: " + newValue);
return newValue - 10;
}
));
System.out.println("Final Modified Map: " + finalMap);
}
- Explaining Code
As software engineers, we often encounter unfamiliar pieces of code, such as built-in methods used from libraries or frameworks that we are utilizing. Additionally, organizations often employ more than one programming language based on the use case, which means we may need to read and understand code in languages where our expertise is limited. In such situations, the “Explain Code” feature comes in handy offering detailed explanations for code snippets.
To explain any code snippet, I don’t need to copy the code, switch to ChatGPT, and paste it for reading. Instead, I can simply highlight the code and then press the button to explain it:
Below is an example:
The bito.ai extension will explain the code within the IDE, making it easier for developers to understand and use the code effectively.
2. Generating Comments
Comments are important for documenting code and teamwork among developers, but writing detailed comments can be time-consuming. Generating comments for the same method helps in understanding its functionality. Bito’s “Generate Comments” feature analyzes code and produces comments that explain functions, variables, and more.
In our example, I have received the following comment about the method, which is both accurate and convenient as bito.ai will go further to even open the window and apply the recommended comments.
// This Java code defines a method performComplexOperations that takes a map,
// filters out entries with values greater than 15, modifies the values by doubling them and subtracting 10,
//and returns the final modified map.
3. Performance Check
I can execute a code “Performance Check” with Bito by running performance tests on the code within the IDE. It analyzes various aspects such as execution time, memory usage, and overall efficiency. Based on the results, I am able to identify areas for improvement to optimize the performance of the code.
Clicking the performance check button I receive the following message:
1. Calling System.out.println within the stream operation can be inefficient.
2. The use of stream operations for simple operations like filtering and mapping can be overkill.
Not only does it give suggestions, Bito also generates optimized code:
public void performComplexOperations() {
Map<String, Integer> sampleMap = new HashMap<>();
sampleMap.put("sun moon", 10);
sampleMap.put("banana", 20);
Map<String, Integer> finalMap = new HashMap<>();
for (Map.Entry<String, Integer> entry : sampleMap.entrySet()) {
if (entry.getValue() > 15) {
int newValue = entry.getValue() * 2;
System.out.println("Modified Key: " + entry.getKey() + ", Modified Value: " + newValue);
finalMap.put(entry.getKey(), newValue - 10);
}
}
System.out.println("Final Modified Map: " + finalMap);
}
4. Security Check
Bito AI checks the code for security vulnerabilities like SQL injection and cross-site scripting. It also looks to adopt security standards and best practices.
The security check feature I used on a piece of code gave the following output:
Potential security issues in the code:
1. Printing sensitive information (key and modified value) to the console which could be a security risk.
2. No input validation for the values being inserted into the map.
3. No exception handling for potential errors during the stream processing.
Bito can also provide suggestions or recommendations for fixing the identified security issue in the code. The rewritten code snippets propose changes to existing code to eliminate the security risks as shown below:
Here is the rewritten code to address the security issue:
public void performComplexOperations() {
Map<String, Integer> sampleMap = new HashMap<>();
sampleMap.put("sun moon", 10);
sampleMap.put("banana", 20);
Map<String, Integer> finalMap = sampleMap.entrySet().stream()
.filter(entry -> entry.getValue() > 15)
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> {
int newValue = entry.getValue() * 2;
return newValue - 10;
}
));
System.out.println("Final Modified Map: " + finalMap);
}
5. Style Check
Another feature of the AI analyzes the code to ensure consistency with coding style guidelines, such as indentation, naming conventions, and formatting. Here it is used to correct the indentation of the written code:
1. Inconsistent indentation - the code inside the method should be indented.
6. Improve Readability
This is an important feature. It identifies areas where the code may be difficult to understand or follow and adds a comment before each line to indicate the purpose of that particular line of code. This functionality proves to be extremely helpful, especially for junior developers.
public void performComplexOperations() {
// Create a new HashMap
Map<String, Integer> sampleMap = new HashMap<>();
sampleMap.put("sun moon", 10);
sampleMap.put("banana", 20);
// Filter the entries in the map based on a condition
Map<String, Integer> finalMap = sampleMap.entrySet().stream()
.filter(entry -> entry.getValue() > 15)
.collect(Collectors.toMap(
Map.Entry::getKey, entry -> {
int newValue = entry.getValue() * 2;
System.out.println("Modified Key: " + entry.getKey() + ", Modified Value: " + newValue);
return newValue - 10;
}
));
// Print the final modified map
System.out.println("Final Modified Map: " + finalMap);
}
7. Clean Code
The AI identifies and addresses various issues that may affect code quality, readability, and maintainability. This function will clean any debugging statement present in the code.
8. Generating Unit Tests
Writing unit tests to cover all potential edge cases can be very tedious and is a very tiresome part of writing the code. Fortunately, I can use the generated unit test feature of the Bito.
The generated test cases are as:
@SpringBootTest
public class SampleServiceTest {
@Autowired
private SampleService sampleService;
@Test
public void testPerformComplexOperations() {
// Capture the output of the performComplexOperations method
Map<String, Integer> sampleMap = new HashMap<>();
sampleMap.put("sun moon", 10);
sampleMap.put("banana", 20);
Map<String, Integer> expectedMap = new HashMap<>();
expectedMap.put("banana", 30);
Map<String, Integer> finalMap = sampleService.performComplexOperations();
// Verify the final map
assertEquals(expectedMap, finalMap);
}
}
Often, the unit tests generated from code have syntax errors and aren’t entirely compatible with the code under test. Debugging and rectifying these test cases can sometimes be more time-consuming than writing them from scratch.
II. Slack + Open AI
At Tamara, we love integrating new tools and technologies. Our founder, Abdul Majeed, is especially excited about using AI, and Chien Hoang, our Head of Core Infrastructure in Engineering, is leading the charge in making AI a part of our daily work. Recently, our engineers have integrated OpenAI APIs into Slack and made a TamaraGPT bot, making it easier for everyone to use AI right within our communication workspace.
For this, we’re using RAG (Retrieval-Augmented Generation) architecture, which enhances our AI capabilities by combining information retrieval with AI-generated content. An added benefit of this integration is that OpenAI will not use our data to train their models, ensuring our data remains secure and private.
Initially, we integrated OpenAI into our system, and then we enhanced it further by adding the ability to perform Google searches. This combination allows TamaraGPT to deliver more comprehensive and accurate results than using OpenAI alone.
Additionally, the OpenAI model within TamaraGPT is going to be trained with our codebase, making it easier for our developers to get relevant and specific insights tailored to our projects.
Looking ahead, we’re planning to integrate Confluence with our Slack bot, so we can easily browse company documentation through Slack.
III. Gitlab + Open AI
Our engineers have skill fully implemented the integration of OpenAI with GitLab, significantly enhancing our code review process. By leveraging AI, we can automatically review code and receive valuable comments that help improve the quality and consistency of our codebase.
This integration provides our developers with insightful suggestions and error detection, streamlining the review process and reducing manual effort. Additionally, this solution is both cost-effective and secure. Since our data is not used to train external models, we maintain full control over our proprietary information, ensuring that our sensitive data remains private and protected.
Example of Gitlab AI code review improvement recommendations by OpenAi:
- Serialization Error Handling
- The method to serialize an object to JSON returns null if an error occurs, which might lead to NullPointerExceptions later.
- Fix: Implement error handling to manage serialization issues and prevent NullPointerExceptions.
private String serializeToJson(Object objectToSerialize) {
try {
return objectMapper.writeValueAsString(objectToSerialize);
} catch (JsonProcessingException e) {
log.error("error while parsing object to json", e); // Add exception to the log
throw new RuntimeException("Serialization to JSON failed", e); // Throw a runtime exception
}
}
2. Security Risks
- Token Handling:
- Ensure that sensitive tokens are handled securely and aren’t exposed in logs or error messages.
- Example: Redact the token value in log statements or avoid logging them entirely if possible.
Input Validation:
- Ensure that all inputs to the external API calls, especially user-supplied inputs like userAgent, are properly sanitized and validated to prevent injection attacks.
Conclusion
In wrapping up, our journey of blending AI into our work has been a productive transformation and has changed how we do things. We’ve integrated AI into Slack, created our own TamaraGPT bot, and even improved how we review code using OpenAI in GitLab. With AI embedded in our development software, we’re providing our developers with targeted support right where they need it. Plus, by integrating AI into our Integrated Development Environment (IDE), we’re making coding smoother and faster. This all makes us work faster and smarter. These advancements enable us to work more efficiently and intelligently. As we continue to explore AI’s potential, we remain committed to leveraging cutting-edge technology to achieve greater impacts with our work.
Bonus Cases
In this final bonus section, I will explain different use cases that have helped me during development and saved substantial time. Here, I have used a combination of ChatGPT and Google Gemini. Since the free version of ChatGPT does not support image uploads, I rely on Gemini for that purpose.
Use Case 1
As a developer, I received a screenshot of a network tab with an error in the GET request while the QA was testing the order creation.
I can see the session ID but I need to extract it from the screenshot.
I go to Gemini Upload Image to extract the requested URL, retrieving the complete URL in text form and then I can get the complete session ID.
Use Case 2
As a product manager very often I receive requests to check the data discrepancy and I often have to check different tables of the database.
For example: the ai_tutorial_table has column details and the details column is a JSON object.
ai_tutorial_table.detail
{
"verified_customer": true,`
"gender": "m",
"country_origin": "pakistan"
}
I need to find out all the data from the ai_tutorial_table where customer verified_customer is true.
In this scenario, the MySQL query will be more complex than a traditional SELECT query. As a product manager with limited MySQL knowledge, I would depend on a chatbot or Gemini to provide the query for me.
I utilized ChatGPT and obtained the following query:
SELECT *
FROM ai_tutorial_table
WHERE JSON_EXTRACT(details, '$.verified_customer') = 'true';
With explanation:
To retrieve data from the ai_tutorial_table where the verified_customer field is true, you can use SQL with JSON functions if your database supports them. This query will select all rows from the ai_tutorial_table where the value of the verified_customer field in the JSON object stored in the details column is true.
You can replace “details” with the actual name of the column containing the JSON object if it differs from your database schema. Additionally, modify the syntax according to your database’s SQL dialect if necessary.