So, are we all freaking out about AI taking over our jobs as software engineers?
With these fancy new AI tools popping up in our work lives, things are getting a little weird. Junior devs are worried about being replaced by GitHub Copilot or even Devin, that AI engineer that’s making headlines. But us senior engineers? We’re kind of digging it. AI’s like this awesome sidekick that helps us code faster and focus on the big picture, not the nitty-gritty.
Let’s be real, tech companies are loving AI. It’s their secret weapon for building and maintaining better software. They throw around buzzwords like “productivity boost,” “faster shipping,” “easier troubleshooting,” and “AI pair programming.” Catchy, right?
But the truth is, they sometimes can be really life changing and sometimes not so much. But AI isn’t going anywhere. So why not get on board and learn how to use it? It might even help you pick up new skills or technologies that would usually take ages to master.
Look, if you haven’t really given these tools a proper go, it’s easy to think they might steal your job – especially if you’re just starting out. But trust me, spend a few weeks with them, and you’ll realize that’s not gonna happen. AI isn’t our enemy, it’s a tool that can actually make us better engineers. Juniors, this is especially good news for you.
How can I be more productive?
You’ve likely heard about ChatGPT and possibly even Google Gemini. These two AI models are pretty similar, and Gemini is probably Google’s way of catching up in the AI race. While it might be slightly behind in terms of features, it’s still incredibly powerful.
We can’t talk about this stuff without mentioning GitHub Copilot, another AI model trained on millions of lines of publicly available code. (Thanks for using my code without asking, Microsoft! 🙄)
At their core, ChatGPT, Gemini, and Copilot are all large language models (LLMs). The main difference is in the interface, the specific features, and the purpose. So, let’s look at some things you can do with pretty much any LLM, and then you can pick your favorite tool or the one your company uses to put these tips into action.
What can I do with a LLM as a Software Engineer?
Let me get straight to the point, here are the things you can do with an LLM.
- Explain code that sometimes are difficult to get at a glance.
- Suggest refactoring to improve code complexity.
- Debug an issue you are stuck with.
- Setup boiler-plate code and often repetitive code faster.
- Write unit tests (or at least try)
The “Explainer” and Teacher example
First up, let’s use AI as your personal coding tutor or expert explainer. To really show off how cool this is, I’m gonna use Assembly language in this example. Why? Well, let’s face it, most of us aren’t Assembly whizzes. 😉
Imagine you’re digging through some code and stumble upon a snippet that leaves you scratching your head. You’re totally clueless about what it does, and you wish you had someone to break it down for you. Well, guess what? AI can be that someone!
Explainer: Example prompt
Input: What the following code does? can you explain for me?
cmp ax, bx
jl Less
mov word [X], 1
jmp Both
Less:
mov word [X], -1
Both:
The LLM Generated output:
This assembly code snippet compares two values stored in registers ax and bx, then stores a result based on the comparison into a memory location labeled X. Here's a breakdown:
Explanation:
... long and detailed technical explanation
In Summary:
This code segment essentially implements a simplified "if-else" structure:
If ax < bx: Store -1 in memory location X.
Else (if ax >= bx): Store 1 in memory location X.
The value stored in X indicates the outcome of the comparison. The label Both is likely followed by code that uses the result stored in X to perform some further action.
Picture this: having your own personal coding guru available 24/7 to explain tricky code whenever you need. That’s pretty awesome, right? It’s a game-changer, especially for newbies who are still getting their heads around complex codebases and need a little extra guidance.
Improve code complexity and refactoring
Let’s be honest, we’re not always writing award-winning code. Especially when drafting new code, it’s easy to end up with something that’s a bit messy or overcomplicated. So why not have AI step in to check for things like complexity and help us clean it up?
For instance, imagine you’ve got a function that could use some polishing. We can ask our AI buddy to look at all the different scenarios, edge cases, and maybe even make the code easier to read. Sometimes, figuring out how to simplify code isn’t a walk in the park, so having a little help is always nice.
Suggest Refactoring: Example Prompt
In the following example, I will use some code snippet that I wrote 4 years ago for a mobile app to calculate the net salary income for someone working in Brazil, here is how AI would help me generate a better code.
Input: Can you improve the following function? and provide suggestions for it?
override fun calculateNetSalary(grossEarnings: Double, discounts: Double, numberOfDependants : Int) {
var inss = 0.0
var irpf = 0.0
var deduction = 0.0
var grossEarningsAfterTaxes = 0.0
when(grossEarnings) {
in INSS_FAIXA_1 -> {
inss = grossEarnings * 0.08
grossEarningsAfterTaxes = grossEarnings - ins
}
in INSS_FAIXA_2 -> {
inss = grossEarnings * 0.09
grossEarningsAfterTaxes = grossEarnings - inss
}
in INSS_FAIXA_3 -> {
inss = grossEarnings * 0.11
grossEarningsAfterTaxes = grossEarnings - inss
}
}
grossEarningsAfterTaxes = (grossEarningsAfterTaxes - (DEPENDANT_REDUCTION * numberOfDependants))
when(grossEarningsAfterTaxes) {
in IRPF_FAIXA_1 -> {
irpf = grossEarningsAfterTaxes * 0.0
}
in IRPF_FAIXA_2 -> {
irpf = grossEarningsAfterTaxes * 0.075
deduction = 142.80
}
in IRPF_FAIXA_3 -> {
irpf = grossEarningsAfterTaxes * 0.15
deduction = 354.80
}
in IRPF_FAIXA_4 -> {
irpf = grossEarningsAfterTaxes * 0.225
deduction = 636.13
}
in IRPF_FAIXA_5 -> {
irpf = grossEarningsAfterTaxes * 0.275
deduction = 869.36
}
}
val final_irpf = irpf - deduction
val grossSalary = grossEarnings
val salary = grossSalary - (final_irpf + inss + discounts)
view.showNetSalary(salary.toFloat())
}
The LLM generated output:
Okay, so the result is still a pretty chunky function, but we got some cool stuff out of it! First off, the AI suggested we break it down into smaller functions, which is a great way to make things less overwhelming. We also got to use some fancy Kotlin destructuring to make the code cleaner.
And check this out: we now have a separate function called calculateINSS
that handles specific cases. If something falls outside those cases, we get an exception. This might be a lifesaver, depending on what you’re doing, and it’ll definitely help us write better unit tests to make sure the code is rock solid.
override fun calculateNetSalary(grossEarnings: Double, discounts: Double, numberOfDependants: Int) {
// 1. Extract Calculation Logic into Functions
val inss = calculateINSS(grossEarnings)
val grossEarningsAfterINSS = grossEarnings - inss
val grossEarningsAfterDependants = applyDependantDeduction(grossEarningsAfterINSS, numberOfDependants)
val (irpf, deduction) = calculateIRPF(grossEarningsAfterDependants)
// 2. Calculate Final Net Salary
val finalIrpf = irpf - deduction
val netSalary = grossEarnings - finalIrpf - inss - discounts
// 3. Display Result (Maintain View Interaction)
view.showNetSalary(netSalary.toFloat())
}
// INSS Calculation
private fun calculateINSS(grossEarnings: Double): Double {
return when (grossEarnings) {
in INSS_FAIXA_1 -> grossEarnings * 0.08
in INSS_FAIXA_2 -> grossEarnings * 0.09
in INSS_FAIXA_3 -> grossEarnings * 0.11
else -> throw IllegalArgumentException("Invalid gross earnings")
}
}
// Dependant Deduction
private fun applyDependantDeduction(grossEarnings: Double, numberOfDependants: Int): Double {
return grossEarnings - (DEPENDANT_REDUCTION * numberOfDependants)
}
// IRPF Calculation
private fun calculateIRPF(grossEarnings: Double): Pair<Double, Double> {
return when (grossEarnings) {
in IRPF_FAIXA_1 -> 0.0 to 0.0
in IRPF_FAIXA_2 -> grossEarnings * 0.075 to 142.80
in IRPF_FAIXA_3 -> grossEarnings * 0.15 to 354.80
in IRPF_FAIXA_4 -> grossEarnings * 0.225 to 636.13
in IRPF_FAIXA_5 -> grossEarnings * 0.275 to 869.36
else -> throw IllegalArgumentException("Invalid gross earnings")
}
}
AI Code assistants can help you get unstuck faster
Another super handy trick? Using AI to get yourself unstuck or troubleshoot errors, FAST. I’ve totally been there, banging my head against the keyboard over some weird bug.
Just the other day, I was battling a React Native issue that was driving me nuts. I couldn’t figure out why my function kept spitting out “undefined” errors, no matter what I tried.
So, I turned to my trusty LLM for help, and here’s what I did:
Troubleshoot Code: Example Prompt
Why the following javascript code returns undefined for the variable “value” after the if statement?
const buttonPressed = (value) => {
console.log(value);
if(typeof value === 'number') {
console.log(`Is a number: ${value}`);
const value = handleNumber(value);
setAnswerValue(value);
}
};
If you are not a Javascript Ninja, and wasn’t able to decipher why I wasn’t getting the value that I wanted for this function in particular, here is how LLM was able to help me with that.
The LLM generated output:
Problem: Inside your if block, you have this line:
const value = handleNumber(value);
By using const again, you're declaring a new variable named value that exists only within the scope of that if block. This new value variable is "shadowing" (hiding) the original value parameter that was passed into the buttonPressed function.
Since handleNumber is likely returning a modified value, the new value variable inside the if block gets assigned this returned value. However, this assignment does not affect the original value parameter that's used outside the if block.
Solution:
Remove the const keyword before value inside the if block. This way, you'll be assigning the result of handleNumber back to the original value parameter, ensuring that the change is reflected outside the if statement.
const buttonPressed = (value) => {
console.log(value);
if (typeof value === 'number') {
console.log(`Is a number: ${value}`);
value = handleNumber(value); // Assign to the original value
setAnswerValue(value);
}
};
Explanation:
Parameter value: The buttonPressed function receives a parameter named value. This parameter's scope is the entire function.
If Condition: The if statement checks if the value is a number.
Shadowed value (Original Code): In your original code, you declare a new const variable named value inside the if block. This creates a separate, block-scoped variable that hides the original parameter with the same name.
Shadowed value Assignment: When you assign the result of handleNumber(value) to this new value variable, it only affects this inner variable, not the original parameter.
Corrected Assignment: By removing const, you're directly assigning the result of handleNumber(value) to the original parameter value, allowing the updated value to be accessible after the if statement.
Again, I was spending hours debugging a very simple thing an AI model could detect right away. That’s how powerful they can be! The answer is very well detailed with explanations that is just mind blowing.
Write Unit tests for you, or at least setup boiler-plate code
Hopefully, by now you’re seeing how handy these AI models can be in your daily grind as a software engineer. So, let’s kick things up a notch and ask our AI assistant to help us with unit tests!
How about we put it to the test with some code snippets I’ve already shown you? Let’s see what kind of unit tests this LLM can cook up for us.
//Input: Can you generate Unit Tests for the function below?
...previously submitted code snippet at "Refactoring example"
//Generated code
import org.junit.Test
import org.junit.Assert.* // or your preferred assertion library
class SalaryCalculatorTest {
// Sample Tax Brackets (replace with your actual values)
private val INSS_FAIXA_1 = 0.0..1320.0
private val INSS_FAIXA_2 = 1320.01..2571.29
private val INSS_FAIXA_3 = 2571.30..3856.94
private val IRPF_FAIXA_1 = 0.0..1903.98
// ... (Define other IRPF brackets)
private val DEPENDANT_REDUCTION = 189.59
// Sample View (replace with your actual implementation)
private val view = object : SalaryView {
override fun showNetSalary(netSalary: Float) {
// In a real test, you would verify that the netSalary was passed correctly to this function
}
}
private val salaryCalculator = SalaryCalculator(view) // Assuming your class is named SalaryCalculator
@Test
fun testCalculateNetSalary_INSSFaixa1() {
val grossEarnings = 1000.0
val discounts = 50.0
val dependants = 2
salaryCalculator.calculateNetSalary(grossEarnings, discounts, dependants)
// Verify that the correct values were passed to showNetSalary (or use a mocking framework)
// In this example, we'll just calculate the expected result
val expectedINSS = grossEarnings * 0.08
val expectedGrossAfterINSS = grossEarnings - expectedINSS
val expectedGrossAfterDependants = expectedGrossAfterINSS - (DEPENDANT_REDUCTION * dependants)
val expectedIRPF = 0.0
val expectedNetSalary = grossEarnings - expectedINSS - expectedIRPF - discounts
// Assert (use a mocking framework for a more robust verification)
// verify(view).showNetSalary(expectedNetSalary.toFloat())
}
// Similar tests for other INSS and IRPF brackets
@Test
fun testCalculateNetSalary_INSSFaixa2() { /* ... */ }
@Test
fun testCalculateNetSalary_INSSFaixa3() { /* ... */ }
@Test
fun testCalculateNetSalary_IRPF_Faixa1() { /* ... */ }
@Test
fun testCalculateNetSalary_IRPF_Faixa2() { /* ... */ }
// ... (Add tests for other IRPF brackets)
// Edge Case Tests
@Test(expected = IllegalArgumentException::class)
fun testCalculateNetSalary_InvalidGrossEarnings() {
salaryCalculator.calculateNetSalary(-100.0, 0.0, 0) // Negative gross earnings
}
}
I’m not gonna lie, I don’t always trust the tests that AI tools spit out. So, be careful when using them. You don’t want to think you’re testing something when you’re not. My advice? Use LLMs to jumpstart your testing process, but make sure you double-check those unit tests to be safe.
A few more-use cases for AI code assistants
Documentation
One of the biggest headaches for new software engineers is dealing with company documentation that’s often outdated or just plain confusing. With AI tools like GitHub Copilot that can understand code context, it might seem like traditional docs are kinda pointless.
But here’s the thing: AI can be super helpful when it comes to writing non-technical docs for non-tech folks at your company.
So, next time you’re stuck writing some boring documentation, try asking your AI assistant for help. They can brainstorm ideas, help you outline your thoughts, even fix your grammar or make complex technical stuff easier to understand for the non-techies.
Cyber-Security
But when it comes to security, AI is our friend, We can actually train AI tools like ChatGPT or Copilot to sniff out vulnerabilities in our code every time we push changes. Github is trying to help developers with AI to help prevent code vulnerabilities with code scanning. See this blog post for more details.
Improve Performance and Monitoring
I’ve lost count of how many times I’ve seen software engineers sweating bullets trying to optimize backend or frontend code. And don’t even get me started on those intense war-rooms where database gurus are scrambling to speed up a SQL query.
But with AI tools, you can get some pretty awesome suggestions for improving your infrastructure and even get tips on how to deploy, monitor, or write better database queries.
If you’re using a relational database like PostgreSQL, there’s this cool AI assistant called Joe Bot that can help you with complex queries and optimizations.
Beware that indexes aren’t always the answer.
Don’t sleep on Privacy Issues and Compliance
Alright, so you’ve seen how awesome these tools are, but now it’s time for the real talk: Are they right for you?
While a lot of the cool stuff I’ve shown you is kinda-sorta free with ChatGPT or Google Gemini, you often have to pay for a subscription to an AI code assistant to unlock the full potential.
Here’s the deal: you gotta be careful what you share with these tools. They basically vacuum up everything you put in them. So if you’re throwing in confidential code, trade secrets, or anything that’s not yours (like stuff from your job), you could find yourself in some hot water.
Take for example some Engineers at Samsung that leaked some important code using LLM models available in the market.
Don’t be like them, consider the implications of using a tool like this. The best place to consult if you can use such AI assistants is the legal department at your company, or if they already have an established AI assistant that is private to the company data. If you don’t have explicit permission, just don’t do it.
It’s also important to remind you to NOT share personal details with these models, or you mind end-up being exposed in someone else’s prompt.
That’s all that I had for now, let me know if you find this article useful.
Leave a Reply