Guide for conducting thorough code reviews focusing on correctness, security, performance, maintainability, and best practices
When reviewing pull requests or auditing code, this skill guides you to conduct thorough reviews focusing on correctness, security vulnerabilities, performance issues, and maintainability. You'll systematically check for bugs, SQL injection risks, N+1 queries, unclear naming, and inadequate error handling, then provide specific, constructive feedback with actionable suggestions.
/plugin marketplace add vinnie357/claude-skills/plugin install core@vinnie357This skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill activates when reviewing code for quality, correctness, security, and maintainability.
Activate when:
Does the code do what it's supposed to do?
Questions to ask:
Is the code secure?
Common security issues:
# BAD: SQL injection vulnerability
query = "SELECT * FROM users WHERE id = #{user_id}"
# GOOD: Use parameterized queries
query = from u in User, where: u.id == ^user_id
# BAD: XSS vulnerability
raw("<div>#{user_input}</div>")
# GOOD: Escape user input
<div><%= user_input %></div>
# BAD: Hardcoded secrets
api_key = "sk_live_123456789"
# GOOD: Use environment variables
api_key = System.get_env("API_KEY")
# BAD: Mass assignment vulnerability
User.changeset(%User{}, params)
# GOOD: Whitelist allowed fields
User.changeset(%User{}, params)
# Where changeset only casts allowed fields:
# cast(user, attrs, [:name, :email])
Is the code efficient?
Common performance issues:
# BAD: N+1 query
posts = Repo.all(Post)
Enum.map(posts, fn post ->
author = Repo.get(User, post.author_id) # Query for each post!
{post, author}
end)
# GOOD: Preload associations
posts = Post |> preload(:author) |> Repo.all()
# BAD: Loading entire dataset
users = Repo.all(User) # Loads all millions of users
Enum.filter(users, & &1.active)
# GOOD: Query in database
users = User |> where(active: true) |> Repo.all()
# BAD: Inefficient data structure
list = [1, 2, 3, 4, 5]
if 3 in list do # O(n) lookup in list
# ...
end
# GOOD: Use set/map for lookups
set = MapSet.new([1, 2, 3, 4, 5])
if MapSet.member?(set, 3) do # O(1) lookup
# ...
end
Is the code readable and maintainable?
Code quality issues:
# BAD: Unclear names
def calc(x, y, z) do
r = x * y / z
r * 1.2
end
# GOOD: Clear names
def calculate_discounted_price(quantity, unit_price, discount_percentage) do
subtotal = quantity * unit_price
discount_amount = subtotal * (discount_percentage / 100)
subtotal - discount_amount
end
# BAD: Long function with multiple responsibilities
def process_order(order) do
# Validate order (responsibility 1)
# Calculate totals (responsibility 2)
# Update inventory (responsibility 3)
# Send email (responsibility 4)
# Log analytics (responsibility 5)
end
# GOOD: Single responsibility functions
def process_order(order) do
with {:ok, order} <- validate_order(order),
{:ok, order} <- calculate_totals(order),
{:ok, order} <- update_inventory(order),
:ok <- send_confirmation_email(order),
:ok <- log_order_analytics(order) do
{:ok, order}
end
end
# BAD: Magic numbers
if user.age >= 13 do
# ...
end
# GOOD: Named constants
@minimum_age_coppa 13
if user.age >= @minimum_age_coppa do
# ...
end
Are errors handled properly?
Error handling patterns:
# BAD: Silent failure
try do
dangerous_operation()
rescue
_ -> nil # Error is swallowed!
end
# GOOD: Handle errors explicitly
case dangerous_operation() do
{:ok, result} -> result
{:error, reason} ->
Logger.error("Operation failed: #{inspect(reason)}")
{:error, reason}
end
# BAD: Generic error message
{:error, "failed"}
# GOOD: Specific error
{:error, :invalid_email_format}
{:error, {:validation_failed, errors}}
# BAD: Let it crash when shouldn't
def parse_config(path) do
File.read!(path) # Crashes if file missing
|> Jason.decode!() # Crashes if invalid JSON
end
# GOOD: Handle expected errors
def parse_config(path) do
with {:ok, content} <- File.read(path),
{:ok, config} <- Jason.decode(content) do
{:ok, config}
else
{:error, :enoent} -> {:error, :config_file_not_found}
{:error, %Jason.DecodeError{}} -> {:error, :invalid_config_format}
end
end
Is the code properly tested?
Testing concerns:
# BAD: Unclear test name
test "test1" do
# ...
end
# GOOD: Descriptive test name
test "create_user/1 returns error when email is invalid" do
# ...
end
# BAD: Testing too much at once
test "user workflow" do
# Creates user
# Updates user
# Deletes user
# All in one test!
end
# GOOD: Focused tests
test "create_user/1 creates user with valid attributes" do
# ...
end
test "update_user/2 updates user name" do
# ...
end
test "delete_user/1 removes user from database" do
# ...
end
# BAD: Non-deterministic test
test "async operation completes" do
start_async_operation()
Process.sleep(100) # Race condition!
assert operation_completed?()
end
# GOOD: Deterministic test
test "async operation completes" do
start_async_operation()
assert_receive {:completed, _result}, 1000
end
Is the code documented?
Are dependencies handled properly?
Understand the context
Build and test locally
Start with the big picture
Review for correctness
Check security and performance
Review code quality
Be constructive and specific:
# BAD: Vague criticism
"This function is bad."
# GOOD: Specific, actionable feedback
"This function has three responsibilities: validation, database update, and email sending. Consider splitting it into separate functions for better testability and maintainability:
```elixir
def update_user(user, attrs) do
with {:ok, changeset} <- validate_user_update(user, attrs),
{:ok, user} <- save_user(changeset),
:ok <- send_update_notification(user) do
{:ok, user}
end
end
"You must change this."
"What do you think about extracting this into a separate function? It would make the code easier to test."
"Use single quotes instead of double quotes."
"Our style guide prefers single quotes for consistency (see CONTRIBUTING.md section 3.2)."
**Use labels to categorize feedback:**
- **[blocking]**: Must be fixed before merging
- **[suggestion]**: Optional improvement
- **[question]**: Asking for clarification
- **[nit]**: Very minor, cosmetic issue
- **[security]**: Security concern
- **[performance]**: Performance concern
**Example:**
```markdown
[blocking] This creates a SQL injection vulnerability. Use parameterized queries:
```elixir
# Instead of:
query = "SELECT * FROM users WHERE name = '#{name}'"
# Use:
from(u in User, where: u.name == ^name)
[suggestion] Consider extracting this logic into a separate function for reusability.
[question] Why are we using a map here instead of a struct?
[nit] Extra blank line here.
### After Review
1. **Respond to author's questions**
2. **Re-review after changes**
3. **Approve when satisfied**
4. **Celebrate good code**
## Language-Specific Considerations
### Elixir
- Pattern matching is used effectively
- Functions leverage pipe operator for readability
- Atoms aren't created dynamically from untrusted input
- `with` statements handle errors properly
- Changesets validate all input
- No direct database queries in controllers/LiveViews (use contexts)
### JavaScript/TypeScript
- Types are properly defined (TypeScript)
- Promises are handled with .catch() or try/catch
- == vs === is used correctly
- Arrays/objects aren't mutated unexpectedly
- this binding is correct
- Async operations are properly awaited
### Python
- Type hints are used
- List comprehensions aren't overly complex
- Exceptions are specific (not bare except:)
- Resources are closed (use with statements)
- Code follows PEP 8
### Rust
- Ownership and borrowing are correct
- Error handling uses Result/Option properly
- Unsafe blocks are justified and minimal
- Clone/copy is used appropriately
- Lifetimes are correctly specified
## Common Code Smells
### Complexity Smells
- **Long functions** - Function does too much
- **Long parameter list** - Too many parameters
- **Deep nesting** - Too many levels of indentation
- **Complex conditionals** - Hard to understand if statements
### Duplication Smells
- **Copy-paste code** - Same code in multiple places
- **Similar functions** - Functions that do almost the same thing
- **Magic numbers** - Repeated literal values
### Naming Smells
- **Unclear names** - Variables like x, tmp, data
- **Misleading names** - Name doesn't match behavior
- **Inconsistent names** - Same concept called different things
### Design Smells
- **God object** - Class/module doing everything
- **Feature envy** - Function using another object's data more than its own
- **Inappropriate intimacy** - Too much coupling between modules
## Anti-Patterns to Watch For
### Premature Optimization
```elixir
# BAD: Optimizing before measuring
def calculate(data) do
# Complex, hard-to-read optimization
# that saves 0.1ms
end
# GOOD: Start simple, optimize if needed
def calculate(data) do
# Clear, simple code
# Optimize later if profiling shows bottleneck
end
# BAD: Abstract after one use
defmodule AbstractDataProcessorFactoryBuilder do
# Complex abstraction for single use case
end
# GOOD: Wait for second use case
def process_user_data(data) do
# Simple, direct implementation
# Abstract when pattern emerges
end
# BAD: Hiding errors
try do
risky_operation()
rescue
_ -> :ok # What went wrong?
end
# GOOD: Handle explicitly
case risky_operation() do
{:ok, result} -> {:ok, result}
{:error, reason} ->
Logger.error("Operation failed: #{inspect(reason)}")
{:error, reason}
end
Before submitting code for review:
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.