wispbit Rules

No important tag in CSS

Do not use the !important declaration in CSS styles. Bad: `css .element { color: red !important; margin-top: 10px !important; } `

css

HTTP conventions in Express API endpoints

Ensure that for any new endpoint, the status code is matched with the correct purpose: - Use 401 Unauthorized for authentication failures (when credentials are missing or invalid) - Use 403 Forbidden for authorization failures (when user is authenticated but lacks required permissions) - Use 404 Not Found for resources that don't exist - Use 400 Bad Request for invalid request parameters - Use 500 Internal Server Error for server-side errors Bad: `typescript // Wrong status code for permission error app.get("/resource", (req: Request, res: Response) => { if (!req.user) { return res.status(401).json({ error: "Permission denied" }) } if (!hasPermission(req.user, "read_resource")) { return res.status(401).json({ error: "Permission denied" }) // Wrong code } // Resource handling... }) ` Good: `typescript // Correct status codes for different scenarios app.get("/resource", (req: Request, res: Response) => { if (!req.user) { return res.status(401).json({ error: "Authentication required" }) } if (!hasPermission(req.user, "read_resource")) { return res.status(403).json({ error: "Permission denied" }) // Correct code } // Resource handling... }) `

typescript

expressjs

HTTP conventions in API endpoints

Ensure that for any new endpoint, the status code is matched with the correct purpose: - Use 401 Unauthorized for authentication failures (when credentials are missing or invalid) - Use 403 Forbidden for authorization failures (when user is authenticated but lacks required permissions) - Use 404 Not Found for resources that don't exist - Use 400 Bad Request for invalid request parameters - Use 500 Internal Server Error for server-side errors Bad: `python Wrong status code for permission error @app.route('/resource') def get_resource(): if not user.is_authenticated: return jsonify({"error": "Permission denied"}), 401 if not user.has_permission('read_resource'): return jsonify({"error": "Permission denied"}), 401 # Wrong code # ... ` Good: `python Correct status codes for different scenarios @app.route('/resource') def get_resource(): if not user.is_authenticated: return jsonify({"error": "Authentication required"}), 401 if not user.has_permission('read_resource'): return jsonify({"error": "Permission denied"}), 403 # Correct code # ... `

python

flask

quart

Avoid getter methods in Go

Avoid using "getter" methods in Go code. Instead, expose fields directly when appropriate, following Go's idiomatic approach to visibility. Bad: `go type Person struct { name string age int } func (p *Person) GetName() string { return p.name } func (p *Person) GetAge() int { return p.age } // Usage name := person.GetName() ` Good: `go type Person struct { Name string Age int } // Usage name := person.Name `

golang

Early returns in Go

Use early returns to reduce nesting levels. Prefer checking error conditions or guard clauses first and returning early, rather than wrapping the main logic in deep conditional blocks. Bad: `go func processData(data []string) (string, error) { if len(data) > 0 { if isValid(data) { result := "" for _, item := range data { if item != "" { // More nested code here result += transform(item) } } return result, nil } else { return "", errors.New("invalid data") } } else { return "", errors.New("empty data") } } ` Good: `go func processData(data []string) (string, error) { if len(data) == 0 { return "", errors.New("empty data") } if !isValid(data) { return "", errors.New("invalid data") } result := "" for _, item := range data { if item == "" { continue } result += transform(item) } return result, nil } `

golang

Inline error assignment in Go

Use inline error assignment with the := operator when checking for errors. Bad: `go var err error result, err = someFunction() if err != nil { return err } ` Good: `go if result, err := someFunction(); err != nil { return err } `

golang

Structured logging in Go

Always use structured logging with field-based approaches instead of string formatting when logging in Go. Bad: `go logger.Info(fmt.Sprintf("User %s logged in from IP %s with status %d", username, ipAddress, statusCode)) ` Good: `go logger.Info("User authentication", "username", username, "ip", ipAddress, "status", statusCode, ) `

golang

Avoid unnecessary else blocks in Go

Avoid unnecessary else blocks when the if block ends with a return statement, break, continue, or similar control flow statements. Bad: `go func processValue(value int) string { if value > 10 { return "high" } else { return "low" } } ` `go func checkItems(items []string) { for _, item := range items { if len(item) > 5 { fmt.Println("Long item:", item) continue } else { fmt.Println("Short item:", item) } } } ` Good: `go func processValue(value int) string { if value > 10 { return "high" } return "low" } ` `go func checkItems(items []string) { for _, item := range items { if len(item) > 5 { fmt.Println("Long item:", item) continue } fmt.Println("Short item:", item) } } `

golang

Use structured logger in Go

Use the structured logger for all logging operations instead of fmt.Print or log package functions. Bad: `go import ( "fmt" "log" ) func processOrder(order Order) error { fmt.Println("Processing order:", order.ID) if err := validateOrder(order); err != nil { log.Printf("Error validating order %s: %v", order.ID, err) return err } return nil } ` Good: `go import ( "github.com/yourproject/logger" ) func processOrder(order Order) error { logger.Info("Processing order", "orderID", order.ID) if err := validateOrder(order); err != nil { logger.Error("Failed to validate order", "orderID", order.ID, "error", err) return err } return nil } `

golang

Use Zap logger in Go

Use Zap for all logging in Go code. Bad: `go func processOrder(order Order) error { fmt.Printf("Processing order %s\n", order.ID) if err := validateOrder(order); err != nil { log.Printf("Error validating order: %v", err) return err } fmt.Println("Order processed successfully") return nil } ` Good: `go func processOrder(order Order) error { logger := zap.L().With(zap.String("orderID", order.ID)) logger.Info("Processing order") if err := validateOrder(order); err != nil { logger.Error("Failed to validate order", zap.Error(err)) return err } logger.Info("Order processed successfully") return nil } `

golang

Mark fields as deprecated in GraphQL

When removing fields from a GraphQL schema, follow a progressive deprecation process: 1. First, mark the field to be removed as deprecated using the @deprecated directive 2. Introduce the new alternative field in the same operation 3. Only remove deprecated fields after they have been deprecated for a sufficient time period Bad: `graphql // Before type User { id: ID! oldEmail: String! } // After (directly removing the field) type User { id: ID! } ` Good: `graphql // Step 1: Mark as deprecated and introduce alternative type User { id: ID! oldEmail: String! @deprecated(reason: "Use 'email' field instead") email: String! } // Step 2: Only later, remove the deprecated field type User { id: ID! email: String! } `

graphql

Check for duplicates in Markdown

Check documentation for duplicate adjacent words, which are typically typos. Bad: ` prefix adds a prefix to the the column names which is useful for merging the result ` Good: ` prefix adds a prefix to the column names which is useful for merging the result `

markdown

Use code highlighting in Markdown

Specify the appropriate language for code blocks to enable proper syntax highlighting. For CLI commands use bash, and for Python code use py or python. Bad: `markdown transformers chat Qwen/Model-Name --torch_dtype auto ` Good: markdown `bash transformers chat Qwen/Model-Name --torch_dtype auto ` ` `

markdown

Prefer Image in NextJS

Always use Next.js <Image> component instead of HTML <img> tag. Bad: `jsx function ProfileCard() { return ( <div className="card"> <img src="/profile.jpg" alt="User profile" width={200} height={200} /> <h2>User Name</h2> </div> ) } ` Good: `jsx import Image from "next/image" function ProfileCard() { return ( <div className="card"> <Image src="/profile.jpg" alt="User profile" width={200} height={200} priority={false} /> <h2>User Name</h2> </div> ) } `

nextjs

Do not rename columns

When renaming columns in PostgreSQL, follow a safe migration pattern to avoid breaking changes to applications: 1. Create a new column 2. Update application code to write to both the old and new columns 3. Backfill data from the old column to the new column 4. Update application code to read from the new column instead of the old one 5. Once all deployments are complete, stop writing to the old column 6. Drop the old column in a later migration Bad: `sql ALTER TABLE users RENAME COLUMN some_column TO new_name; `

postgresql

prisma

supabase

mysql

drizzle

migrations

Do not rename tables

When renaming tables, use a multi-step approach instead of direct renaming to prevent downtime. 1. Create a new table 2. Write to both tables 3. Backfill data from the old table to the new table 4. Move reads from the old table to the new table 5. Stop writing to the old table 6. Drop the old table Bad: `sql ALTER TABLE users RENAME TO customers; `

postgresql

prisma

supabase

mysql

drizzle

migrations

Avoid aliases for new routes in PHP

Only use route aliases for backward compatibility with renamed or moved routes. Do not add aliases to newly created routes. Bad: `php // Adding an alias to a new route Route::put('/api/users/{id}') ->alias('/api/user/{id}'); // Another framework example $router->map('GET', '/products/{productId}', 'ProductController::show') ->alias('product.show.alt'); ` Good: `php // New route without an alias Route::put('/api/users/{id}'); `

php

Prefer switch statements in PHP

Use switch statements when handling multiple attribute types. Bad: `php foreach ($attributes as $attribute) { if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { // Handle relationship attribute } if ($attribute->getAttribute('type') === Database::VAR_STRING) { // Handle string attribute } } ` Good: `php foreach ($attributes as $attribute) { $attributeType = $attribute->getAttribute('type'); switch ($attributeType) { case Database::VAR_RELATIONSHIP: // Handle relationship attribute break; case Database::VAR_STRING: // Handle string attribute break; } } `

php

Add indexes for foreign keys in PostgreSQL

When adding a foreign key constraint in PostgreSQL, always add a corresponding index. Bad: `sql ALTER TABLE orders ADD CONSTRAINT fk_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id); ` Good: `sql ALTER TABLE orders ADD CONSTRAINT fk_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id); CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders (user_id); `

postgresql

prisma

supabase

drizzle

migrations

Always have id, created_at, updated_at columns in PostgreSQL

All CREATE TABLE statements must include id, created_at, and updated_at columns. Bad: `sql CREATE TABLE users ( email VARCHAR(255) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL ); ` Good: `sql CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); `

postgresql

prisma

supabase

drizzle

migrations

Column naming standards in PostgreSQL

Maintain consistent naming conventions for new columns. Bad `sql -- Bad: Column named uuid instead of id ALTER TABLE users ADD COLUMN uuid UUID PRIMARY KEY DEFAULT gen_random_uuid(); ` `sql -- Bad: Column named camelCase instead of snake_case ALTER TABLE users ADD COLUMN firstName VARCHAR(255); ` `sql -- Bad: Column foreign key ends with uuid instead of id ALTER TABLE orders ADD COLUMN user_uuid UUID REFERENCES users(id); ` Good `sql -- Good: Consistent naming ALTER TABLE users ADD COLUMN id UUID PRIMARY KEY DEFAULT gen_random_uuid(); ALTER TABLE users ADD COLUMN first_name VARCHAR(255); ALTER TABLE orders ADD COLUMN user_id UUID REFERENCES users(uuid); `

postgresql

prisma

supabase

drizzle

migrations

Index naming standards in PostgreSQL

For indexes, use the following naming standards: - idx_tablename_columnname for single column indexes, - idx_tablename_col1_col2 for multi-column indexes Bad `sql -- Bad: Inconsistent and unclear index names CREATE INDEX email_index ON users(email); CREATE INDEX user_orders ON orders(user_id); CREATE INDEX idx_prod_cat_stat ON products(category, status); ` Good `sql -- Good: Consistent index naming CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_orders_user_id ON orders(user_id); CREATE INDEX idx_products_category_status ON products(category, status); `

postgresql

prisma

supabase

drizzle

migrations

Limit non unique indexes in PostgreSQL

Limit non-unique indexes to a maximum of three columns in PostgreSQL databases: Bad: `sql CREATE INDEX index_users_on_multiple_columns ON users (column_a, column_b, column_c, column_d); ` Good: `sql CREATE INDEX CONCURRENTLY index_users_on_selective_columns ON users (column_d, column_b); `

postgresql

prisma

supabase

drizzle

migrations

Only concurrent indexes in PostgreSQL

When creating indexes in PostgreSQL, always use the CONCURRENTLY option to prevent blocking writes during index creation. Bad: `sql CREATE INDEX idx_users_email ON users(email); ` Good: `sql CREATE INDEX CONCURRENTLY idx_users_email ON users(email); `

postgresql

prisma

supabase

drizzle

migrations

Always use JSONB in PostgreSQL

Always use jsonb instead of json data type when creating columns in PostgreSQL databases. Bad: `sql ALTER TABLE users ADD COLUMN properties json; ` Good: `sql ALTER TABLE users ADD COLUMN properties jsonb; `

postgresql

prisma

supabase

drizzle

migrations

Use check constraints for setting NOT NULL columns in PostgreSQL

When adding a NOT NULL constraint to an existing column in PostgreSQL, use a check constraint first to avoid blocking reads and writes while every row is checked. Bad: `sql -- This can cause performance issues with large tables ALTER TABLE users ALTER COLUMN some_column SET NOT NULL; ` Good: `sql -- Step 1: Add a check constraint without validation ALTER TABLE users ADD CONSTRAINT users_some_column_null CHECK (some_column IS NOT NULL) NOT VALID; -- Step 2: In a separate transaction, validate the constraint ALTER TABLE users VALIDATE CONSTRAINT users_some_column_null; -- Step 3: Add the NOT NULL constraint and remove the check constraint ALTER TABLE users ALTER COLUMN some_column SET NOT NULL; ALTER TABLE users DROP CONSTRAINT users_some_column_null; `

postgresql

prisma

supabase

drizzle

migrations

Split foreign keys in PostgreSQL

When adding foreign keys in Postgres migrations, split the operation into two steps to avoid blocking writes on both tables: 1. First create the foreign key constraint without validation 2. Then validate existing data in a separate migration Bad: `sql -- In a single migration ALTER TABLE users ADD CONSTRAINT fk_users_orders FOREIGN KEY (order_id) REFERENCES orders (id); ` Good: `sql -- In first migration: add without validating ALTER TABLE users ADD CONSTRAINT fk_users_orders FOREIGN KEY (order_id) REFERENCES orders (id) NOT VALID; -- In second migration: validate existing data ALTER TABLE users VALIDATE CONSTRAINT fk_users_orders; `

postgresql

prisma

supabase

drizzle

migrations

Split unique constraints in PostgreSQL

When adding unique constraints in PostgreSQL, create the unique index concurrently first before adding the constraint to avoid blocking reads and writes. Bad: `sql -- Creates a unique constraint directly, which blocks reads and writes ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE (email); ` Good: `sql -- First create a unique index concurrently (non-blocking) CREATE UNIQUE INDEX CONCURRENTLY users_email_unique_idx ON users (email); -- Then add the constraint using the existing index ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE USING INDEX users_email_unique_idx; `

postgresql

prisma

supabase

drizzle

migrations

Ensure removed column is ignored in Prisma

When creating a migration to remove a column from the database, ensure that the schema has the @ignore attribute on that column in the Prisma schema. Search for the .prisma schema in the codebase to verify this. `sql ALTER TABLE "User" DROP COLUMN "createdAt"; ALTER TABLE "User" DROP COLUMN "updatedAt"; ` `prisma model User { id Int @id @default(autoincrement()) email String @unique password String remarks String? createdAt DateTime @default(now()) @ignore updatedAt DateTime @updatedAt @ignore } `

postgresql

prisma

migrations

Avoid duplicate words in Python

Check all text elements (comments, docstrings, and string literals) for duplicate adjacent words for typos or duplicates. Bad: `python This function validates the the input parameters def validate_input(data): ... ` Good: `python This function validates the input parameters def validate_input(data): ... `

python

Self documenting code in Python

Avoid unnecessary explanatory comments for code that is self-documenting. Comments should only be used when they add context that the code itself cannot convey. Bad: `python Join the test directory with the base directory test_dir = os.path.join(BASE_DIR, test_case.identifier) ` Good: `python test_dir = os.path.join(BASE_DIR, test_case.identifier) `

python

Avoid print in Python tests

Avoid using print() statements in test files. Bad: `python def test_example(): result = some_function() print(result) # Debugging statement left in the code assert result == expected_value ` Good: `python def test_example(): result = some_function() assert result == expected_value `

python

Consistent error classes in Python

Use consistent naming conventions for error classes in Python. Bad: `python class PublicAPiError(Exception): # Inconsistent casing in "APi" - should be either "Api" or "API" pass class UnauthorizedHTtpError(Exception): # Inconsistent casing in "HTtp" - should be either "Http" or "HTTP" pass ` Good: `python class PublicApiError(Exception): # Consistent Pascal casing with "Api" pass class UnauthorizedHttpError(Exception): # Consistent Pascal casing with "Http" pass `

python

Python DRY

Avoid duplicating code in Python. Extract repeated logic into reusable functions, classes, or constants. You may have to search the codebase to see if the function or class is already defined. Bad: `python Duplicated class definitions class User: def __init__(self, id: str, name: str): self.id = id self.name = name class UserProfile: def __init__(self, id: str, name: str): self.id = id self.name = name Magic numbers repeated page_size = 10 items_per_page = 10 ` Good: `python Reusable class and constant class User: def __init__(self, id: str, name: str): self.id = id self.name = name PAGE_SIZE = 10 `

python

Avoid duplicate variable reassignment in Python

Avoid assigning a variable to itself or reassigning a variable with the same value. Bad: `python Redundant self-assignment x = 10 x = x # Unnecessary reassignment Duplicate assignment with the same value y = "hello" ... some code ... y = "hello" # Unnecessary reassignment with identical value ` Good: `python Single, clear assignment x = 10 Only reassign when the value changes y = "hello" ... some code ... y = "updated value" # Value actually changes `

python

Early returns in Python

Use early returns to reduce nesting levels. Instead of wrapping large code blocks in conditional statements, return early when conditions are not met. Bad: `python def process_user(user): if user is not None: if user.is_active: # Many lines of processing code result = perform_complex_operation(user) return result return None ` Good: `python def process_user(user): if user is None: return None if not user.is_active: return None # Now we can work with user without nesting # Many lines of processing code result = perform_complex_operation(user) return result `

python

No unused code in python

Do not leave commented-out code blocks in Python files. If code is no longer needed, remove it entirely rather than commenting it out. Bad: `python def calculate_total(items): total = 0 for item in items: total += item.price # Old calculation method that we might need later # subtotal = 0 # for item in items: # if item.type != 'tax': # subtotal += item.price # tax = calculate_tax(subtotal) # total = subtotal + tax return total ` Good: `python def calculate_total(items): total = 0 for item in items: total += item.price return total `

python

Unnecessary else blocks in Python

Avoid unnecessary else blocks when the if block ends with a return statement, break, continue, or similar control flow statements. Bad: `python def process_value(value): if value > 10: return "high" else: return "low" ` `python def check_items(items): for item in items: if len(item) > 5: print("Long item:", item) continue else: print("Short item:", item) ` Good: `python def process_value(value): if value > 10: return "high" return "low" ` `python def check_items(items): for item in items: if len(item) > 5: print("Long item:", item) continue print("Short item:", item) `

python

Avoid unncecessary try except in Python

When using try-except blocks in Python, keep the try block focused only on the code that can raise the expected exception. Bad: `python try: # Large block of code with many potential errors user_data = get_user_data() process_data(user_data) save_to_db(user_data) except (NetworkError, DBError): logger.error("Operation failed") ` Bad: `python try: # Contains only one potential error but still # has a block of code unrelated to the exception url = "https://google.com" url += "/?search=hello" response = requests.get(url) data = response.json() print(data) except NetworkError as e: logger.error(f"Error: {e}") ` Bad: `python Try except blocks are nested into each other try: response = client.beta.chat.completions.parse( model="some-model", messages=[ {"role": "system", "content": "hello"}, {"role": "user", "content": "how are you"}, ], ) try: json.loads(response.choices[0].message.parsed) except json.JSONDecodeError as e: logger.error(f"Decode failed: {e}") except requests.RequestException as e: logger.error(f"Error: {e}") ` Good: `python try: # Only one function that could have an error user_data = get_user_data() except NetworkError: logger.error("Failed to fetch user data") return Cannot raise an exception so it doesn't need to be handled process_data(user_data) try: # Only one potential error save_to_db(user_data) except DBError: logger.error("Failed to save to database") return ` Good: `python url = "https://google.com" url += "/?search=hello" Network call is a separate try except block try: response = requests.get(url) response.raise_for_status() except RequestException as e: logger.error(f"Error: {e}") Getting response in json is a separate try except block try: data = response.json() except JSONDecodeError as e: logger.error(f"Error: {e}") ` Good: `python Blocks that were nested before are now unnested into separate blocks try: response = client.beta.chat.completions.parse( model="some-model", messages=[ {"role": "system", "content": "hello"}, {"role": "user", "content": "how are you"}, ], ) except requests.RequestException as e: logger.error(f"Error: {e}") try: json.loads(response.choices[0].message.parsed) except json.JSONDecodeError as e: logger.error(f"Decode failed: {e}") `

python

Enforce component design system in React

All design system components must use forwardRef pattern, CVA for variants, and follow the established component structure. Bad: `typescript interface ButtonProps { className?: string variant?: string size?: string children: React.ReactNode } const Button = ({ className, variant, size, children, ...props }: ButtonProps) => { let baseClasses = "inline-flex items-center justify-center rounded-md text-sm font-medium" if (variant === "destructive") { baseClasses += " bg-red-500 text-white" } else { baseClasses += " bg-blue-500 text-white" } if (size === "sm") { baseClasses += " h-9 px-3" } else { baseClasses += " h-10 px-4 py-2" } return ( <button className={${baseClasses} ${className}} {...props}> {children} </button> ) } ` Good: `typescript import { cva, type VariantProps } from "class-variance-authority" import { clx } from "../utils" const buttonVariants = cva( "inline-flex items-center justify-center rounded-md text-sm font-medium", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", }, }, defaultVariants: { variant: "default", size: "default", }, } ) export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {} const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( ({ className, variant, size, ...props }, ref) => { return ( <button className={clx(buttonVariants({ variant, size }), className)} ref={ref} {...props} /> ) } ) Button.displayName = "Button" export { Button, buttonVariants } `

nextjs

react

typescript

Check for duplicate components

Favor existing components over creating new ones. Before creating a new component, check if an existing component can satisfy the requirements through its props and parameters. Bad: `tsx // Creating a new component that duplicates functionality export function FormattedDate({ date, variant }) { // Implementation that duplicates existing functionality return <span>{/ formatted date /}</span> } ` Good: `tsx // Using an existing component with appropriate parameters import { DateTime } from "./DateTime" function Page() { return <DateTime date={date} variant={variant} noTrigger={true} /> } `

nextjs

react

typescript

Internal links in React

When linking between internal sites, use rel="noopener" instead of rel="noopener noreferrer". Bad: `jsx // For internal links, don't use noreferrer <Link to="/dashboard" rel="noopener noreferrer">Dashboard</Link> // Or with anchor tags <a href="/about" rel="noopener noreferrer">About Us</a> ` Good: `jsx // For internal links, only use noopener <Link to="/dashboard" rel="noopener">Dashboard</Link> // Or with anchor tags <a href="/about" rel="noopener">About Us</a> // For external links, noreferrer can be appropriate <a href="https://external-site.com" rel="noopener noreferrer" target="_blank">External Site</a> `

react

typescript

No random numbers in React

Do not generate non-deterministic values like random IDs during render in React components. This causes hydration errors because the server-rendered HTML will not match what the client generates. Avoid using functions like Math.random(), Date.now(), uuid(), or any other source of randomness directly in your render function or JSX. Instead: - Generate IDs in useEffect hooks - Use stable IDs based on props or state - Use refs to store generated values - Use libraries that support SSR (like uuid with specific configuration) Bad: `tsx function UserCard() { // This will generate different values on server and client const id = user-${Math.random()} return ( <div id={id}> <input aria-labelledby={label-${Math.floor(Math.random() * 1000)}} /> </div> ) } ` Good: `tsx function UserCard({ userId }) { // Using stable props for IDs const id = user-${userId} // For dynamic IDs, use useEffect and useState const [randomId, setRandomId] = useState(null) useEffect(() => { // Generate random values after mounting setRandomId(label-${Math.floor(Math.random() * 1000)}) }, []) return <div id={id}>{randomId && <input aria-labelledby={randomId} />}</div> } `

nextjs

react

typescript

No unused components

Do not leave commented-out components. Either remove unused components entirely or implement them properly. Bad: `tsx function MyComponent() { return ( <div> <Header /> {/* <Sidebar> <Navigation /> </Sidebar> */} <MainContent /> </div> ) } ` Good: `tsx function MyComponent() { return ( <div> <Header /> <MainContent /> </div> ) } `

nextjs

react

typescript

Early returns in Ruby

Use early returns to reduce nesting levels. Prefer checking error conditions or guard clauses first and returning early, rather than wrapping the main logic in deep conditional blocks. Bad `ruby def process_data(data) if data.present? if valid?(data) result = "" data.each do |item| if item.present? # More nested code here result += transform(item) end end { success: result } else { error: "invalid data" } end else { error: "empty data" } end end ` Good `ruby def process_data(data) return { error: "empty data" } if data.empty? return { error: "invalid data" } unless valid?(data) result = "" data.each do |item| next if item.blank? result += transform(item) end { success: result } end `

ruby

rails

External API error handling in Ruby

When making external API requests, implement proper error handling with descriptive logging to help with debugging issues. Bad: `ruby def fetch_external_data response = HTTParty.get("https://api.example.com/data") JSON.parse(response.body) end ` Good: `ruby def fetch_external_data response = HTTParty.get("https://api.example.com/data") if response.success? JSON.parse(response.body) else Rails.logger.error("API request failed: status=#{response.code}, message=#{response.message}, body=#{response.body}") nil end end `

ruby

rails

Avoid unnecessary else blocks in Ruby

Avoid unnecessary else blocks when the if block ends with a return statement, break, next, or similar control flow statements. Bad: `ruby def process_value(value) if value > 10 return "high" else return "low" end end ` `ruby def check_items(items) items.each do |item| if item.length > 5 puts "Long item: #{item}" next else puts "Short item: #{item}" end end end ` Good: `ruby def process_value(value) if value > 10 return "high" end "low" end ` `ruby def check_items(items) items.each do |item| if item.length > 5 puts "Long item: #{item}" next end puts "Short item: #{item}" end end `

ruby

rails

Check character boundaries in Rust

When truncating strings, ensure you check character boundaries to prevent panics with multi-byte UTF-8 characters. Bad: `rust // This can cause a panic if truncation happens in the middle of a multi-byte character let mut value = some_string; value.truncate(limit); ` Good: `rust // Check character boundaries before truncating let mut value = some_string; let mut index = limit; while !value.is_char_boundary(index) { index -= 1; } value.truncate(index); `

rust

Use triple slash for documentation in Rust

Use triple slashes (///) for documenting Rust functions and methods. Bad: `rust // This function processes tenant requests fn process_tenant_request() { // implementation } ` Good: `rust /// This function processes tenant requests fn process_tenant_request() { // implementation } `

rust

Prefer logging instead of panicking in Rust

Use logging instead of panicking for recoverable errors. For operations that might fail but don't compromise the entire application state, log the error and provide a fallback rather than panicking. Bad: `rust let top = editor.row_for_block(decorations.prompt_block_id, cx).unwrap(); let bottom = editor.row_for_block(decorations.end_block_id, cx).unwrap(); ` Good: `rust let scroll_target_range = maybe!({ let top = editor.row_for_block(decorations.prompt_block_id, cx)?.0 as f32; let bottom = editor.row_for_block(decorations.end_block_id, cx)?.0 as f32; Some((top, bottom)) }); if scroll_target_range.is_none() { log::error!("bug: failed to find blocks for scrolling to inline assist"); } // Use a fallback value when the operation fails let scroll_target_range = scroll_target_range.unwrap_or_else(|| { // fallback calculation }); `

rust

Shell script best practices

Follow these shell script best practices when writing or modifying bash scripts: 1. Use #!/usr/bin/env bash instead of #!/bin/bash for better portability Bad: `bash !/bin/bash echo "Hello World" ` Good: `bash !/usr/bin/env bash echo "Hello World" ` 2. Use ${variable} syntax for all variable references Bad: `bash name="Alice" echo "Hello $name" ` Good: `bash name="Alice" echo "Hello ${name}" ` 3. Use double quotes around variable expansions to prevent word splitting and globbing Bad: `bash files=$(ls) for file in $files; do rm $file done ` Good: `bash files=$(ls) for file in "${files}"; do rm "${file}" done ` 4. Use [[ and ]] instead of [ and ] for conditional expressions Bad: `bash if [ -z "$input" ] || [ "$input" = "exit" ]; then echo "Exiting..." exit 0 fi ` Good: `bash if [[ -z "${input}" || "${input}" = "exit" ]]; then echo "Exiting..." exit 0 fi ` 5. Use printf '%s\n' instead of echo for output with special characters Bad: `bash output="Text with special chars: * & $HOME" echo $output ` Good: `bash output="Text with special chars: * & $HOME" printf '%s\n' "${output}" ` 6. Use readonly for constants that should not be modified Bad: `bash CONFIG_PATH="/etc/app/config.json" LOG_DIR="/var/log/app" ` Good: `bash readonly CONFIG_PATH="/etc/app/config.json" readonly LOG_DIR="/var/log/app" ` 7. Use | as delimiter in sed commands when replacing paths containing slashes Bad: `bash sed -i "s/${source_path}/${target_path}/" "${config_file}" ` Good: `bash sed -i "s|${source_path}|${target_path}|" "${config_file}" `

shell

Split check constraints

When adding check constraints in migrations, split the operation into two steps to avoid blocking writes during the table scan: 1. First create the check constraint without validation 2. Then validate existing data in a separate migration Bad: `sql -- In a single migration ALTER TABLE users ADD CONSTRAINT ck_users_age_positive CHECK (age >= 0); ` Good: `sql -- In first migration: add without validating ALTER TABLE users ADD CONSTRAINT ck_users_age_positive CHECK (age >= 0) NOT VALID; -- In second migration: validate existing data ALTER TABLE users VALIDATE CONSTRAINT ck_users_age_positive; `

postgresql

prisma

supabase

mysql

drizzle

migrations

Change column types safely in SQLAlchemy

When changing a column type that requires a table rewrite, follow these steps: 1. Create a new column with the desired type 2. Write to both columns during the transition period 3. Backfill data from the old column to the new column 4. Move reads from the old column to the new column 5. Stop writing to the old column 6. Drop the old column Bad: `python def upgrade(): # Directly changing a column type can cause table locks op.alter_column('users', 'some_column', type_=sa.String(50), existing_type=sa.Integer()) def downgrade(): op.alter_column('users', 'some_column', type_=sa.Integer(), existing_type=sa.String(50)) ` Good: `python Migration 1: Add new column def upgrade(): # Adding a new column first op.add_column('users', sa.Column('some_column_new', sa.String(50))) def downgrade(): op.drop_column('users', 'some_column_new') ` `python Migration 2: Complete the transition (after backfilling data) def upgrade(): # After ensuring all data is migrated op.drop_column('users', 'some_column') op.alter_column('users', 'some_column_new', new_column_name='some_column') def downgrade(): op.alter_column('users', 'some_column', new_column_name='some_column_new') op.add_column('users', sa.Column('some_column', sa.Integer())) `

postgresql

mysql

sqlalchemy

migrations

alembic

Ensure index is not already covered in SQLAlchemy

Ensure that individual column indexes in SQLAlchemy are not covered by existing composite indexes. Bad: `python class User(Base): __tablename__ = "users" __table_args__ = ( Index("email_username_idx", "email", "username"), ) id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(String(255), index=True) # covered by email_username_idx username: Mapped[str] = mapped_column(String(100)) status: Mapped[str] = mapped_column(String(20)) ` Good: `python class User(Base): __tablename__ = "users" # Only composite index needed - covers both email and email+username queries __table_args__ = ( Index("email_username_idx", "email", "username"), ) id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(String(255)) username: Mapped[str] = mapped_column(String(100)) status: Mapped[str] = mapped_column(String(20)) `

postgresql

sqlalchemy

alembic

migrations

Limit non unique indexes in SQLAlchemy

Limit non-unique indexes to a maximum of three columns in PostgreSQL databases: Bad: `python def upgrade(): with op.get_context().autocommit_block(): op.create_index( 'index_users_on_multiple_columns', 'users', ['column_a', 'column_b', 'column_c', 'column_d'], postgresql_concurrently=True ) ` Good: `python def upgrade(): # Limit to most selective columns for better performance with op.get_context().autocommit_block(): op.create_index( 'index_users_on_selective_columns', 'users', ['column_d', 'column_b'], postgresql_concurrently=True ) `

postgresql

sqlalchemy

alembic

migrations

Only concurrent indexes in SQLAlchemy

When creating or dropping indexes in PostgreSQL using SQLAlchemy migrations, always use the postgresql_concurrently=True option within an autocommit block. This prevents blocking writes during index operations. For upgrade(): Bad: `python def upgrade(): op.create_index('idx_users_email', 'users', ['email']) ` Good: `python def upgrade(): with op.get_context().autocommit_block(): op.create_index('idx_users_email', 'users', ['email'], postgresql_concurrently=True) ` For downgrade(): Bad: `python def downgrade(): op.drop_index('idx_users_email', 'users') ` Good: `python def downgrade(): with op.get_context().autocommit_block(): op.drop_index('idx_users_email', 'users', postgresql_concurrently=True) `

postgresql

sqlalchemy

migrations

alembic

Add check constraints safely in SQLAlchemy

When adding check constraints that could affect large tables, create the constraint with NOT VALID first to avoid blocking writes during the validation scan. Bad: `python def upgrade(): # Directly creating a check constraint blocks writes during table scan op.create_check_constraint( 'ck_users_age_positive', 'users', 'age >= 0' ) ` Good: `python Migration 1: Create check constraint without validation def upgrade(): # Create the check constraint without validating existing data (non-blocking) op.create_check_constraint( 'ck_users_age_positive', 'users', 'age >= 0', postgresql_not_valid=True ) ` `python Migration 2: Validate existing data def upgrade(): op.execute('ALTER TABLE users VALIDATE CONSTRAINT ck_users_age_positive') `

postgresql

sqlalchemy

alembic

migrations

Add foreign keys safely in SQLAlchemy

When adding foreign keys in SQLAlchemy migrations, split the operation into two steps to avoid blocking writes on both tables: 1. First create the foreign key constraint without validation 2. Then validate existing data in a separate migration Bad: `python def upgrade(): # Directly creating a foreign key constraint can block writes on both tables op.create_foreign_key( 'fk_users_orders', 'users', 'orders', ['order_id'], ['id'] ) ` Good: `python Migration 1: Add foreign key without validation def upgrade(): # Create the foreign key constraint without validating existing data op.create_foreign_key( 'fk_users_orders', 'users', 'orders', ['order_id'], ['id'], postgresql_not_valid=True ) ` `python Migration 2: Validate existing data def upgrade(): op.execute('ALTER TABLE users VALIDATE CONSTRAINT fk_users_orders') `

postgresql

sqlalchemy

alembic

migrations

Add unique constraints safely in SQLAlchemy

When adding unique constraints that could affect large tables, create the unique index concurrently first to avoid blocking reads and writes during the migration. Bad: `python def upgrade(): # Directly creating a unique constraint can block reads and writes op.create_unique_constraint('users_email_unique', 'users', ['email']) ` Good: `python Migration 1: Create unique index concurrently def upgrade(): # Create the unique index concurrently (non-blocking) op.create_index( 'users_email_unique_idx', 'users', ['email'], unique=True, postgresql_concurrently=True ) ` `python Migration 2: Add constraint using existing index def upgrade(): # Add the unique constraint using the existing index op.create_unique_constraint( 'users_email_unique', 'users', ['email'], postgresql_using_index='users_email_unique_idx' ) `

postgresql

sqlalchemy

alembic

migrations

Verify query patterns are covered by an index in SQLAlchemy

Ensure that SQLAlchemy query patterns are covered by appropriate database indexes. Bad: `python queries.py def get_user_by_email(session: Session, email: str): # Will perform full table scan - no index on email return session.scalar(select(User).where(User.email == email)) models.py class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(String(255)) # No index status: Mapped[str] = mapped_column(String(50)) created_at: Mapped[datetime] = mapped_column(DateTime) ` Good: `python queries.py def get_user_by_email(session: Session, email: str): # Is covered by an index return session.scalar(select(User).where(User.email == email)) models.py class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(String(255), index=True) status: Mapped[str] = mapped_column(String(50)) created_at: Mapped[datetime] = mapped_column(DateTime) `

postgresql

sqlalchemy

alembic

migrations

Prefer tailwind design tokens

Use Tailwind's predefined design tokens instead of arbitrary values. Do not use custom pixel values, color codes, or arbitrary numbers in your Tailwind CSS classes. 1. Use Tailwind's spacing scale instead of arbitrary pixel values 2. Use Tailwind's color palette instead of custom color codes 3. Use Tailwind's z-index scale instead of arbitrary z-index values 4. Use Tailwind's percentage-based positioning values instead of arbitrary percentages Bad: `html <div class="mt-[37px] text-[#3366FF] z-[9999] top-[37%] w-[142px]"> Custom content </div> ` Good: `html <div class="mt-10 text-blue-600 z-50 top-1/3 w-36">Custom content</div> `

nextjs

tailwind

Always return empty arrays in Typescript

When defining methods that return collections like arrays, always return an empty array instead of undefined when no items exist. Bad: `typescript function getUserNames(): string[] | undefined { if (users.length === 0) { return undefined } return users.map((user) => user.name) } ` Good: `typescript function getUserNames(): string[] { if (users.length === 0) { return [] } return users.map((user) => user.name) } `

typescript

react

Annotate skipped tests in Typescript

When skipping tests, always add a comment explaining why the test is being skipped. Bad: `typescript describe.skip("enqueueExecution", () => { // test code }) ` Good: `typescript // Test was skipped because it was flaky describe.skip("enqueueExecution", () => { // test code }) `

typescript

Avoid console.log in Typescript tests

Avoid using console.log statements in test files. Bad: `typescript describe("Example test", () => { it("should test something", () => { const result = someFunction() console.log(result) // Debugging statement left in the code expect(result).toBe(expectedValue) }) }) ` Good: `typescript describe("Example test", () => { it("should test something", () => { const result = someFunction() expect(result).toBe(expectedValue) }) }) `

typescript

Avoid duplicate words in Typescript

Check all text elements (comments, docstrings, and string literals) for duplicate adjacent words for typos or duplicates. Bad: `typescript // This function validates the the input parameters function validateInput() { ... } ` Good: `typescript // This function validates the input parameters function validateInput() { ... } `

typescript

react

Self documenting code in Typescript

Avoid unnecessary explanatory comments for code that is self-documenting. Comments should only be used when they add context that the code itself cannot convey. Bad: `typescript // Use the test-specific directory path testDir = join(BASE_DIR, testCase.identifier) ` Good: `typescript testDir = join(BASE_DIR, testCase.identifier) `

typescript

Self documenting string operations in Typescript

Replace magic numbers with self-documenting expressions when dealing with string operations. Bad: `typescript // Magic number - unclear what it represents const position = url.indexOf("/", 12) ` Good: `typescript // Self documenting expression const prefix = "rsc://React/" const position = url.indexOf("/", prefix.length) `

typescript

Check error types in Typescript

Always check the error type in catch blocks and handle specific error types explicitly. Bad: `typescript try { // Some operation } catch (error) { // Converting all errors to a specific type without checking throw new CredentialNotFoundError(id, type) } ` Good: `typescript try { // Some operation } catch (error) { // Check specific error type first if (error instanceof EntityNotFoundError) { throw new CredentialNotFoundError(id, type) } // Pass through other errors throw error } `

typescript

Consistent error classes in Typescript

Use consistent naming conventions for error classes. Bad: `typescript abstract class PublicAPiError extends Error { // Inconsistent casing in "APi" - should be either "Api" or "API" } class UnauthorizedHTtpError extends Error { // Inconsistent casing in "HTtp" - should be either "Http" or "HTTP" } ` Good: `typescript abstract class PublicApiError extends Error { // Consistent Pascal casing with "Api" } class UnauthorizedHttpError extends Error { // Consistent Pascal casing with "Http" } // Or alternatively: abstract class PublicAPIError extends Error { // Consistent uppercase for the acronym "API" } class UnauthorizedHTTPError extends Error { // Consistent uppercase for the acronym "HTTP" } `

typescript

Dev dependencies in typescript

Place CLI tool dependencies in the devDependencies section of package.json instead of dependencies when they are only used for local development, scripts, or tooling. Bad: `json { "dependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/postcss": "^4.1.6", "@types/node": "^20" } } ` Good: `json { "devDependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/postcss": "^4.1.6", "@types/node": "^20" } } `

typescript

react

nextjs

Typescript DRY

Avoid duplicating code in TypeScript. Extract repeated logic into reusable functions, types, or constants. You may have to search the codebase to see if the method or type is already defined. Bad: `typescript // Duplicated type definitions interface User { id: string name: string } interface UserProfile { id: string name: string } // Magic numbers repeated const pageSize = 10 const itemsPerPage = 10 ` Good: `typescript // Reusable type and constant type User = { id: string name: string } const PAGE_SIZE = 10 `

typescript

nextjs

react

Avoid duplicate assignment in Typescript

Avoid assigning values to the same variable multiple times in succession without using the variable in between. Bad: `typescript let count = 0 count = 1 // Duplicate assignment without using the initial value count = 2 // Another duplicate assignment ` Good: `typescript let count = 2 // Direct assignment to final value `

typescript

No unused code in typescript

Do not leave commented-out code blocks. Delete unused code instead of commenting it out. Bad: `typescript function calculateTotal(items: Item[]): number { let total = 0 // Old implementation // for (let i = 0; i < items.length; i++) { // const item = items[i]; // total += item.price * item.quantity; // if (item.discounted) { // total -= item.discountAmount; // } // } // New implementation for (const item of items) { total += item.price item.quantity (item.discounted ? 0.9 : 1) } return total } ` Good: `typescript function calculateTotal(items: Item[]): number { let total = 0 for (const item of items) { total += item.price item.quantity (item.discounted ? 0.9 : 1) } return total } `

typescript

Promise all async loops in Typescript

Use Promise.all when processing multiple async operations in loops. Bad: `typescript async function processItems(items: string[]) { const results = [] for (const item of items) { // Sequential execution - slower const result = await fetchData(item) results.push(result) } return results } ` Good: `typescript async function processItems(items: string[]) { // Parallel execution - faster const results = await Promise.all( items.map(async (item) => { return await fetchData(item) }) ) return results } `

typescript

Query standards for Tanstack Query

When using TanStack Query (React Query), always configure cache and refetching behavior explicitly: 1. Set appropriate staleTime based on how frequently the data changes 2. Configure all refetching flags explicitly to prevent unnecessary network requests Bad: `tsx const { data } = useQuery({ queryKey: ["resource", id], queryFn: () => fetchResource(id), refetchOnMount: false, // Missing staleTime and other refetching settings }) ` Good: `tsx const { data } = useQuery({ queryKey: ["resource", id], queryFn: () => fetchResource(id), refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: 5 60 1000, // 5 minutes }) `

typescript

react

nextjs

Use union types in Typescript

Use union types with specific interfaces for mutually exclusive properties instead of a single interface with multiple optional properties. Bad: `typescript interface ConfigOptions { fileConfig?: { path: string encoding?: string } dbConfig?: { connectionString: string poolSize?: number } properties?: Record<string, any> } ` Good: `typescript interface FileConfigOptions { fileConfig: { path: string encoding?: string } properties?: Record<string, any> } interface DbConfigOptions { dbConfig: { connectionString: string poolSize?: number } properties?: Record<string, any> } type ConfigOptions = FileConfigOptions | DbConfigOptions `

typescript

Avoid unnecessary else blocks in Typescript

Avoid unnecessary else blocks when the if block ends with a return statement, break, continue, or similar control flow statements. Bad: `typescript function processValue(value: number): string { if (value > 10) { return "high" } else { return "low" } } ` `typescript function checkItems(items: string[]): void { for (const item of items) { if (item.length > 5) { console.log("Long item:", item) continue } else { console.log("Short item:", item) } } } ` Good: `typescript function processValue(value: number): string { if (value > 10) { return "high" } return "low" } ` `typescript function checkItems(items: string[]): void { for (const item of items) { if (item.length > 5) { console.log("Long item:", item) continue } console.log("Short item:", item) } } `

typescript

Avoid unnecessary try catch in Typescript

When using try-catch blocks in Typescript, keep the try block focused only on the code that can raise the expected exception. Bad: `typescript async function doSomething() { try { // Large block of code with multiple potential error sources await fetchData() await processData() await saveResults() } catch (error) { console.error(Error: ${(error as Error).message}) process.exit(1) } } ` Good: `typescript async function doSomething() { // Let errors propagate with their full stack trace // or handle specific errors at appropriate points await fetchData() await processData() await saveResults() } // If you need top-level error handling: async function main() { try { await doSomething() } catch (error) { console.error("Unexpected error:", error) process.exit(1) } } `

typescript

Prefer with syntax in Typescript

Use the newer with syntax for JSON imports instead of the deprecated assert syntax for Node.js compatibility. Bad: `javascript import data from "./data.json" assert { type: "json" } ` Good: `javascript import data from "./data.json" with { type: "json" } `

typescript

javascript

Prefer Composition API over Options API in Vue components

Favor the Composition API (<script setup> or setup() function) instead of the Options API when writing new Vue components. Bad – Options API component `vue <script> export default { name: "Counter", data() { return { count: 0, } }, methods: { increment() { this.count++ }, }, mounted() { console.log(The initial count is ${this.count}.) }, } </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> ` Good – Composition API component (<script setup>) `vue <script setup lang="ts"> import { ref, onMounted } from "vue" const count = ref(0) function increment() { count.value++ } onMounted(() => { console.log(The initial count is ${count.value}.) }) </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> `

vue

typescript

javascript

Validate redirect URLs

Always validate redirect URLs to prevent open redirect vulnerabilities. When validating external URLs, parse them with the URL constructor and compare origins exactly rather than using string operations. Bad: `javascript // Vulnerable to subdomain attacks (e.g., example.com.attacker.com) const isRedirectSafe = (redirectUrl) => { return ( redirectUrl.startsWith("/") || redirectUrl.startsWith(window.location.origin) ) } ` Good: `javascript const isRedirectSafe = (redirectUrl) => { // Allow local redirects if (redirectUrl.startsWith("/")) { return true } try { // Validate external URLs by checking exact origin match const url = new URL(redirectUrl) return url.origin === window.location.origin } catch { return false } } `

vue

typescript