Product
Code Quality
Introduction
- What is Matter AI?
- Use Cases
Getting Started
- QuickStart
Integrations
- Code Repositories
- Team Messengers
- Ticketing
Enterprise
Code Quality
Learn how Matter AI helps in code quality analysis and recommendations
This guide walks you through the code quality features of Matter AI, which helps identify and fix code quality issues in your code.
Code Quality Analysis
We follow a large list of anti-patterns for multiple languages and frameworks to identify code quality issues.
Some examples
- Using
eval()
for parsing data
// Anti-pattern: Using eval to parse JSON
const userData = eval('(' + jsonString + ')');
// Better approach
const userData = JSON.parse(jsonString);
- Modifying built-in objects
// Anti-pattern: Extending built-in objects
Array.prototype.contains = function(item) {
return this.indexOf(item) !== -1;
};
// Better approach: Create utility functions
function arrayContains(array, item) {
return array.indexOf(item) !== -1;
}
- Using
==
instead of===
// Anti-pattern: Using loose equality
if (value == 0) { /* ... */ }
// Better approach: Use strict equality
if (value === 0) { /* ... */ }
- Global variables
// Anti-pattern: Using global variables
var count = 0;
function incrementCounter() {
count++;
}
// Better approach: Use closures or modules
const counter = (function() {
let count = 0;
return {
increment: function() { count++; },
getCount: function() { return count; }
};
})();
- Callback hell
// Anti-pattern: Nested callbacks
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
getTheMostData(c, function(d) {
// Do something with d
});
});
});
});
// Better approach: Use Promises or async/await
async function getAllData() {
const a = await getData();
const b = await getMoreData(a);
const c = await getEvenMoreData(b);
const d = await getTheMostData(c);
// Do something with d
}
- Using
any
type excessively
// Anti-pattern: Overusing 'any'
function processData(data: any): any {
return data.map((item: any) => item.value);
}
// Better approach: Define proper types
interface DataItem {
value: string;
id: number;
}
function processData(data: DataItem[]): string[] {
return data.map(item => item.value);
}
- Type assertions without verification
// Anti-pattern: Unsafe type assertion
const userData = JSON.parse(response) as UserData;
// Better approach: Validate before assertion
function isUserData(obj: any): obj is UserData {
return obj && typeof obj.name === 'string' && typeof obj.id === 'number';
}
const parsedData = JSON.parse(response);
if (isUserData(parsedData)) {
const userData: UserData = parsedData;
// Use userData safely
}
- Not using readonly for immutable properties
// Anti-pattern: Mutable interface properties
interface Config {
apiUrl: string;
maxRetries: number;
}
// Better approach: Use readonly for immutable properties
interface Config {
readonly apiUrl: string;
readonly maxRetries: number;
}
- Using
Object
as a type
// Anti-pattern: Using Object as a type
function processObject(obj: Object) {
// ...
}
// Better approach: Use more specific types or generics
function processObject<T extends Record<string, unknown>>(obj: T) {
// ...
}
- Not leveraging discriminated unions
// Anti-pattern: Complex type checking
interface Square {
kind?: string;
size: number;
}
interface Rectangle {
kind?: string;
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(shape: Shape) {
if ('size' in shape) {
return shape.size * shape.size;
}
if ('width' in shape) {
return shape.width * shape.height;
}
}
// Better approach: Use discriminated unions
interface Square {
kind: 'square';
size: number;
}
interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(shape: Shape) {
switch (shape.kind) {
case 'square':
return shape.size * shape.size;
case 'rectangle':
return shape.width * shape.height;
}
}
- Directly mutating state
// Anti-pattern: Mutating state directly
handleClick = () => {
this.state.count += 1;
this.forceUpdate();
}
// Better approach: Use setState
handleClick = () => {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
- Not using keys in lists
// Anti-pattern: Lists without keys
render() {
return (
<ul>
{this.state.items.map(item => (
<li>{item.name}</li>
))}
</ul>
);
}
// Better approach: Use unique keys
render() {
return (
<ul>
{this.state.items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
- Inline function definitions in render
// Anti-pattern: Creating functions in render
render() {
return (
<button onClick={() => this.handleClick(id)}>
Click me
</button>
);
}
// Better approach: Use class methods with binding
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(id) {
// Handle click
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
- Excessive use of state
// Anti-pattern: Derived state in component state
state = {
users: [],
filteredUsers: [],
totalCount: 0
}
componentDidUpdate(prevProps) {
if (prevProps.users !== this.props.users) {
const filteredUsers = this.props.users.filter(user => user.active);
this.setState({
users: this.props.users,
filteredUsers,
totalCount: filteredUsers.length
});
}
}
// Better approach: Compute derived values in render
render() {
const filteredUsers = this.props.users.filter(user => user.active);
return (
<div>
<p>Total: {filteredUsers.length}</p>
<UserList users={filteredUsers} />
</div>
);
}
- Prop drilling
// Anti-pattern: Passing props through many levels
function App() {
const [user, setUser] = useState({ name: 'John' });
return <Main user={user} />;
}
function Main({ user }) {
return <Profile user={user} />;
}
function Profile({ user }) {
return <Avatar user={user} />;
}
// Better approach: Use Context API
const UserContext = React.createContext();
function App() {
const [user, setUser] = useState({ name: 'John' });
return (
<UserContext.Provider value={user}>
<Main />
</UserContext.Provider>
);
}
function Main() {
return <Profile />;
}
function Profile() {
return <Avatar />;
}
function Avatar() {
const user = useContext(UserContext);
return <img src={user.avatarUrl} />;
}
- Using mutable default arguments
# Anti-pattern: Mutable default argument
def append_to(element, to=[]):
to.append(element)
return to
# This will not work as expected
append_to(1) # Returns [1]
append_to(2) # Returns [1, 2], not [2]
# Better approach
def append_to(element, to=None):
if to is None:
to = []
to.append(element)
return to
- Not using context managers for resource management
# Anti-pattern: Not using context managers
f = open('file.txt', 'r')
data = f.read()
# What if an exception occurs here?
f.close()
# Better approach: Use context managers
with open('file.txt', 'r') as f:
data = f.read()
# File is automatically closed, even if an exception occurs
- Using wildcard imports
# Anti-pattern: Wildcard imports
from module import *
# Better approach: Import only what you need
from module import specific_function, AnotherFunction
# Or
import module
- Ignoring exceptions too broadly
# Anti-pattern: Catching all exceptions
try:
do_something()
except Exception:
pass # Silently ignore all errors
# Better approach: Catch specific exceptions
try:
do_something()
except ValueError as e:
logger.error(f"Value error occurred: {e}")
except IOError as e:
logger.error(f"IO error occurred: {e}")
- Modifying a list while iterating over it
# Anti-pattern: Modifying a list during iteration
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
if numbers[i] % 2 == 0:
numbers.remove(numbers[i]) # This will skip elements
# Better approach: Create a new list or use list comprehension
numbers = [1, 2, 3, 4, 5]
numbers = [n for n in numbers if n % 2 != 0]
# Or
odd_numbers = []
for n in numbers:
if n % 2 != 0:
odd_numbers.append(n)
- Not closing resources properly
// Anti-pattern: Not closing resources
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// What if an exception occurs? Resources might not be closed
}
// Better approach: Use try-with-resources
public void readFile(String path) throws IOException {
try (FileReader reader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(reader)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
// Resources are automatically closed
}
- Using raw types instead of generics
// Anti-pattern: Using raw types
List myList = new ArrayList();
myList.add("string");
myList.add(42); // No compile-time type checking
String s = (String) myList.get(1); // ClassCastException at runtime
// Better approach: Use generics
List<String> myList = new ArrayList<>();
myList.add("string");
// myList.add(42); // Compile-time error
String s = myList.get(0); // No cast needed
- Excessive null checks
// Anti-pattern: Excessive null checking
public String getUserCity(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
City city = address.getCity();
if (city != null) {
return city.getName();
}
}
}
return "Unknown";
}
// Better approach: Use Optional (Java 8+)
public String getUserCity(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("Unknown");
}
- Using exceptions for flow control
// Anti-pattern: Using exceptions for flow control
public boolean isInteger(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
// Better approach: Use validation
public boolean isInteger(String s) {
if (s == null || s.isEmpty()) {
return false;
}
for (int i = 0; i < s.length(); i++) {
if (!Character.isDigit(s.charAt(i))) {
return false;
}
}
return true;
}
- Mutable public fields
// Anti-pattern: Public mutable fields
public class User {
public List<String> roles = new ArrayList<>();
}
// Anyone can modify the list
user.roles.clear();
// Better approach: Encapsulation
public class User {
private final List<String> roles = new ArrayList<>();
public List<String> getRoles() {
return Collections.unmodifiableList(roles);
}
public void addRole(String role) {
roles.add(role);
}
public void removeRole(String role) {
roles.remove(role);
}
}
- Using !! operator excessively
// Anti-pattern: Excessive use of !!
fun processUser(user: User?) {
val name = user!!.name
val age = user!!.age
val address = user!!.address!!
// NullPointerException if any is null
}
// Better approach: Safe calls and Elvis operator
fun processUser(user: User?) {
val name = user?.name ?: "Unknown"
val age = user?.age ?: 0
val address = user?.address?.toString() ?: "No address"
}
- Not using data classes for simple data holders
// Anti-pattern: Regular class for data
class User(val name: String, val age: Int) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is User) return false
return name == other.name && age == other.age
}
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + age
return result
}
override fun toString(): String {
return "User(name='$name', age=$age)"
}
}
// Better approach: Use data classes
data class User(val name: String, val age: Int)
// equals, hashCode, toString, copy are generated automatically
- Ignoring nullability in platform types
// Anti-pattern: Ignoring Java nullability
fun processJavaString(javaUtil: JavaUtil) {
val str = javaUtil.getStringThatMightBeNull()
println(str.length) // Potential NPE
}
// Better approach: Handle potential nulls
fun processJavaString(javaUtil: JavaUtil) {
val str = javaUtil.getStringThatMightBeNull()
if (str != null) {
println(str.length)
}
// Or
println(str?.length ?: 0)
}
- Overusing extension functions
// Anti-pattern: Extension function abuse
fun String.toInteger(): Int = this.toInt()
fun String.toDouble(): Double = this.toDouble()
fun String.isValidEmail(): Boolean = this.matches(Regex("^[A-Za-z](.*)([@]{1})(.*)$"))
// Better approach: Use utility class for related functions
object StringUtils {
fun toInteger(s: String): Int = s.toInt()
fun toDouble(s: String): Double = s.toDouble()
fun isValidEmail(s: String): Boolean = s.matches(Regex("^[A-Za-z](.*)([@]{1})(.*)$"))
}
- Not using coroutines for asynchronous operations
// Anti-pattern: Callbacks for async operations
fun fetchUserData(userId: String, callback: (User) -> Unit, errorCallback: (Exception) -> Unit) {
thread {
try {
val user = api.getUser(userId)
callback(user)
} catch (e: Exception) {
errorCallback(e)
}
}
}
// Better approach: Use coroutines
suspend fun fetchUserData(userId: String): User {
return withContext(Dispatchers.IO) {
api.getUser(userId)
}
}
// Usage
lifecycleScope.launch {
try {
val user = fetchUserData(userId)
updateUI(user)
} catch (e: Exception) {
showError(e)
}
}
- Using loose comparisons
// Anti-pattern: Loose comparisons
if ($value == 0) {
// This will be true for 0, '0', false, null, empty array
}
// Better approach: Use strict comparisons
if ($value === 0) {
// This will only be true for 0
}
- Not sanitizing user input
// Anti-pattern: Unsanitized input
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = mysqli_query($connection, $query);
// SQL injection vulnerability
// Better approach: Use prepared statements
$username = $_POST['username'];
$stmt = $connection->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
- Using deprecated mysql_ functions
// Anti-pattern: Using deprecated mysql_ functions
$connection = mysql_connect('localhost', 'user', 'password');
mysql_select_db('database');
$result = mysql_query("SELECT * FROM users");
// Better approach: Use mysqli or PDO
$connection = new mysqli('localhost', 'user', 'password', 'database');
$result = $connection->query("SELECT * FROM users");
// Or with PDO
$pdo = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT * FROM users");
- Not using namespaces
// Anti-pattern: Global namespace
class User {
// ...
}
function validate_email($email) {
// ...
}
// Better approach: Use namespaces
namespace App\Models;
class User {
// ...
}
namespace App\Utils;
function validate_email($email) {
// ...
}
- Using eval()
// Anti-pattern: Using eval
$calculation = $_GET['calc'];
$result = eval('return ' . $calculation . ';');
// Extremely dangerous - allows code execution
// Better approach: Use safer alternatives
$calculation = $_GET['calc'];
if (preg_match('/^[0-9+\-*\/()\s\.]+$/', $calculation)) {
// Still not perfect, but safer than eval
$result = eval('return ' . $calculation . ';');
} else {
throw new Exception("Invalid calculation");
}
// Even better: Use a proper math library
use MathParser\StdMathParser;
$parser = new StdMathParser();
$result = $parser->parse($calculation)->evaluate();
- Not quoting variables
# Anti-pattern: Unquoted variables
FILE_PATH=/path/with spaces/file.txt
rm $FILE_PATH # Will try to remove '/path/with' and 'spaces/file.txt'
# Better approach: Quote your variables
FILE_PATH="/path/with spaces/file.txt"
rm "$FILE_PATH" # Correctly handles the spaces
- Using
cd
in scripts without checking
# Anti-pattern: Unchecked directory change
cd /some/directory
# If directory doesn't exist, script continues in the wrong location
rm -rf temp/ # Could delete wrong files
# Better approach: Check directory change
if ! cd /some/directory; then
echo "Failed to change directory" >&2
exit 1
fi
rm -rf temp/
- Using command substitution without quotes
# Anti-pattern: Unquoted command substitution
files=$(find . -name "*.txt")
for file in $files; do # Word splitting happens
echo "Processing $file"
done
# Better approach: Use quotes and read
find . -name "*.txt" | while read -r file; do
echo "Processing $file"
done
- Not checking command exit status
# Anti-pattern: Not checking exit status
make all
./program # Runs even if compilation failed
# Better approach: Check exit status
if ! make all; then
echo "Compilation failed" >&2
exit 1
fi
./program
- Using
[ ]
instead of[[ ]]
# Anti-pattern: Using [ ] for complex conditions
if [ $name = "John" -a $age -gt 30 ]; then
echo "Found John who is older than 30"
fi
# Better approach: Use [[ ]] for better syntax
if [[ $name == "John" && $age -gt 30 ]]; then
echo "Found John who is older than 30"
fi
On this page